From bb0212301322d2dd2c68fee9089b37ff8d13bd7d Mon Sep 17 00:00:00 2001 From: Darcy Date: Tue, 25 Aug 2015 20:32:19 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=A5=BD=E5=8F=8B?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E5=AE=8C=E6=88=90=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 10 +- app/src/main/AndroidManifest.xml | 55 +-- .../net/oschina/app/api/ApiHttpClient.java | 4 +- .../oschina/app/api/remote/OSChinaApi.java | 11 + .../app/fragment/TweetPubFragment.java | 49 +-- .../oschina/app/ui/SelectUserActivity.java | 322 ++++++++++++++++++ .../net/oschina/app/util/StringUtils.java | 29 ++ .../net/oschina/app/widget/AlphabetBar.java | 135 ++++++++ .../res/drawable-xhdpi/cb_circle_normal.png | Bin 0 -> 2388 bytes .../res/drawable-xhdpi/cb_circle_selected.png | Bin 0 -> 4091 bytes app/src/main/res/drawable/bg_alphabet_bar.xml | 6 + .../res/drawable/bg_cb_friend_selected.xml | 6 + .../res/drawable/bg_cb_friend_unselect.xml | 6 + .../main/res/layout/activity_select_user.xml | 51 +++ .../res/layout/item_letter_index_title.xml | 10 + .../main/res/layout/list_select_friend.xml | 38 +++ app/src/main/res/values/attrs.xml | 6 +- app/src/main/res/values/colors.xml | 2 + app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 4 + 20 files changed, 693 insertions(+), 52 deletions(-) create mode 100644 app/src/main/java/net/oschina/app/ui/SelectUserActivity.java create mode 100644 app/src/main/java/net/oschina/app/widget/AlphabetBar.java create mode 100644 app/src/main/res/drawable-xhdpi/cb_circle_normal.png create mode 100644 app/src/main/res/drawable-xhdpi/cb_circle_selected.png create mode 100644 app/src/main/res/drawable/bg_alphabet_bar.xml create mode 100644 app/src/main/res/drawable/bg_cb_friend_selected.xml create mode 100644 app/src/main/res/drawable/bg_cb_friend_unselect.xml create mode 100644 app/src/main/res/layout/activity_select_user.xml create mode 100644 app/src/main/res/layout/item_letter_index_title.xml create mode 100644 app/src/main/res/layout/list_select_friend.xml diff --git a/app/build.gradle b/app/build.gradle index 4f5b8271e..c6d07b1c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'com.android.application' +apply plugin: 'android' apply plugin: 'newlens' android { @@ -13,13 +13,15 @@ android { versionName "2.4" } + /* signingConfigs { release { } } + buildTypes { debug { - signingConfig signingConfigs.release + storeFile file("debug.keystore") } release { signingConfig signingConfigs.release @@ -31,6 +33,7 @@ android { lintOptions { abortOnError false } + */ } dependencies { @@ -44,9 +47,11 @@ dependencies { compile 'com.networkbench.newlens.agent.android:nbs.newlens.agent:2.2.5' compile 'com.google.zxing:core:3.2.0' compile 'com.joanzapata.android:android-iconify:1.0.9' + compile 'com.belerweb:pinyin4j:2.5.0' } // 配置签名文件以及相关的账号信息 +/* File propFile = new File('sign.properties') if (propFile.exists()) { def Properties props = new Properties() @@ -64,3 +69,4 @@ if (propFile.exists()) { } else { android.buildTypes.release.signingConfig = null } +*/ \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 72cd19687..6a0cf4050 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="net.oschina.app" > @@ -121,21 +121,24 @@ - + - - + + - + android:screenOrientation="portrait" + android:windowSoftInputMode="stateHidden|adjustResize" /> - - - + android:screenOrientation="portrait" /> - + + @@ -191,12 +195,12 @@ - + - + - + android:screenOrientation="portrait" + android:theme="@style/Theme.Transparent" /> + + diff --git a/app/src/main/java/net/oschina/app/api/ApiHttpClient.java b/app/src/main/java/net/oschina/app/api/ApiHttpClient.java index 59613bf92..105957060 100644 --- a/app/src/main/java/net/oschina/app/api/ApiHttpClient.java +++ b/app/src/main/java/net/oschina/app/api/ApiHttpClient.java @@ -18,8 +18,8 @@ public class ApiHttpClient { // public final static String HOST = "www.oschina.net"; // private static String API_URL = "http://www.oschina.net/%s"; - public final static String HOST = "192.168.1.107"; - private static String API_URL = "http://192.168.1.107/%s"; + public final static String HOST = "www.oschina.net"; + private static String API_URL = "http://www.oschina.net/%s"; public static final String DELETE = "DELETE"; public static final String GET = "GET"; public static final String POST = "POST"; diff --git a/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java b/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java index a67188790..74a406d53 100644 --- a/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java +++ b/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java @@ -1007,4 +1007,15 @@ public class OSChinaApi { ApiHttpClient.post("action/api/openid_reg", params, handler); } + /** + * 获取全部好友 + * @param uid 用户id + * @param handler + */ + public static void getAllFriendList(int uid,AsyncHttpResponseHandler handler) { + RequestParams params = new RequestParams(); + params.put("uid", uid); + params.put("all", 1); + ApiHttpClient.get("action/api/friends_list", params, handler); + } } diff --git a/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java index 27558fa96..5d431e8c7 100644 --- a/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java @@ -36,6 +36,7 @@ import net.oschina.app.emoji.Emojicon; import net.oschina.app.emoji.InputHelper; import net.oschina.app.emoji.OnEmojiClickListener; import net.oschina.app.service.ServerTaskUtils; +import net.oschina.app.ui.SelectUserActivity; import net.oschina.app.util.DialogHelp; import net.oschina.app.util.FileUtil; import net.oschina.app.util.ImageUtils; @@ -595,30 +596,32 @@ public class TweetPubFragment extends BaseFragment implements } private void insertMention() { - TDevice.showSoftKeyboard(mEtInput); + // TDevice.showSoftKeyboard(mEtInput); // 在光标所在处插入“@用户名” - int curTextLength = mEtInput.getText().length(); - if (curTextLength >= MAX_TEXT_LENGTH) - return; - String atme = TEXT_ATME; - int start, end; - if ((MAX_TEXT_LENGTH - curTextLength) >= atme.length()) { - start = mEtInput.getSelectionStart() + 1; - end = start + atme.length() - 2; - } else { - int num = MAX_TEXT_LENGTH - curTextLength; - if (num < atme.length()) { - atme = atme.substring(0, num); - } - start = mEtInput.getSelectionStart() + 1; - end = start + atme.length() - 1; - } - if (start > MAX_TEXT_LENGTH || end > MAX_TEXT_LENGTH) { - start = MAX_TEXT_LENGTH; - end = MAX_TEXT_LENGTH; - } - mEtInput.getText().insert(mEtInput.getSelectionStart(), atme); - mEtInput.setSelection(start, end);// 设置选中文字 +// int curTextLength = mEtInput.getText().length(); +// if (curTextLength >= MAX_TEXT_LENGTH) +// return; +// String atme = TEXT_ATME; +// int start, end; +// if ((MAX_TEXT_LENGTH - curTextLength) >= atme.length()) { +// start = mEtInput.getSelectionStart() + 1; +// end = start + atme.length() - 2; +// } else { +// int num = MAX_TEXT_LENGTH - curTextLength; +// if (num < atme.length()) { +// atme = atme.substring(0, num); +// } +// start = mEtInput.getSelectionStart() + 1; +// end = start + atme.length() - 1; +// } +// if (start > MAX_TEXT_LENGTH || end > MAX_TEXT_LENGTH) { +// start = MAX_TEXT_LENGTH; +// end = MAX_TEXT_LENGTH; +// } +// mEtInput.getText().insert(mEtInput.getSelectionStart(), atme); +// mEtInput.setSelection(start, end);// 设置选中文字 + Intent selectUserIntent = new Intent(getActivity(), SelectUserActivity.class); + startActivity(selectUserIntent); } private void insertTrendSoftware() { diff --git a/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java new file mode 100644 index 000000000..93e1187d9 --- /dev/null +++ b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java @@ -0,0 +1,322 @@ +package net.oschina.app.ui; + +import android.app.Activity; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.support.v7.app.ActionBar; + +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.loopj.android.http.AsyncHttpResponseHandler; + +import net.oschina.app.AppContext; +import net.oschina.app.R; +import net.oschina.app.api.remote.OSChinaApi; +import net.oschina.app.base.BaseActivity; +import net.oschina.app.bean.Friend; +import net.oschina.app.bean.FriendsList; +import net.oschina.app.util.StringUtils; +import net.oschina.app.util.XmlUtils; + +import org.apache.http.Header; +import org.kymjs.kjframe.KJBitmap; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * + * @author Darcy www.darcye.com + * + */ +public class SelectUserActivity extends BaseActivity { + + private static final char OTHER_INDEX_CHAR = Character.MAX_VALUE; + + private static final int MSG_DATA_PROCESS = 0x10000; + private static final int MSG_DATA_PROCESS_SUCCESS = 0x10001; + + private TextView mTvConfirm; + private ListView mLvFriends; + private BaseAdapter mLvAdapter; + + private List mAllMdlFriends; + private List mShowMdlFriends; + private List mSelectedFriends; + private Map mFriendIndexs; + + private HandlerThread mBackgroundThread; + private BackgroundHandler mBackgroundHandler; + + private Handler mUIHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if(msg.what == MSG_DATA_PROCESS_SUCCESS){ + if(mLvAdapter == null){ + mLvAdapter = new FriendListAdapter(); + mLvFriends.setAdapter(mLvAdapter); + }else{ + mLvAdapter.notifyDataSetChanged(); + } + } + } + }; + + private AsyncHttpResponseHandler mFriendsListHandler =new AsyncHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { + FriendsList friendList = XmlUtils.toBean(FriendsList.class, responseBody); + mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(MSG_DATA_PROCESS,friendList)); + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setActionBarTitle("选择@好友"); + setContentView(R.layout.activity_select_user); + requestFriendsList(); + mBackgroundThread = new HandlerThread("Work Thread On SelectUserActivity"); + mBackgroundThread.start(); + mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper()); + } + + @Override + protected boolean hasBackButton() { + return true; + } + + @Override + protected void initActionBar(ActionBar actionBar) { + super.initActionBar(actionBar); + actionBar.setDisplayOptions(actionBar.getDisplayOptions() | ActionBar.DISPLAY_SHOW_CUSTOM); + mTvConfirm = new TextView(actionBar.getThemedContext()); + ActionBar.LayoutParams params = new ActionBar.LayoutParams( ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, + Gravity.RIGHT | Gravity.CENTER_VERTICAL); + mTvConfirm.setLayoutParams(params); + mTvConfirm.setTextColor(getResources().getColor(R.color.white)); + mTvConfirm.setText("确定"); + actionBar.setCustomView(mTvConfirm); + } + + @Override + public void initData() { + + } + + @Override + public void initView() { + mLvFriends = (ListView)findViewById(R.id.search_result_listview); + } + + @Override + public void onClick(View v) { + + } + + private void requestFriendsList(){ + AppContext appContext = (AppContext) getApplication(); + OSChinaApi.getAllFriendList(appContext.getLoginUid(), mFriendsListHandler); + } + + private class ItemModel{ + static final int TYPE_CHARACTER = 0x0; + static final int TYPE_USER_INFO = 0x1; + int type; + Object data; + + } + + private class FriendListAdapter extends BaseAdapter{ + + Activity activity; + + KJBitmap kjBitmap; + + FriendListAdapter(){ + this.activity = SelectUserActivity.this; + kjBitmap = new KJBitmap(); + } + + @Override + public int getCount() { + return mShowMdlFriends == null ? 0 : mShowMdlFriends.size(); + } + + @Override + public Object getItem(int position) { + return mShowMdlFriends.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemViewType(int position) { + return mShowMdlFriends.get(position).type; + } + + @Override + public int getViewTypeCount() { + return 2; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final int itemType = getItemViewType(position); + final ItemModel model = mShowMdlFriends.get(position); + if(itemType == ItemModel.TYPE_CHARACTER){ + return getAlphaTitleView(model,convertView); + }else{ + return getItemView(model,convertView); + } + } + + private View getAlphaTitleView(final ItemModel model,View convertView){ + TextView tvletter; + if(convertView == null){ + tvletter = (TextView) View.inflate(activity, R.layout.item_letter_index_title, null); + }else{ + tvletter = (TextView)convertView; + } + Character letter = (Character)model.data; + if(letter == OTHER_INDEX_CHAR){ + tvletter.setText("#"); + }else{ + tvletter.setText(String.valueOf(letter)); + } + return tvletter; + } + + private View getItemView(final ItemModel model,View convertView){ + ItemViewHolder viewHodler; + if(convertView == null){ + convertView = View.inflate(activity,R.layout.list_select_friend,null); + viewHodler = new ItemViewHolder(); + viewHodler.ivUserAvator = (ImageView)convertView.findViewById(R.id.iv_user_avator); + viewHodler.tvUserName = (TextView)convertView.findViewById(R.id.tv_user_name); + viewHodler.ivSelector = (ImageView)convertView.findViewById(R.id.iv_selector); + convertView.setTag(viewHodler); + }else{ + viewHodler = (ItemViewHolder)convertView.getTag(); + } + + Friend friend = (Friend)model.data; + viewHodler.tvUserName.setText(friend.getName()); + + if(mSelectedFriends.contains(friend)){ + viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_selected); + }else{ + viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect); + } + + kjBitmap.display(viewHodler.ivUserAvator,friend.getPortrait()); + + return convertView; + } + + private class ItemViewHolder{ + ImageView ivUserAvator; + TextView tvUserName; + ImageView ivSelector; + } + } + + public class BackgroundHandler extends Handler { + + public BackgroundHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + if(msg.what == MSG_DATA_PROCESS){ + FriendsList friendList = (FriendsList)msg.obj; + processData(friendList); + mUIHandler.sendEmptyMessage(MSG_DATA_PROCESS_SUCCESS); + } + } + + private void processData(FriendsList friendList){ + if(friendList != null) { + + List allFriends = friendList.getFriendlist(); + if (allFriends == null || allFriends.isEmpty()) { + // no friends + return; + } + + mFriendIndexs = new TreeMap<>(); + Character firstAlpha; + + + for (Friend f : allFriends) { + firstAlpha = StringUtils.getFirstLetter(f.getName().charAt(0)); + if ('A' <= firstAlpha && firstAlpha <= 'Z') { + addUserIndex(firstAlpha, f); + } else { + addUserIndex(OTHER_INDEX_CHAR, f); + } + } + + mShowMdlFriends = new ArrayList<>(); + + ItemModel model; + FriendIndex friendIndex; + int itemPos = 0; + for (java.util.Map.Entry entry : mFriendIndexs.entrySet()) { + model = new ItemModel(); + model.type = ItemModel.TYPE_CHARACTER; + model.data = entry.getKey(); + mShowMdlFriends.add(model); + friendIndex = entry.getValue(); + friendIndex.position = itemPos; + ++itemPos; + for (Friend friend : friendIndex.friends) { + model = new ItemModel(); + model.type = ItemModel.TYPE_USER_INFO; + model.data = friend; + mShowMdlFriends.add(model); + ++itemPos; + } + } + + mAllMdlFriends = new ArrayList<>(); + mAllMdlFriends.addAll(mShowMdlFriends); + } + } + + private void addUserIndex(char letter, Friend friend){ + FriendIndex friendIndex = mFriendIndexs.get(letter); + if(friendIndex == null){ + friendIndex = new FriendIndex(); + mFriendIndexs.put(letter, friendIndex); + } + friendIndex.friends.add(friend); + } + } + + private class FriendIndex{ + int position; + List friends = new ArrayList<>(); + } +} diff --git a/app/src/main/java/net/oschina/app/util/StringUtils.java b/app/src/main/java/net/oschina/app/util/StringUtils.java index 7a56fcbc4..b190757d1 100644 --- a/app/src/main/java/net/oschina/app/util/StringUtils.java +++ b/app/src/main/java/net/oschina/app/util/StringUtils.java @@ -1,5 +1,9 @@ package net.oschina.app.util; +import net.sourceforge.pinyin4j.PinyinHelper; +import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; +import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -476,4 +480,29 @@ public class StringUtils { return df.format(new Date()); } + private static final HanyuPinyinOutputFormat PINGYIN_FORMAT = new HanyuPinyinOutputFormat(); + /** + * 获取一个汉字的拼音首字母。 (大写) + * + * @return 如果是汉字则返回首字母,否则直接返回 + */ + public static Character getFirstLetter(char ch) { + + if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z')) { + return Character.toUpperCase(ch); + } + + try { + String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(ch, PINGYIN_FORMAT); + if(pinyins == null || pinyins.length == 0){ + return ch; + }else{ + return Character.toUpperCase(pinyins[0].charAt(0)); + } + } catch (BadHanyuPinyinOutputFormatCombination e) { + e.printStackTrace(); + } + + return ch; + } } diff --git a/app/src/main/java/net/oschina/app/widget/AlphabetBar.java b/app/src/main/java/net/oschina/app/widget/AlphabetBar.java new file mode 100644 index 000000000..e0e4cbe43 --- /dev/null +++ b/app/src/main/java/net/oschina/app/widget/AlphabetBar.java @@ -0,0 +1,135 @@ +package net.oschina.app.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint.FontMetricsInt; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import net.oschina.app.R; + +/** + * + * @author Darcy www.darcye.com + * + */ +public class AlphabetBar extends View { + + public static final char OTHER_CHARACTOR = '#'; + + private static final char[] ALPHABETS = new char[27]; + + private TextPaint mPaint; + + private int mUnitHeight; + private int letterYOffset; + private boolean mHasInitParams = false; + + private OnAlphabetTouchListener mOnAlphabetTouchListener; + + private OnSizeChangedListener mOnSizeChangedListener; + + static{ + for(char ch = 'A'; ch <= 'Z' ; ++ch){ + ALPHABETS[ch - 'A'] = ch; + } + ALPHABETS[26] = OTHER_CHARACTOR; + } + + public AlphabetBar(Context context){ + this(context,null); + } + + public AlphabetBar(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AlphabetBar); + final int textSize = a.getDimensionPixelSize(R.styleable.AlphabetBar_alphaTextSize, 12); + final int textColor = a.getColor(R.styleable.AlphabetBar_alphaTextColor, 0xFF000000); + mPaint = new TextPaint(); + mPaint.setAntiAlias(true); + mPaint.setTextSize(textSize); + mPaint.setColor(textColor); + a.recycle(); + setClickable(true); + } + + public void setOnAlphabetTouchListener(OnAlphabetTouchListener l) { + this.mOnAlphabetTouchListener = l; + } + + public void setOnSizeChangedListener( + OnSizeChangedListener l) { + this.mOnSizeChangedListener = l; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + final int width = getWidth(); + if(!mHasInitParams){ + final int paddingTop = getPaddingTop(); + final int height = getHeight() - paddingTop - getPaddingBottom(); + this.mUnitHeight = height / ALPHABETS.length; + final FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); + this.letterYOffset = (int) ((mUnitHeight - (fontMetrics.bottom - fontMetrics.top)) * 0.5 - fontMetrics.top + paddingTop); + mHasInitParams = false; + } + + int letterXOffset; + String letter; + for(int i = 0 ; i < ALPHABETS.length ; ++i){ + letter = String.valueOf(ALPHABETS[i]); + letterXOffset = (int) ((width - mPaint.measureText(letter)) * 0.5); + canvas.drawText(letter, letterXOffset, letterYOffset + mUnitHeight * i, mPaint); + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + super.dispatchTouchEvent(event); + return true; + } + + private int originIndex = -1; + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + final int action = event.getAction(); + if(action == MotionEvent.ACTION_MOVE){ + final float moveY = event.getY(); + final int newIndex = (int) (moveY / mUnitHeight) ; + if(originIndex != newIndex && 0 <= newIndex && newIndex < ALPHABETS.length){ + originIndex = newIndex; + if(mOnAlphabetTouchListener != null){ + mOnAlphabetTouchListener.onTouchMove(ALPHABETS[newIndex]); + } + } + }else if(action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL){ + originIndex = -1; + if(mOnAlphabetTouchListener != null) + mOnAlphabetTouchListener.onTouchCancel(); + } + return true; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if(mOnSizeChangedListener != null) + mOnSizeChangedListener.onSizeChanged(w, h, oldw, oldh); + } + + public interface OnAlphabetTouchListener{ + void onTouchMove(char al); + + void onTouchCancel(); + } + + public interface OnSizeChangedListener{ + void onSizeChanged(int w, int h, int oldw, int oldh); + } +} diff --git a/app/src/main/res/drawable-xhdpi/cb_circle_normal.png b/app/src/main/res/drawable-xhdpi/cb_circle_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..cf886cc9e121187e14d0d1423d9bc89b793b840f GIT binary patch literal 2388 zcmbVOX;f2Z8V(8wibb?4jw~U7RUq39Nk|~1kVT_{2nisrS#BUeazheGB+&xmf`Uam zIz$xET98;3i+~FPEfq^u0)3Lz|unS#L+Nn{Gy4++3~EG_^G;Ltbl4Rwt|0vCm!%!GugQc$MiFli|G z1|yP)sQwf@iw!UdWOe|B<&Vb)gy7f=91({n`xD8bp@b=pPhpt=$sZt52n2sz2p-QO zh5$Gqltm^HZ~%o!Acjm~IWnb+FB5`Ob|tXg4_M%Du~dcvEbI_=vPu4@X{L_gPMj1!jsU#*I7FZfo*V@{ zB469rS`Y{u9fujh)!g~Ba9aW|)%kjHx5#P0`}bKL(Ks>Gc}3urMDWGgF{JFhv-Wz& za+&k&XAq!|QK<<{4{Vk4ud$gK1B@ zY3i3pH#_Pcs<*$qr!6wl`d%uE{&?>D*L^fWP$Gnnv)tt!7 z>U-c=o0k|vJDylL5U49kJeJ5QnQ*5LUpBj%+U#GY?l-5IA}93TnZ}yuIj>TIj6&}E z&SjLq@;jw*r_D3R4%Drv3N?N2Lmck!i0f>stY&`J_eijq7wF(O*dNVv#k!Hcw~*Is z^3K$jF1AT)Eo*PI#l&1am)_9f$|V{G!MlDJhAnYFf_dE{v&A_q zUVAJ#sjo_H%g$NTpR}n#lN|iOW`l9x$c0~CT)0-T{Z;GA;w>@dBi64DAI(@rv20Fi zY7~#OtUW*cLXv;|c5B~nIS6{$5h1lq8{opcRb45)(vtkyHlw{W!>CZcao&CG)Sc5W z+PW0ML+h-BS#KjtcEowM)ev1uk4k$TFrF56U0cItifz-iK>}lebCJ33wt%D*oN7$Sq`D4yHpKlO5glo zmgiCvuUk2hs*L)>@>$IDTSlL zbNZps83QNw4W?{2dOlF!63%W~i7*~~*l<_9H5)vUu)Ntzbo3AoVpNcx8U5NF5S#fv zbt7{+fw1ZFGv)n5uw`?(4!VAcrohgo)=qQ_v8>?CMyBiLd2YI~32HHQc z(%ztD`;mLB5HIz6eH=55Ko1?E`>dymX55Wf-}euBuT z2j=IwO*4{u!VzC#8duFPh$;Td$#21JO#Gr;R|Gqua>t=qNpYW(C1_EL8$wuIs2Kph zAZo2^JN~J@v}c9`zCX&(^W?fd&eMUPD$9Neu)gP8Ud4MEOCPYZFnUw&Gn$-Io>Z0Q z_FOkRH%3op&W5c?bH5R9J&|#-iy)c|fqpU2sY1zRqhNPVnW8oA}5X(M^c7?{Zfw zW0yz-Dj_Q{Ve;cZilYF z+r@QnUEcMsP3F*Q-`t%9@R7E_qS7rZzZdU7KXCWdp_YN@ASUCyW&fUp%V#w8s}e&H hLPUjItmdXDd4lA5_HgrqYe*msh@%aD% literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/cb_circle_selected.png b/app/src/main/res/drawable-xhdpi/cb_circle_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..d8d1732b0b33fbed6cf46dce6935225d099a29eb GIT binary patch literal 4091 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/bg_alphabet_bar.xml b/app/src/main/res/drawable/bg_alphabet_bar.xml new file mode 100644 index 000000000..802b26641 --- /dev/null +++ b/app/src/main/res/drawable/bg_alphabet_bar.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_cb_friend_selected.xml b/app/src/main/res/drawable/bg_cb_friend_selected.xml new file mode 100644 index 000000000..06aeabf15 --- /dev/null +++ b/app/src/main/res/drawable/bg_cb_friend_selected.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_cb_friend_unselect.xml b/app/src/main/res/drawable/bg_cb_friend_unselect.xml new file mode 100644 index 000000000..c4b427a00 --- /dev/null +++ b/app/src/main/res/drawable/bg_cb_friend_unselect.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_select_user.xml b/app/src/main/res/layout/activity_select_user.xml new file mode 100644 index 000000000..94f8d7a63 --- /dev/null +++ b/app/src/main/res/layout/activity_select_user.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_letter_index_title.xml b/app/src/main/res/layout/item_letter_index_title.xml new file mode 100644 index 000000000..9e5e0ad9a --- /dev/null +++ b/app/src/main/res/layout/item_letter_index_title.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_select_friend.xml b/app/src/main/res/layout/list_select_friend.xml new file mode 100644 index 000000000..a107f47cc --- /dev/null +++ b/app/src/main/res/layout/list_select_friend.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 01c26a29d..cede74952 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -10,5 +10,9 @@ - + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 4df8e5e3f..1599f0125 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -90,4 +90,6 @@ #464646 #6baf77 + + #338899a6 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 58d7807c6..6514a70f8 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -151,4 +151,5 @@ 0.14 0.11 + 12dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eea0b4c9d..46b26bd94 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -303,4 +303,8 @@ 选择团队 我的任务 + SelectUserActivity + + Hello world! + Settings -- Gitee From d519ae61210aac66dd89b582a69baaeaa595ee8a Mon Sep 17 00:00:00 2001 From: Darcy Date: Wed, 26 Aug 2015 20:48:03 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=A5=BD=E5=8F=8B=E5=88=97=E8=A1=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/fragment/TweetPubFragment.java | 14 +- .../oschina/app/ui/SelectUserActivity.java | 374 +++++++++++++++++- .../main/res/layout/activity_select_user.xml | 42 +- .../res/layout/item_letter_index_title.xml | 2 +- .../main/res/layout/list_select_friend.xml | 10 +- app/src/main/res/values/dimens.xml | 1 + gradle.properties | 3 + 7 files changed, 411 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java b/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java index 5d431e8c7..8cc9b8381 100644 --- a/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java +++ b/app/src/main/java/net/oschina/app/fragment/TweetPubFragment.java @@ -65,6 +65,8 @@ import butterknife.InjectView; public class TweetPubFragment extends BaseFragment implements OnEmojiClickListener { + private static final int REQUEST_CODE_AT_USER = 0x1225; + public static final int ACTION_TYPE_ALBUM = 0; public static final int ACTION_TYPE_PHOTO = 1; public static final int ACTION_TYPE_RECORD = 2; // 录音 @@ -413,6 +415,14 @@ public class TweetPubFragment extends BaseFragment implements final Intent imageReturnIntent) { if (resultCode != Activity.RESULT_OK) return; + + // at user return + if(requestCode == REQUEST_CODE_AT_USER){ + String atUsersText = imageReturnIntent.getStringExtra(SelectUserActivity.RESULT_AT_USERS); + if(!TextUtils.isEmpty(atUsersText)) + mEtInput.getText().replace(mEtInput.getSelectionStart(),mEtInput.getSelectionEnd(),atUsersText); + } + new Thread() { private String selectedImagePath; @@ -605,7 +615,7 @@ public class TweetPubFragment extends BaseFragment implements // int start, end; // if ((MAX_TEXT_LENGTH - curTextLength) >= atme.length()) { // start = mEtInput.getSelectionStart() + 1; -// end = start + atme.length() - 2; +// end = start + atme.length() - 2 // } else { // int num = MAX_TEXT_LENGTH - curTextLength; // if (num < atme.length()) { @@ -621,7 +631,7 @@ public class TweetPubFragment extends BaseFragment implements // mEtInput.getText().insert(mEtInput.getSelectionStart(), atme); // mEtInput.setSelection(start, end);// 设置选中文字 Intent selectUserIntent = new Intent(getActivity(), SelectUserActivity.class); - startActivity(selectUserIntent); + startActivityForResult(selectUserIntent,REQUEST_CODE_AT_USER); } private void insertTrendSoftware() { diff --git a/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java index 93e1187d9..ac90a8db2 100644 --- a/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java +++ b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java @@ -1,6 +1,10 @@ package net.oschina.app.ui; import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -8,14 +12,26 @@ import android.os.Message; import android.support.v7.app.ActionBar; import android.os.Bundle; +import android.text.Editable; +import android.text.Html; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.style.ImageSpan; +import android.util.SparseArray; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; import android.widget.AbsListView; +import android.widget.AdapterView; import android.widget.BaseAdapter; +import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; import com.loopj.android.http.AsyncHttpResponseHandler; @@ -25,17 +41,25 @@ import net.oschina.app.api.remote.OSChinaApi; import net.oschina.app.base.BaseActivity; import net.oschina.app.bean.Friend; import net.oschina.app.bean.FriendsList; +import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.StringUtils; import net.oschina.app.util.XmlUtils; +import net.oschina.app.widget.AlphabetBar; import org.apache.http.Header; import org.kymjs.kjframe.KJBitmap; +import java.io.ByteArrayInputStream; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; + /** * * @author Darcy www.darcye.com @@ -43,33 +67,59 @@ import java.util.TreeMap; */ public class SelectUserActivity extends BaseActivity { + private static final String HIGHLIGHT_COLOR = "#cc0000"; + private static final String HIGHLIGHT_REPLACEMENT = String.format("$1",HIGHLIGHT_COLOR); private static final char OTHER_INDEX_CHAR = Character.MAX_VALUE; private static final int MSG_DATA_PROCESS = 0x10000; private static final int MSG_DATA_PROCESS_SUCCESS = 0x10001; + private static final int MSG_SEARCH_FRIENDS = 0x20000; + private static final int MSG_SEARCH_FRIENDS_SUCCESS = 0x20001; + + private static final int MSG_SELECT_USERS_PROCESS = 0x30000; + private static final int MSG_SELECT_USERS_PROCESS_SUCCESS = 0x30001; + + private static final int MAX_SELECT_USER_COUNT = 10; + + public static final String RESULT_AT_USERS = "at_users"; + + private EmptyLayout mEmptyLayout; private TextView mTvConfirm; + private EditText mEtSearch; + private TextView mTvSelectedUsers; + private AlphabetBar mAlphaBar; + private TextView mTvAlphaTip; private ListView mLvFriends; - private BaseAdapter mLvAdapter; + private FriendListAdapter mLvAdapter; private List mAllMdlFriends; private List mShowMdlFriends; - private List mSelectedFriends; + private Set mSelectedFriends = new LinkedHashSet<>(); private Map mFriendIndexs; private HandlerThread mBackgroundThread; private BackgroundHandler mBackgroundHandler; + private KJBitmap mkjBitmap; + private String mSearchText; + private boolean mIsShowAll; + private boolean mIsMultiSelect; + private int mSelectUserPicSize; + private Handler mUIHandler = new Handler() { @Override public void handleMessage(Message msg) { if(msg.what == MSG_DATA_PROCESS_SUCCESS){ - if(mLvAdapter == null){ - mLvAdapter = new FriendListAdapter(); - mLvFriends.setAdapter(mLvAdapter); - }else{ - mLvAdapter.notifyDataSetChanged(); - } + mLvAdapter = new FriendListAdapter(); + mLvFriends.setAdapter(mLvAdapter); + initAlphaBar(); + mEmptyLayout.setVisibility(View.GONE); + }else if(msg.what == MSG_SEARCH_FRIENDS_SUCCESS){ + mLvAdapter.notifyDataSetChanged(); + }else if(msg.what == MSG_SELECT_USERS_PROCESS_SUCCESS){ + SpannableStringBuilder usersPicSpannable = (SpannableStringBuilder)msg.obj; + mTvSelectedUsers.setText(usersPicSpannable); } } }; @@ -78,12 +128,53 @@ public class SelectUserActivity extends BaseActivity { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { FriendsList friendList = XmlUtils.toBean(FriendsList.class, responseBody); - mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(MSG_DATA_PROCESS,friendList)); + if(friendList == null || friendList.getFriendlist().isEmpty()){ + mEmptyLayout.setErrorType(EmptyLayout.NODATA); + }else{ + mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(MSG_DATA_PROCESS,friendList)); + } } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + mEmptyLayout.setErrorType(EmptyLayout.NETWORK_ERROR); + } + }; + + private TextWatcher mSearchTextWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + final String searchText = s.toString(); + mSearchText = searchText; + mBackgroundHandler.removeMessages(MSG_SEARCH_FRIENDS); + mBackgroundHandler.sendMessageDelayed(mBackgroundHandler.obtainMessage(MSG_SEARCH_FRIENDS, searchText),200); + } + }; + private final Comparator friendSearchComparator = new Comparator() { + @Override + public int compare(ItemModel lhs, ItemModel rhs) { + Friend lhsUser = (Friend) lhs.data; + Friend rhsUser = (Friend) rhs.data; + final String lhsUserName = lhsUser.getName(); + final String rhsUserName = rhsUser.getName(); + final String lowerCaseKeyword = mSearchText.toLowerCase(); + int result = lhsUserName.toLowerCase().indexOf(lowerCaseKeyword) - rhsUserName.toLowerCase().indexOf(lowerCaseKeyword); + if(result == 0){ + return lhsUserName.compareTo(rhsUserName); + }else{ + return result; + } } }; @@ -91,11 +182,12 @@ public class SelectUserActivity extends BaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setActionBarTitle("选择@好友"); - setContentView(R.layout.activity_select_user); requestFriendsList(); mBackgroundThread = new HandlerThread("Work Thread On SelectUserActivity"); mBackgroundThread.start(); mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper()); + mkjBitmap = new KJBitmap(); + mSelectUserPicSize = getResources().getDimensionPixelSize(R.dimen.select_user_pic_size); } @Override @@ -109,13 +201,19 @@ public class SelectUserActivity extends BaseActivity { actionBar.setDisplayOptions(actionBar.getDisplayOptions() | ActionBar.DISPLAY_SHOW_CUSTOM); mTvConfirm = new TextView(actionBar.getThemedContext()); ActionBar.LayoutParams params = new ActionBar.LayoutParams( ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, - Gravity.RIGHT | Gravity.CENTER_VERTICAL); + Gravity.END | Gravity.CENTER_VERTICAL); mTvConfirm.setLayoutParams(params); mTvConfirm.setTextColor(getResources().getColor(R.color.white)); - mTvConfirm.setText("确定"); + mTvConfirm.setOnClickListener(this); + mTvConfirm.setVisibility(View.GONE); actionBar.setCustomView(mTvConfirm); } + @Override + protected int getLayoutId() { + return R.layout.activity_select_user; + } + @Override public void initData() { @@ -123,12 +221,144 @@ public class SelectUserActivity extends BaseActivity { @Override public void initView() { + mEmptyLayout = (EmptyLayout)findViewById(R.id.error_layout); mLvFriends = (ListView)findViewById(R.id.search_result_listview); + mEtSearch = (EditText)findViewById(R.id.search_edit_text); + mEtSearch.addTextChangedListener(mSearchTextWatcher); + mAlphaBar = (AlphabetBar)findViewById(R.id.alphabet_bar); + mTvAlphaTip = (TextView)findViewById(R.id.alphabet_tip); + mTvSelectedUsers = (TextView)findViewById(R.id.selected_users_tv); + mLvFriends.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){ + hideInputMethod(); + } + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + } + }); + mLvFriends.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + ItemModel m = mShowMdlFriends.get(position); + if (m.type == ItemModel.TYPE_USER_INFO && !mSelectedFriends.contains(m.data) && !checkIfExceedMaxSelectCount()) { + Friend f = (Friend) m.data; + mSelectedFriends.add(f); + if (!mIsMultiSelect) { + mIsMultiSelect = true; + mLvAdapter.notifyDataSetChanged(); + mTvConfirm.setVisibility(View.VISIBLE); + refleshSelectUsers(); + } else { + mLvAdapter.refleshItemStatus(position, f); + refleshSelectUsers(); + } + } + return true; + } + }); + mLvFriends.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + ItemModel m = mShowMdlFriends.get(position); + if (m.type == ItemModel.TYPE_USER_INFO) { + Friend f = (Friend) m.data; + if (mIsMultiSelect) { + if (mSelectedFriends.contains(f)) { + mSelectedFriends.remove(f); + } else if(!checkIfExceedMaxSelectCount()){ + mSelectedFriends.add(f); + } + mLvAdapter.refleshItemStatus(position, f); + refleshSelectUsers(); + } else { + Intent resultIntent = new Intent(); + resultIntent.putExtra(RESULT_AT_USERS, String.format("@%s ", f.getName())); + setResult(RESULT_OK, resultIntent); + finish(); + } + } + } + }); + + mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING); + requestFriendsList(); + } + }); + } + + private void refleshSelectUsers(){ + int selectFriendsSize = mSelectedFriends.size(); + mTvConfirm.setText(String.format("确定(%s/%s)", selectFriendsSize, mAllMdlFriends.size())); + if(selectFriendsSize == 0){ + mTvSelectedUsers.setVisibility(View.GONE); + }else { + mTvSelectedUsers.setVisibility(View.VISIBLE); + mBackgroundHandler.sendEmptyMessage(MSG_SELECT_USERS_PROCESS); + } + } + + private boolean checkIfExceedMaxSelectCount(){ + boolean isExceed = mSelectedFriends.size() >= MAX_SELECT_USER_COUNT; + if(isExceed){ + Toast.makeText(this,String.format("选择用户数不能超过%s个",MAX_SELECT_USER_COUNT),Toast.LENGTH_SHORT).show(); + } + return isExceed; + } + + private Bitmap getCacheUserBitmap(String url){ + if(TextUtils.isEmpty(url)) + return BitmapFactory.decodeResource(getResources(), R.drawable.widget_dface); + + Bitmap bm = mkjBitmap.getMemoryCache(url); + if(bm == null){ + bm = BitmapFactory.decodeStream(new ByteArrayInputStream(mkjBitmap.getCache(url))); + } + return bm; } @Override public void onClick(View v) { + StringBuilder atUsers = new StringBuilder(); + for(Friend f : mSelectedFriends){ + atUsers.append(String.format("@%s ", f.getName())); + } + Intent resultIntent = new Intent(); + resultIntent.putExtra(RESULT_AT_USERS,atUsers.toString()); + setResult(RESULT_OK, resultIntent); + finish(); + } + + private void initAlphaBar(){ + mAlphaBar.setVisibility(View.VISIBLE); + mAlphaBar.setOnAlphabetTouchListener(new AlphabetBar.OnAlphabetTouchListener() { + @Override + public void onTouchMove(char al) { + FriendIndex friendIndex; + if (al == AlphabetBar.OTHER_CHARACTOR) { + friendIndex = mFriendIndexs.get(OTHER_INDEX_CHAR); + } else { + friendIndex = mFriendIndexs.get(al); + } + mTvAlphaTip.setVisibility(View.VISIBLE); + mTvAlphaTip.setText(String.valueOf(al)); + if (friendIndex != null) { + mLvFriends.setSelection(friendIndex.position); + } + } + @Override + public void onTouchCancel() { + mTvAlphaTip.setVisibility(View.GONE); + } + }); } private void requestFriendsList(){ @@ -136,6 +366,20 @@ public class SelectUserActivity extends BaseActivity { OSChinaApi.getAllFriendList(appContext.getLoginUid(), mFriendsListHandler); } + private void clearHighLightTag(){ + for(ItemModel model : mShowMdlFriends){ + if(model.data instanceof Friend){ + Friend user = (Friend) model.data; + user.setName(user.getName().replaceAll("<.+?>", "")); + } + } + } + + private void hideInputMethod() { + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mEtSearch.getWindowToken(), 0); + } + private class ItemModel{ static final int TYPE_CHARACTER = 0x0; static final int TYPE_USER_INFO = 0x1; @@ -148,11 +392,11 @@ public class SelectUserActivity extends BaseActivity { Activity activity; - KJBitmap kjBitmap; + SparseArray selectorHolder; FriendListAdapter(){ this.activity = SelectUserActivity.this; - kjBitmap = new KJBitmap(); + selectorHolder = new SparseArray<>(); } @Override @@ -187,7 +431,7 @@ public class SelectUserActivity extends BaseActivity { if(itemType == ItemModel.TYPE_CHARACTER){ return getAlphaTitleView(model,convertView); }else{ - return getItemView(model,convertView); + return getItemView(position,model,convertView); } } @@ -207,7 +451,7 @@ public class SelectUserActivity extends BaseActivity { return tvletter; } - private View getItemView(final ItemModel model,View convertView){ + private View getItemView(final int position, final ItemModel model,View convertView){ ItemViewHolder viewHodler; if(convertView == null){ convertView = View.inflate(activity,R.layout.list_select_friend,null); @@ -221,19 +465,37 @@ public class SelectUserActivity extends BaseActivity { } Friend friend = (Friend)model.data; - viewHodler.tvUserName.setText(friend.getName()); + viewHodler.tvUserName.setText(Html.fromHtml(friend.getName())); - if(mSelectedFriends.contains(friend)){ - viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_selected); + selectorHolder.put(position,viewHodler.ivSelector); + + if(mIsMultiSelect){ + viewHodler.ivSelector.setVisibility(View.VISIBLE); + if(mSelectedFriends.contains(friend)){ + viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_selected); + }else{ + viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect); + } }else{ - viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect); + viewHodler.ivSelector.setVisibility(View.GONE); } - kjBitmap.display(viewHodler.ivUserAvator,friend.getPortrait()); + mkjBitmap.display(viewHodler.ivUserAvator,friend.getPortrait()); return convertView; } + void refleshItemStatus(int position, Friend friend){ + ImageView ivSelector = selectorHolder.get(position); + if(ivSelector != null){ + if(mSelectedFriends.contains(friend)){ + ivSelector.setImageResource(R.drawable.bg_cb_friend_selected); + }else{ + ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect); + } + } + } + private class ItemViewHolder{ ImageView ivUserAvator; TextView tvUserName; @@ -253,6 +515,25 @@ public class SelectUserActivity extends BaseActivity { FriendsList friendList = (FriendsList)msg.obj; processData(friendList); mUIHandler.sendEmptyMessage(MSG_DATA_PROCESS_SUCCESS); + }else if(msg.what == MSG_SEARCH_FRIENDS){ + String searchText = (String)msg.obj; + if(mShowMdlFriends != null){ + clearHighLightTag(); + mShowMdlFriends.clear(); + } + + if(!TextUtils.isEmpty(searchText)){ + mIsShowAll = false; + searchFriends(searchText); + }else{ + mIsShowAll = true; + mShowMdlFriends.addAll(mAllMdlFriends); + } + + mUIHandler.sendEmptyMessage(MSG_SEARCH_FRIENDS_SUCCESS); + }else if(msg.what == MSG_SELECT_USERS_PROCESS){ + SpannableStringBuilder spannable = processSelectedUsers(); + mUIHandler.sendMessage(mUIHandler.obtainMessage(MSG_SELECT_USERS_PROCESS_SUCCESS, spannable)); } } @@ -313,6 +594,57 @@ public class SelectUserActivity extends BaseActivity { } friendIndex.friends.add(friend); } + + private void searchFriends(String searchText){ + if(mAllMdlFriends == null || mAllMdlFriends.isEmpty()) + return; + + for(ItemModel m : mAllMdlFriends){ + if(m.type == ItemModel.TYPE_USER_INFO && m.data instanceof Friend){ + Friend f = (Friend) m.data; + String name = f.getName(); + if(name.toLowerCase().contains(searchText.toLowerCase())){ + f.setName(name.replaceAll("((?i)" + searchText + ")",HIGHLIGHT_REPLACEMENT)); + mShowMdlFriends.add(m); + } + } + } + + Collections.sort(mShowMdlFriends, friendSearchComparator); + } + + private SpannableStringBuilder processSelectedUsers(){ + int selectFriendsSize = mSelectedFriends.size(); + + String spanText = ""; + int picIndex; + for(picIndex = 0 ; picIndex < selectFriendsSize ; ++picIndex){ + spanText += (picIndex + " "); + } + spanText = spanText.substring(0,spanText.length() - 1); + SpannableStringBuilder spannable = new SpannableStringBuilder(spanText); + + ImageSpan imgSpan; + Bitmap bmUser , newBmUser; + picIndex = 0; + int spanStart; + String indexStr; + + for (Friend f : mSelectedFriends) { + indexStr = String.valueOf(picIndex); + spanStart = spanText.indexOf(indexStr); + bmUser = getCacheUserBitmap(f.getPortrait()); + newBmUser = Bitmap.createScaledBitmap(bmUser, mSelectUserPicSize, mSelectUserPicSize, true); + if (newBmUser == null) { + newBmUser = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.widget_dface), mSelectUserPicSize, mSelectUserPicSize, true); + } + imgSpan = new ImageSpan(SelectUserActivity.this, newBmUser); + spannable.setSpan(imgSpan, spanStart, spanStart + indexStr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + ++picIndex; + } + + return spannable; + } } private class FriendIndex{ diff --git a/app/src/main/res/layout/activity_select_user.xml b/app/src/main/res/layout/activity_select_user.xml index 94f8d7a63..ed96cc6ee 100644 --- a/app/src/main/res/layout/activity_select_user.xml +++ b/app/src/main/res/layout/activity_select_user.xml @@ -6,7 +6,10 @@ + android:textSize="18dp" + android:textColor="@color/black" + android:hint="搜索" + android:textColorHint="@color/gray"/> + + + android:layout_below="@+id/selected_users_tv" + android:cacheColorHint="@android:color/transparent" + android:divider="@null" + android:fadingEdge="none" + android:listSelector="@color/transparent" + android:overScrollMode="never" + android:scrollbars="none" /> + android:text="H" + android:visibility="gone"/> + + diff --git a/app/src/main/res/layout/item_letter_index_title.xml b/app/src/main/res/layout/item_letter_index_title.xml index 9e5e0ad9a..415c96a9f 100644 --- a/app/src/main/res/layout/item_letter_index_title.xml +++ b/app/src/main/res/layout/item_letter_index_title.xml @@ -6,5 +6,5 @@ android:paddingLeft="20dp" android:paddingTop="5dp" android:textColor="#333" - android:textSize="15dp" + android:textSize="12dp" android:background="#CCC"/> \ No newline at end of file diff --git a/app/src/main/res/layout/list_select_friend.xml b/app/src/main/res/layout/list_select_friend.xml index a107f47cc..ae3e6933b 100644 --- a/app/src/main/res/layout/list_select_friend.xml +++ b/app/src/main/res/layout/list_select_friend.xml @@ -1,10 +1,13 @@ + android:paddingLeft="10dp" + android:paddingRight="10dp"> + android:layout_marginLeft="10dp"/> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 6514a70f8..a878a0566 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -152,4 +152,5 @@ 0.11 12dp + 20dp diff --git a/gradle.properties b/gradle.properties index a67972e42..9b73b9663 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,5 +16,8 @@ # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +org.gradle.daemon=true +org.gradle.parallel=true + KEYSTORE_PASSWORD=oschina123 KEY_PASSWORD=oschina123 \ No newline at end of file -- Gitee From 68f850d5e3ba6c991fda3f5677ec173c3ef3f14e Mon Sep 17 00:00:00 2001 From: Darcy Date: Thu, 27 Aug 2015 00:13:31 +0800 Subject: [PATCH 3/5] modify AndroidManifest --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a0cf4050..7fba0ecf5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -242,6 +242,7 @@ android:theme="@style/Theme.Transparent" /> -- Gitee From 25fa0d28e153d31bd2b731d3fc19a8dc926e93b1 Mon Sep 17 00:00:00 2001 From: Darcy Date: Thu, 27 Aug 2015 11:12:12 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=B3=E6=B3=A8?= =?UTF-8?q?=E5=A5=BD=E5=8F=8B=E7=9A=84=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=98=BE=E7=A4=BA=E6=95=B0=E9=87=8F=E4=B8=8D=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/net/oschina/app/api/remote/OSChinaApi.java | 1 + .../main/java/net/oschina/app/ui/SelectUserActivity.java | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java b/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java index 74a406d53..6d7f153d2 100644 --- a/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java +++ b/app/src/main/java/net/oschina/app/api/remote/OSChinaApi.java @@ -1016,6 +1016,7 @@ public class OSChinaApi { RequestParams params = new RequestParams(); params.put("uid", uid); params.put("all", 1); + params.put("relation", 1); ApiHttpClient.get("action/api/friends_list", params, handler); } } diff --git a/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java index ac90a8db2..1d7eb65b5 100644 --- a/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java +++ b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java @@ -103,9 +103,9 @@ public class SelectUserActivity extends BaseActivity { private KJBitmap mkjBitmap; private String mSearchText; - private boolean mIsShowAll; private boolean mIsMultiSelect; private int mSelectUserPicSize; + private int mTotalFriendSize; private Handler mUIHandler = new Handler() { @Override @@ -296,7 +296,7 @@ public class SelectUserActivity extends BaseActivity { private void refleshSelectUsers(){ int selectFriendsSize = mSelectedFriends.size(); - mTvConfirm.setText(String.format("确定(%s/%s)", selectFriendsSize, mAllMdlFriends.size())); + mTvConfirm.setText(String.format("确定(%s/%s)", selectFriendsSize, mTotalFriendSize)); if(selectFriendsSize == 0){ mTvSelectedUsers.setVisibility(View.GONE); }else { @@ -523,10 +523,8 @@ public class SelectUserActivity extends BaseActivity { } if(!TextUtils.isEmpty(searchText)){ - mIsShowAll = false; searchFriends(searchText); }else{ - mIsShowAll = true; mShowMdlFriends.addAll(mAllMdlFriends); } @@ -546,10 +544,10 @@ public class SelectUserActivity extends BaseActivity { return; } + mTotalFriendSize = allFriends.size(); mFriendIndexs = new TreeMap<>(); Character firstAlpha; - for (Friend f : allFriends) { firstAlpha = StringUtils.getFirstLetter(f.getName().charAt(0)); if ('A' <= firstAlpha && firstAlpha <= 'Z') { -- Gitee From cec8c249829404649fb3dee00567a4e05f929a98 Mon Sep 17 00:00:00 2001 From: Darcy Date: Thu, 27 Aug 2015 16:59:11 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86bug,=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=90=9C=E7=B4=A2=E6=94=AF=E6=8C=81=E4=B8=AD?= =?UTF-8?q?=E6=96=87=E9=A6=96=E5=AD=97=E6=AF=8D,=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E5=A5=BD=E5=8F=8B=E5=9B=BE=E7=89=87=E4=B8=8D?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oschina/app/ui/SelectUserActivity.java | 169 ++++++------ .../net/oschina/app/util/StringUtils.java | 14 + .../net/oschina/app/widget/AlphabetBar.java | 10 +- .../net/oschina/app/widget/ImageGrid.java | 249 ++++++++++++++++++ .../main/res/layout/activity_select_user.xml | 24 +- .../main/res/layout/list_select_friend.xml | 2 +- app/src/main/res/values/attrs.xml | 5 + 7 files changed, 363 insertions(+), 110 deletions(-) create mode 100644 app/src/main/java/net/oschina/app/widget/ImageGrid.java diff --git a/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java index 1d7eb65b5..10195ca5b 100644 --- a/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java +++ b/app/src/main/java/net/oschina/app/ui/SelectUserActivity.java @@ -14,11 +14,8 @@ import android.support.v7.app.ActionBar; import android.os.Bundle; import android.text.Editable; import android.text.Html; -import android.text.Spannable; -import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.TextWatcher; -import android.text.style.ImageSpan; import android.util.SparseArray; import android.view.Gravity; import android.view.View; @@ -34,7 +31,6 @@ import android.widget.TextView; import android.widget.Toast; import com.loopj.android.http.AsyncHttpResponseHandler; - import net.oschina.app.AppContext; import net.oschina.app.R; import net.oschina.app.api.remote.OSChinaApi; @@ -45,6 +41,7 @@ import net.oschina.app.ui.empty.EmptyLayout; import net.oschina.app.util.StringUtils; import net.oschina.app.util.XmlUtils; import net.oschina.app.widget.AlphabetBar; +import net.oschina.app.widget.ImageGrid; import org.apache.http.Header; import org.kymjs.kjframe.KJBitmap; @@ -77,8 +74,6 @@ public class SelectUserActivity extends BaseActivity { private static final int MSG_SEARCH_FRIENDS = 0x20000; private static final int MSG_SEARCH_FRIENDS_SUCCESS = 0x20001; - private static final int MSG_SELECT_USERS_PROCESS = 0x30000; - private static final int MSG_SELECT_USERS_PROCESS_SUCCESS = 0x30001; private static final int MAX_SELECT_USER_COUNT = 10; @@ -87,7 +82,7 @@ public class SelectUserActivity extends BaseActivity { private EmptyLayout mEmptyLayout; private TextView mTvConfirm; private EditText mEtSearch; - private TextView mTvSelectedUsers; + private ImageGrid mIgSelectedUsers; private AlphabetBar mAlphaBar; private TextView mTvAlphaTip; private ListView mLvFriends; @@ -103,7 +98,6 @@ public class SelectUserActivity extends BaseActivity { private KJBitmap mkjBitmap; private String mSearchText; - private boolean mIsMultiSelect; private int mSelectUserPicSize; private int mTotalFriendSize; @@ -117,9 +111,6 @@ public class SelectUserActivity extends BaseActivity { mEmptyLayout.setVisibility(View.GONE); }else if(msg.what == MSG_SEARCH_FRIENDS_SUCCESS){ mLvAdapter.notifyDataSetChanged(); - }else if(msg.what == MSG_SELECT_USERS_PROCESS_SUCCESS){ - SpannableStringBuilder usersPicSpannable = (SpannableStringBuilder)msg.obj; - mTvSelectedUsers.setText(usersPicSpannable); } } }; @@ -164,10 +155,8 @@ public class SelectUserActivity extends BaseActivity { private final Comparator friendSearchComparator = new Comparator() { @Override public int compare(ItemModel lhs, ItemModel rhs) { - Friend lhsUser = (Friend) lhs.data; - Friend rhsUser = (Friend) rhs.data; - final String lhsUserName = lhsUser.getName(); - final String rhsUserName = rhsUser.getName(); + final String lhsUserName = lhs.primaryPinyin; + final String rhsUserName = rhs.primaryPinyin; final String lowerCaseKeyword = mSearchText.toLowerCase(); int result = lhsUserName.toLowerCase().indexOf(lowerCaseKeyword) - rhsUserName.toLowerCase().indexOf(lowerCaseKeyword); if(result == 0){ @@ -203,9 +192,9 @@ public class SelectUserActivity extends BaseActivity { ActionBar.LayoutParams params = new ActionBar.LayoutParams( ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, Gravity.END | Gravity.CENTER_VERTICAL); mTvConfirm.setLayoutParams(params); + mTvConfirm.setText("确定"); mTvConfirm.setTextColor(getResources().getColor(R.color.white)); mTvConfirm.setOnClickListener(this); - mTvConfirm.setVisibility(View.GONE); actionBar.setCustomView(mTvConfirm); } @@ -227,7 +216,7 @@ public class SelectUserActivity extends BaseActivity { mEtSearch.addTextChangedListener(mSearchTextWatcher); mAlphaBar = (AlphabetBar)findViewById(R.id.alphabet_bar); mTvAlphaTip = (TextView)findViewById(R.id.alphabet_tip); - mTvSelectedUsers = (TextView)findViewById(R.id.selected_users_tv); + mIgSelectedUsers = (ImageGrid)findViewById(R.id.selected_users_ig); mLvFriends.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { @@ -240,46 +229,40 @@ public class SelectUserActivity extends BaseActivity { public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); - mLvFriends.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + mLvFriends.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + public void onItemClick(AdapterView parent, View view, int position, long id) { ItemModel m = mShowMdlFriends.get(position); - if (m.type == ItemModel.TYPE_USER_INFO && !mSelectedFriends.contains(m.data) && !checkIfExceedMaxSelectCount()) { + if (m.type == ItemModel.TYPE_USER_INFO) { Friend f = (Friend) m.data; - mSelectedFriends.add(f); - if (!mIsMultiSelect) { - mIsMultiSelect = true; - mLvAdapter.notifyDataSetChanged(); - mTvConfirm.setVisibility(View.VISIBLE); - refleshSelectUsers(); - } else { - mLvAdapter.refleshItemStatus(position, f); - refleshSelectUsers(); + if (mSelectedFriends.contains(f)) { + mSelectedFriends.remove(f); + } else if (!checkIfExceedMaxSelectCount()) { + mSelectedFriends.add(f); } + mLvAdapter.refleshItemStatus(position, f); + refleshSelectUsers(); } - return true; } }); - mLvFriends.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + mIgSelectedUsers.setOnImageGridItemClickListener(new ImageGrid.OnImageGridItemClickListener() { @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - ItemModel m = mShowMdlFriends.get(position); - if (m.type == ItemModel.TYPE_USER_INFO) { - Friend f = (Friend) m.data; - if (mIsMultiSelect) { - if (mSelectedFriends.contains(f)) { - mSelectedFriends.remove(f); - } else if(!checkIfExceedMaxSelectCount()){ - mSelectedFriends.add(f); - } - mLvAdapter.refleshItemStatus(position, f); - refleshSelectUsers(); - } else { - Intent resultIntent = new Intent(); - resultIntent.putExtra(RESULT_AT_USERS, String.format("@%s ", f.getName())); - setResult(RESULT_OK, resultIntent); - finish(); + public void onImageClick(int row, int column) { + Friend removeFriend = null; + final int removeIndex = row * column + column; + int i = 0; + for(Friend f : mSelectedFriends){ + if(i == removeIndex){ + removeFriend = f; + break; } + ++i; + } + if(removeFriend != null){ + mSelectedFriends.remove(removeFriend); + mLvAdapter.refleshItemStatus(removeIndex, removeFriend); + refleshSelectUsers(); } } }); @@ -298,10 +281,15 @@ public class SelectUserActivity extends BaseActivity { int selectFriendsSize = mSelectedFriends.size(); mTvConfirm.setText(String.format("确定(%s/%s)", selectFriendsSize, mTotalFriendSize)); if(selectFriendsSize == 0){ - mTvSelectedUsers.setVisibility(View.GONE); + mIgSelectedUsers.setVisibility(View.GONE); }else { - mTvSelectedUsers.setVisibility(View.VISIBLE); - mBackgroundHandler.sendEmptyMessage(MSG_SELECT_USERS_PROCESS); + mIgSelectedUsers.setVisibility(View.VISIBLE); + Bitmap[] userBitmaps = new Bitmap[mSelectedFriends.size()]; + int i = 0; + for(Friend f : mSelectedFriends){ + userBitmaps[i++] = getCacheUserBitmap(f.getPortrait()); + } + mIgSelectedUsers.setBitmaps(userBitmaps); } } @@ -385,7 +373,7 @@ public class SelectUserActivity extends BaseActivity { static final int TYPE_USER_INFO = 0x1; int type; Object data; - + String primaryPinyin; } private class FriendListAdapter extends BaseAdapter{ @@ -469,15 +457,11 @@ public class SelectUserActivity extends BaseActivity { selectorHolder.put(position,viewHodler.ivSelector); - if(mIsMultiSelect){ - viewHodler.ivSelector.setVisibility(View.VISIBLE); - if(mSelectedFriends.contains(friend)){ - viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_selected); - }else{ - viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect); - } + + if(mSelectedFriends.contains(friend)){ + viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_selected); }else{ - viewHodler.ivSelector.setVisibility(View.GONE); + viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect); } mkjBitmap.display(viewHodler.ivUserAvator,friend.getPortrait()); @@ -529,9 +513,6 @@ public class SelectUserActivity extends BaseActivity { } mUIHandler.sendEmptyMessage(MSG_SEARCH_FRIENDS_SUCCESS); - }else if(msg.what == MSG_SELECT_USERS_PROCESS){ - SpannableStringBuilder spannable = processSelectedUsers(); - mUIHandler.sendMessage(mUIHandler.obtainMessage(MSG_SELECT_USERS_PROCESS_SUCCESS, spannable)); } } @@ -574,6 +555,7 @@ public class SelectUserActivity extends BaseActivity { model = new ItemModel(); model.type = ItemModel.TYPE_USER_INFO; model.data = friend; + model.primaryPinyin = StringUtils.toPrimaryPinyin(friend.getName()); mShowMdlFriends.add(model); ++itemPos; } @@ -601,9 +583,19 @@ public class SelectUserActivity extends BaseActivity { if(m.type == ItemModel.TYPE_USER_INFO && m.data instanceof Friend){ Friend f = (Friend) m.data; String name = f.getName(); - if(name.toLowerCase().contains(searchText.toLowerCase())){ + String lowerSearchText = searchText.toLowerCase(); + + if(name.toLowerCase().contains(lowerSearchText)){ f.setName(name.replaceAll("((?i)" + searchText + ")",HIGHLIGHT_REPLACEMENT)); mShowMdlFriends.add(m); + continue; + } + + String lowerCasePrimaryPinyin = m.primaryPinyin.toLowerCase(); + if(lowerCasePrimaryPinyin.contains(lowerSearchText)){ + String highlightName = highlightName(f.getName(),lowerSearchText, lowerCasePrimaryPinyin); + f.setName(highlightName); + mShowMdlFriends.add(m); } } } @@ -611,37 +603,28 @@ public class SelectUserActivity extends BaseActivity { Collections.sort(mShowMdlFriends, friendSearchComparator); } - private SpannableStringBuilder processSelectedUsers(){ - int selectFriendsSize = mSelectedFriends.size(); - - String spanText = ""; - int picIndex; - for(picIndex = 0 ; picIndex < selectFriendsSize ; ++picIndex){ - spanText += (picIndex + " "); - } - spanText = spanText.substring(0,spanText.length() - 1); - SpannableStringBuilder spannable = new SpannableStringBuilder(spanText); - - ImageSpan imgSpan; - Bitmap bmUser , newBmUser; - picIndex = 0; - int spanStart; - String indexStr; - - for (Friend f : mSelectedFriends) { - indexStr = String.valueOf(picIndex); - spanStart = spanText.indexOf(indexStr); - bmUser = getCacheUserBitmap(f.getPortrait()); - newBmUser = Bitmap.createScaledBitmap(bmUser, mSelectUserPicSize, mSelectUserPicSize, true); - if (newBmUser == null) { - newBmUser = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.widget_dface), mSelectUserPicSize, mSelectUserPicSize, true); - } - imgSpan = new ImageSpan(SelectUserActivity.this, newBmUser); - spannable.setSpan(imgSpan, spanStart, spanStart + indexStr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ++picIndex; + private String highlightName(String name , String keyWord , String primaryPinyin){ + if(name == null || primaryPinyin == null || name.length() != primaryPinyin.length()) + return name; + + int startIndex, endIndex; + + StringBuilder srcBuilder = new StringBuilder(name); + StringBuilder primaryPinyinBuidler = new StringBuilder(primaryPinyin); + + startIndex = primaryPinyin.indexOf(keyWord); + String beginTag = String.format("", HIGHLIGHT_COLOR); + String endTag = ""; + while(startIndex != -1){ + srcBuilder.insert(startIndex, beginTag); + primaryPinyinBuidler.insert(startIndex, beginTag); + endIndex = startIndex + keyWord.length() + beginTag.length(); + srcBuilder.insert(endIndex, endTag); + primaryPinyinBuidler.insert(endIndex, endTag); + startIndex = primaryPinyinBuidler.indexOf(keyWord, endIndex + endTag.length()); } - return spannable; + return srcBuilder.toString(); } } diff --git a/app/src/main/java/net/oschina/app/util/StringUtils.java b/app/src/main/java/net/oschina/app/util/StringUtils.java index b190757d1..7d6b9fa8e 100644 --- a/app/src/main/java/net/oschina/app/util/StringUtils.java +++ b/app/src/main/java/net/oschina/app/util/StringUtils.java @@ -505,4 +505,18 @@ public class StringUtils { return ch; } + + /** + * 返回首字母组成的字符串,英文(统一大写)和特殊字符不变化 + * @param str + * @return + */ + public static String toPrimaryPinyin(String str){ + char[] strChars = str.toCharArray(); + StringBuilder primaryPinyin = new StringBuilder(); + for(char ch : strChars){ + primaryPinyin.append(getFirstLetter(ch)); + } + return primaryPinyin.toString(); + } } diff --git a/app/src/main/java/net/oschina/app/widget/AlphabetBar.java b/app/src/main/java/net/oschina/app/widget/AlphabetBar.java index e0e4cbe43..f8dbc16f6 100644 --- a/app/src/main/java/net/oschina/app/widget/AlphabetBar.java +++ b/app/src/main/java/net/oschina/app/widget/AlphabetBar.java @@ -72,7 +72,8 @@ public class AlphabetBar extends View { final int width = getWidth(); if(!mHasInitParams){ final int paddingTop = getPaddingTop(); - final int height = getHeight() - paddingTop - getPaddingBottom(); + final int paddingBottom = getPaddingBottom(); + final int height = getHeight() - paddingTop - paddingBottom; this.mUnitHeight = height / ALPHABETS.length; final FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); this.letterYOffset = (int) ((mUnitHeight - (fontMetrics.bottom - fontMetrics.top)) * 0.5 - fontMetrics.top + paddingTop); @@ -99,9 +100,10 @@ public class AlphabetBar extends View { public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); final int action = event.getAction(); - if(action == MotionEvent.ACTION_MOVE){ - final float moveY = event.getY(); - final int newIndex = (int) (moveY / mUnitHeight) ; + final int paddingTop = getPaddingTop(); + if(action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE){ + final float eventY = event.getY(); + final int newIndex = (int) ((eventY - paddingTop) / mUnitHeight) ; if(originIndex != newIndex && 0 <= newIndex && newIndex < ALPHABETS.length){ originIndex = newIndex; if(mOnAlphabetTouchListener != null){ diff --git a/app/src/main/java/net/oschina/app/widget/ImageGrid.java b/app/src/main/java/net/oschina/app/widget/ImageGrid.java new file mode 100644 index 000000000..69503b77c --- /dev/null +++ b/app/src/main/java/net/oschina/app/widget/ImageGrid.java @@ -0,0 +1,249 @@ +package net.oschina.app.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import net.oschina.app.R; + +/** + * + * 图片表格控件,它会根据占用的width和规定的列数来平均每张图片的大小。 + * + * @author Darcy www.darcye.com + * + */ +public class ImageGrid extends View { + + private int mImageNumber; + + private int mColumnNum; + private int mMaxRow = 100; + private int mTotalRow; + + private int mCellGap; + private int mCellHeight; + + private Bitmap[] mBitmaps; + + private SparseArray mPositionRectMap; + private ViewConfiguration mViewConfiguration; + + private int mCurrentPosition; + + private OnImageGridItemClickListener mOnImageGridItemClickListener; + + private boolean mNeedReLayout = true; + + public ImageGrid(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ImageGrid); + mCellGap = a.getDimensionPixelSize(R.styleable.ImageGrid_CellGap, 10); + mColumnNum = a.getInteger(R.styleable.ImageGrid_ColumnNum, 9); + a.recycle(); + mViewConfiguration = ViewConfiguration.get(context); + } + + public void setOnImageGridItemClickListener( + OnImageGridItemClickListener onImageGridItemClickListener) { + mOnImageGridItemClickListener = onImageGridItemClickListener; + } + + /** + * 最大行数 + * @param maxRow + */ + public void setMaxRow(int maxRow){ + this.mMaxRow = maxRow; + } + + /** + * 设置列数 + * @param columnNum + */ + public void setColumnNumber(int columnNum){ + this.mColumnNum = columnNum; + } + + /** + * 设置 + * @param bitmaps + */ + public void setBitmaps(Bitmap[] bitmaps){ + this.mBitmaps = bitmaps; + this.mImageNumber = bitmaps.length; + this.mPositionRectMap = new SparseArray<>(bitmaps.length); + invalidate(); + } + + public void setNeedReLayout(boolean needReLayout) { + mNeedReLayout = needReLayout; + } + + public int getColumnNumer(){ + return mColumnNum; + } + + /** + * 更新某个位置的图片 + * @param bitmap + * @param position + */ + public void refleshBitmap(Bitmap bitmap,int position){ + + if(mBitmaps == null){ + throw new NullPointerException("please setBitmaps first."); + } + + + if(position >= mBitmaps.length){ + throw new IllegalArgumentException("position cannot bigger than the capacity"); + } + + if(bitmap == null || mBitmaps[position] == bitmap){ + return; + } + + mBitmaps[position] = bitmap; + Rect rect = mPositionRectMap.get(position); + invalidate(rect); + } + + @Override + protected void onDraw(Canvas canvas) { + + if(!mNeedReLayout) + return; + + final int totalRow = mTotalRow; + + if(mImageNumber <= 0 || mColumnNum <=0){ + return; + } + + final int lastRowCount = (mImageNumber % mColumnNum) ==0 ? mColumnNum : (mImageNumber % mColumnNum); + mCurrentPosition = 0; + + if(totalRow == 1){ + drawOneRow(canvas, 0, lastRowCount); + return; + } + + if(totalRow == 2){ + drawOneRow(canvas, 0, mColumnNum); + drawOneRow(canvas, 1, lastRowCount); + return; + } + + for(int curRow = 0 ; curRow < totalRow - 1 ; ++curRow){ + drawOneRow(canvas, curRow, mColumnNum); + } + + drawOneRow(canvas, totalRow-1, lastRowCount); + + } + + private void drawOneRow(Canvas canvas, int rowNum,int rowCount){ + final int cellHeight = mCellHeight; + final int cellGap = mCellGap; + int curPos = mCurrentPosition; + int curTop = rowNum == 0 ? 0 : rowNum * (cellHeight + cellGap); + int curBottom = curTop + cellHeight; + int curLeft = 0; + int curRight = curLeft + cellHeight; + + Rect rect; + for(int pos = 0; pos < rowCount; ++pos, ++curPos){ + rect = mPositionRectMap.get(curPos); + if(rect == null){ + rect = new Rect(); + rect.left = curLeft; + rect.top = curTop; + rect.right = curRight; + rect.bottom = curBottom; + mPositionRectMap.put(curPos, rect); + } + canvas.drawBitmap(mBitmaps[curPos], null, rect, null); + curLeft += (cellHeight + cellGap) ; + curRight = curLeft + cellHeight; + } + + mCurrentPosition = curPos; + } + + private float touchDownX, touchDownY; + private boolean isValidClick; + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + switch(event.getAction()){ + case MotionEvent.ACTION_DOWN: + touchDownX = event.getX(); + touchDownY = event.getY(); + isValidClick = true; + break; + case MotionEvent.ACTION_MOVE: + if(!isValidClick && (Math.abs(touchDownY - event.getY()) > mViewConfiguration.getScaledTouchSlop() + || Math.abs(touchDownX - event.getX()) > mViewConfiguration.getScaledTouchSlop())){ + isValidClick = false; + } + break; + case MotionEvent.ACTION_CANCEL: + isValidClick = false; + break; + case MotionEvent.ACTION_UP: + if(isValidClick){ + final int validItemWidth = getWidth() / mColumnNum; + final int validItemHeight = getHeight() / mTotalRow; + int clickColumn = (int) Math.ceil(touchDownX / validItemWidth); + int clickRow = (int) Math.ceil(touchDownY / validItemHeight); + if(mOnImageGridItemClickListener != null && clickColumn >= 1 && clickRow >= 1){ + mOnImageGridItemClickListener.onImageClick(clickRow-1, clickColumn-1); + } + } + isValidClick = false; + break; + } + return true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + if(!mNeedReLayout) + return; + + if(mImageNumber <= 0){ + setMeasuredDimension(0, 0); + return; + } + + final int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); + int specHeightSize; + int rowNum = mImageNumber%mColumnNum == 0 ? mImageNumber/mColumnNum : mImageNumber / mColumnNum + 1; + mTotalRow = Math.min(rowNum, mMaxRow); + mCellHeight = ( specWidthSize - (mColumnNum - 1) * mCellGap ) / mColumnNum; + if(mTotalRow == 1){ + specHeightSize = mCellHeight; + }else{ + specHeightSize = mTotalRow * mCellHeight + (mTotalRow - 1) * mCellGap; + } + setMeasuredDimension(specWidthSize, specHeightSize); + } + + + public interface OnImageGridItemClickListener{ + /** + * call back when clicking image + * @param row + * @param column + */ + void onImageClick(int row, int column); + } +} diff --git a/app/src/main/res/layout/activity_select_user.xml b/app/src/main/res/layout/activity_select_user.xml index ed96cc6ee..64f298f60 100644 --- a/app/src/main/res/layout/activity_select_user.xml +++ b/app/src/main/res/layout/activity_select_user.xml @@ -23,21 +23,23 @@ android:hint="搜索" android:textColorHint="@color/gray"/> - + android:layout_marginLeft="10dp" + android:layout_marginRight="10dp" + android:layout_marginBottom="5dp" + android:visibility="gone" + app:ColumnNum="10" + app:CellGap="2dp"/> + /> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index cede74952..b84bc5aee 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -15,4 +15,9 @@ + + + + + \ No newline at end of file -- Gitee