From ad1f14c20c0e38e8849730ef2aada20457118bb3 Mon Sep 17 00:00:00 2001 From: Mariotaku Lee Date: Sat, 7 Jan 2017 22:45:33 +0800 Subject: [PATCH] fixed #672 --- .../adapter/ComposeAutoCompleteAdapter.java | 188 ------------------ .../preference/AccountsListPreference.java | 34 +--- .../mariotaku/twidere/util/BitmapUtils.java | 29 --- .../twidere/view/holder/GroupViewHolder.java | 145 -------------- .../holder/IncomingMessageViewHolder.java | 57 ------ .../view/holder/MessageEntryViewHolder.java | 127 ------------ .../view/holder/MessageViewHolder.java | 140 ------------- .../view/holder/UserListViewHolder.java | 134 ------------- .../twidere/activity/ComposeActivity.kt | 5 + .../twidere/adapter/AccountsSpinnerAdapter.kt | 51 ++--- .../twidere/adapter/BaseArrayAdapter.kt | 8 +- .../adapter/ComposeAutoCompleteAdapter.kt | 170 ++++++++++++++++ .../adapter/ParcelableActivitiesAdapter.kt | 5 +- .../adapter/ParcelableGroupsAdapter.kt | 2 +- .../adapter/ParcelableUserListsAdapter.kt | 17 +- .../adapter/UserAutoCompleteAdapter.kt | 71 ++++--- .../fragment/AccountsDashboardFragment.kt | 17 +- .../twidere/fragment/StatusFragment.kt | 10 +- .../twidere/fragment/UserFragment.kt | 9 + .../holder/ActivityTitleSummaryViewHolder.kt | 26 ++- .../twidere/view/holder/GroupViewHolder.kt | 135 +++++++++++++ .../view/holder/IncomingMessageViewHolder.kt | 56 ++++++ .../view/holder/MessageEntryViewHolder.kt | 115 +++++++++++ .../twidere/view/holder/MessageViewHolder.kt | 134 +++++++++++++ .../twidere/view/holder/StatusViewHolder.kt | 5 +- .../twidere/view/holder/UserListViewHolder.kt | 126 ++++++++++++ .../twidere/view/holder/UserViewHolder.kt | 4 +- .../res/layout/list_item_auto_complete.xml | 13 +- .../res/layout/list_item_message_entry.xml | 10 +- 29 files changed, 867 insertions(+), 976 deletions(-) delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.java delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/view/holder/GroupViewHolder.java delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.java delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.java delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageViewHolder.java delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/view/holder/UserListViewHolder.java create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/GroupViewHolder.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageViewHolder.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserListViewHolder.kt diff --git a/twidere/src/main/java/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.java b/twidere/src/main/java/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.java deleted file mode 100644 index d2b4a1d28..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2014 Mariotaku Lee - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.mariotaku.twidere.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.graphics.PorterDuff.Mode; -import android.net.Uri; -import android.support.annotation.Nullable; -import android.support.v4.widget.SimpleCursorAdapter; -import android.text.TextUtils; -import android.view.View; -import android.widget.FilterQueryProvider; -import android.widget.ImageView; -import android.widget.TextView; - -import org.apache.commons.lang3.StringUtils; -import org.mariotaku.twidere.Constants; -import org.mariotaku.twidere.R; -import org.mariotaku.twidere.model.UserKey; -import org.mariotaku.twidere.provider.TwidereDataStore.Suggestions; -import org.mariotaku.twidere.util.MediaLoaderWrapper; -import org.mariotaku.twidere.util.SharedPreferencesWrapper; -import org.mariotaku.twidere.util.UserColorNameManager; -import org.mariotaku.twidere.util.dagger.GeneralComponentHelper; - -import javax.inject.Inject; - -public class ComposeAutoCompleteAdapter extends SimpleCursorAdapter implements Constants { - - private static final String[] FROM = new String[0]; - private static final int[] TO = new int[0]; - - @Inject - MediaLoaderWrapper mProfileImageLoader; - @Inject - SharedPreferencesWrapper mPreferences; - @Inject - UserColorNameManager mUserColorNameManager; - - private final boolean mDisplayProfileImage; - - private int mTypeIdx, mIconIdx, mTitleIdx, mSummaryIdx, mExtraIdIdx, mValueIdx; - private UserKey accountKey; - private char mToken; - - public ComposeAutoCompleteAdapter(final Context context) { - super(context, R.layout.list_item_auto_complete, null, FROM, TO, 0); - GeneralComponentHelper.build(context).inject(this); - mDisplayProfileImage = mPreferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true); - } - - @Override - public void bindView(final View view, final Context context, final Cursor cursor) { - final TextView text1 = (TextView) view.findViewById(android.R.id.text1); - final TextView text2 = (TextView) view.findViewById(android.R.id.text2); - final ImageView icon = (ImageView) view.findViewById(android.R.id.icon); - - // Clear images in order to prevent images in recycled view shown. - icon.setImageDrawable(null); - - if (Suggestions.AutoComplete.TYPE_USERS.equals(cursor.getString(mTypeIdx))) { - text1.setText(mUserColorNameManager.getUserNickname(cursor.getString(mExtraIdIdx), - cursor.getString(mTitleIdx))); - text2.setText(String.format("@%s", cursor.getString(mSummaryIdx))); - if (mDisplayProfileImage) { - final String profileImageUrl = cursor.getString(mIconIdx); - mProfileImageLoader.displayProfileImage(icon, profileImageUrl); - } else { - mProfileImageLoader.cancelDisplayTask(icon); - } - - icon.clearColorFilter(); - } else { - text1.setText(String.format("#%s", cursor.getString(mTitleIdx))); - text2.setText(R.string.hashtag); - - icon.setImageResource(R.drawable.ic_action_hashtag); - icon.setColorFilter(text1.getCurrentTextColor(), Mode.SRC_ATOP); - } - icon.setVisibility(mDisplayProfileImage ? View.VISIBLE : View.GONE); - super.bindView(view, context, cursor); - } - - public void closeCursor() { - final Cursor cursor = swapCursor(null); - if (cursor == null) return; - if (!cursor.isClosed()) { - cursor.close(); - } - } - - @Override - public CharSequence convertToString(final Cursor cursor) { - switch (StringUtils.defaultIfEmpty(cursor.getString(mTypeIdx), "")) { - case Suggestions.AutoComplete.TYPE_HASHTAGS: { - return '#' + cursor.getString(mValueIdx); - } - case Suggestions.AutoComplete.TYPE_USERS: { - return '@' + cursor.getString(mValueIdx); - } - } - return cursor.getString(mValueIdx); - } - - @Override - public Cursor runQueryOnBackgroundThread(final CharSequence constraint) { - if (TextUtils.isEmpty(constraint)) return null; - char token = constraint.charAt(0); - if (getNormalizedSymbol(token) == getNormalizedSymbol(mToken)) { - final FilterQueryProvider filter = getFilterQueryProvider(); - if (filter != null) return filter.runQuery(constraint); - } - mToken = token; - final Uri.Builder builder = Suggestions.AutoComplete.CONTENT_URI.buildUpon(); - builder.appendQueryParameter(QUERY_PARAM_QUERY, String.valueOf(constraint.subSequence(1, constraint.length()))); - switch (getNormalizedSymbol(token)) { - case '#': { - builder.appendQueryParameter(QUERY_PARAM_TYPE, Suggestions.AutoComplete.TYPE_HASHTAGS); - break; - } - case '@': { - builder.appendQueryParameter(QUERY_PARAM_TYPE, Suggestions.AutoComplete.TYPE_USERS); - break; - } - default: { - return null; - } - } - builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, String.valueOf(accountKey)); - return mContext.getContentResolver().query(builder.build(), Suggestions.AutoComplete.COLUMNS, - null, null, null); - } - - - public void setAccountKey(UserKey accountKey) { - this.accountKey = accountKey; - } - - public UserKey getAccountKey() { - return accountKey; - } - - @Override - @Nullable - public Cursor swapCursor(@Nullable final Cursor cursor) { - if (cursor != null) { - mTypeIdx = cursor.getColumnIndex(Suggestions.AutoComplete.TYPE); - mTitleIdx = cursor.getColumnIndex(Suggestions.AutoComplete.TITLE); - mSummaryIdx = cursor.getColumnIndex(Suggestions.AutoComplete.SUMMARY); - mExtraIdIdx = cursor.getColumnIndex(Suggestions.AutoComplete.EXTRA_ID); - mIconIdx = cursor.getColumnIndex(Suggestions.AutoComplete.ICON); - mValueIdx = cursor.getColumnIndex(Suggestions.AutoComplete.VALUE); - } - return super.swapCursor(cursor); - } - - - private static char getNormalizedSymbol(final char character) { - switch (character) { - case '\uff20': - case '@': - return '@'; - case '\uff03': - case '#': - return '#'; - } - return '\0'; - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java b/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java index c787e03a8..16586ac7b 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java +++ b/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java @@ -24,8 +24,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.internal.widget.PreferenceImageView; @@ -35,19 +33,14 @@ import android.support.v7.preference.PreferenceManager; import android.support.v7.preference.PreferenceViewHolder; import android.support.v7.widget.SwitchCompat; import android.util.AttributeSet; -import android.view.Gravity; import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import com.nostra13.universalimageloader.core.assist.FailReason; -import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; - import org.mariotaku.twidere.Constants; import org.mariotaku.twidere.R; import org.mariotaku.twidere.model.AccountDetails; import org.mariotaku.twidere.model.util.AccountUtils; -import org.mariotaku.twidere.util.BitmapUtils; import org.mariotaku.twidere.util.MediaLoaderWrapper; import org.mariotaku.twidere.util.dagger.GeneralComponentHelper; @@ -101,8 +94,7 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen return mSwitchDefault; } - public static final class AccountItemPreference extends Preference implements ImageLoadingListener, - OnSharedPreferenceChangeListener { + public static final class AccountItemPreference extends Preference implements OnSharedPreferenceChangeListener { private final AccountDetails mAccount; @Nullable @@ -125,33 +117,9 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen mSwitchPreference.registerOnSharedPreferenceChangeListener(this); setTitle(mAccount.user.name); setSummary(String.format("@%s", mAccount.user.screen_name)); - mImageLoader.loadProfileImage(mAccount, this); setWidgetLayoutResource(R.layout.layout_preference_switch_indicator); } - @Override - public void onLoadingCancelled(final String imageUri, final View view) { -// setIcon(R.drawable.ic_profile_image_default); - } - - @Override - public void onLoadingComplete(final String imageUri, final View view, final Bitmap loadedImage) { - final Bitmap roundedBitmap = BitmapUtils.getCircleBitmap(loadedImage); - final BitmapDrawable icon = new BitmapDrawable(getContext().getResources(), roundedBitmap); - icon.setGravity(Gravity.FILL); - setIcon(icon); - } - - @Override - public void onLoadingFailed(final String imageUri, final View view, final FailReason failReason) { -// setIcon(R.drawable.ic_profile_image_default); - } - - @Override - public void onLoadingStarted(final String imageUri, final View view) { -// setIcon(R.drawable.ic_profile_image_default); - } - @Override public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) { notifyChanged(); diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/BitmapUtils.java b/twidere/src/main/java/org/mariotaku/twidere/util/BitmapUtils.java index 9914bef7d..5d9e62a73 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/BitmapUtils.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/BitmapUtils.java @@ -17,15 +17,7 @@ package org.mariotaku.twidere.util; import android.content.ContentResolver; -import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.RectF; import android.net.Uri; import android.support.annotation.Nullable; @@ -38,27 +30,6 @@ public class BitmapUtils { private BitmapUtils() { } - public static Bitmap getCircleBitmap(Bitmap bitmap) { - final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), - Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(output); - - final int color = Color.RED; - final Paint paint = new Paint(); - final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); - final RectF rectF = new RectF(rect); - - paint.setAntiAlias(true); - canvas.drawARGB(0, 0, 0, 0); - paint.setColor(color); - canvas.drawOval(rectF, paint); - - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(bitmap, rect, rect, paint); - - return output; - } - @Nullable public static String getImageMimeType(ContentResolver cr, final Uri uri) { if (uri == null) return null; diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/holder/GroupViewHolder.java b/twidere/src/main/java/org/mariotaku/twidere/view/holder/GroupViewHolder.java deleted file mode 100644 index b703bd1ff..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/view/holder/GroupViewHolder.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2015 Mariotaku Lee - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.mariotaku.twidere.view.holder; - -import android.content.Context; -import android.support.v4.text.BidiFormatter; -import android.support.v7.widget.RecyclerView.ViewHolder; -import android.text.TextUtils; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import org.mariotaku.twidere.R; -import org.mariotaku.twidere.adapter.iface.IGroupsAdapter; -import org.mariotaku.twidere.model.ParcelableGroup; -import org.mariotaku.twidere.model.util.UserKeyUtils; -import org.mariotaku.twidere.util.MediaLoaderWrapper; -import org.mariotaku.twidere.util.Utils; -import org.mariotaku.twidere.view.NameView; -import org.mariotaku.twidere.view.iface.IColorLabelView; - -import java.util.Locale; - -/** - * Created by mariotaku on 15/4/29. - */ -public class GroupViewHolder extends ViewHolder implements View.OnClickListener, View.OnLongClickListener { - - private final IGroupsAdapter adapter; - - private final IColorLabelView itemContent; - private final ImageView profileImageView; - private final NameView nameView; - private final TextView externalIndicator; - private final TextView descriptionView; - private final TextView membersCountView; - private final TextView adminsCountView; - - private IGroupsAdapter.GroupAdapterListener groupClickListener; - - public GroupViewHolder(IGroupsAdapter adapter, View itemView) { - super(itemView); - itemContent = (IColorLabelView) itemView.findViewById(R.id.itemContent); - this.adapter = adapter; - profileImageView = (ImageView) itemView.findViewById(R.id.profileImage); - nameView = (NameView) itemView.findViewById(R.id.name); - externalIndicator = (TextView) itemView.findViewById(R.id.externalIndicator); - descriptionView = (TextView) itemView.findViewById(R.id.description); - membersCountView = (TextView) itemView.findViewById(R.id.membersCount); - adminsCountView = (TextView) itemView.findViewById(R.id.adminsCount); - } - - public void displayGroup(ParcelableGroup group) { - final Context context = itemView.getContext(); - final MediaLoaderWrapper loader = adapter.getMediaLoader(); - final BidiFormatter formatter = adapter.getBidiFormatter(); - - nameView.setName(group.fullname); - nameView.setScreenName("!" + group.nickname); - - nameView.updateText(formatter); - final String groupHost = UserKeyUtils.getUserHost(group.url, group.account_key.getHost()); - if (UserKeyUtils.isSameHost(group.account_key.getHost(), groupHost)) { - externalIndicator.setVisibility(View.GONE); - } else { - externalIndicator.setVisibility(View.VISIBLE); - externalIndicator.setText(context.getString(R.string.external_group_host_format, - groupHost)); - } - if (adapter.getProfileImageEnabled()) { - profileImageView.setVisibility(View.VISIBLE); - loader.displayProfileImage(profileImageView, group.homepage_logo); - } else { - profileImageView.setVisibility(View.GONE); - loader.cancelDisplayTask(profileImageView); - } - descriptionView.setVisibility(TextUtils.isEmpty(group.description) ? View.GONE : View.VISIBLE); - descriptionView.setText(formatter.unicodeWrap(group.description)); - membersCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), group.member_count)); - adminsCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), group.admin_count)); - } - - public void setOnClickListeners() { - setGroupClickListener(adapter.getGroupAdapterListener()); - } - - @Override - public void onClick(View v) { - if (groupClickListener == null) return; - switch (v.getId()) { - case R.id.itemContent: { - groupClickListener.onGroupClick(this, getLayoutPosition()); - break; - } - } - } - - @Override - public boolean onLongClick(View v) { - if (groupClickListener == null) return false; - switch (v.getId()) { - case R.id.itemContent: { - return groupClickListener.onGroupLongClick(this, getLayoutPosition()); - } - } - return false; - } - - public void setGroupClickListener(IGroupsAdapter.GroupAdapterListener listener) { - groupClickListener = listener; - ((View) itemContent).setOnClickListener(this); - ((View) itemContent).setOnLongClickListener(this); - } - - public void setupViewOptions() { - setTextSize(adapter.getTextSize()); - } - - public void setTextSize(final float textSize) { - descriptionView.setTextSize(textSize); - externalIndicator.setTextSize(textSize); - nameView.setPrimaryTextSize(textSize); - nameView.setSecondaryTextSize(textSize * 0.75f); - membersCountView.setTextSize(textSize); - adminsCountView.setTextSize(textSize); - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.java b/twidere/src/main/java/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.java deleted file mode 100644 index c3cfa6e42..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2015 Mariotaku Lee - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.mariotaku.twidere.view.holder; - -import android.database.Cursor; -import android.view.View; -import android.widget.ImageView; - -import org.mariotaku.twidere.R; -import org.mariotaku.twidere.adapter.MessageConversationAdapter; -import org.mariotaku.twidere.model.ParcelableDirectMessageCursorIndices; -import org.mariotaku.twidere.util.MediaLoaderWrapper; - -/** - * Created by mariotaku on 15/4/25. - */ -public class IncomingMessageViewHolder extends MessageViewHolder { - - private final ImageView profileImageView; - - public IncomingMessageViewHolder(MessageConversationAdapter adapter, View itemView) { - super(adapter, itemView); - profileImageView = (ImageView) itemView.findViewById(R.id.profileImage); - } - - @Override - public void displayMessage(Cursor cursor, ParcelableDirectMessageCursorIndices indices) { - super.displayMessage(cursor, indices); - final MediaLoaderWrapper wrapper = adapter.getMediaLoader(); - if (adapter.getProfileImageEnabled()) { - profileImageView.setVisibility(View.VISIBLE); - wrapper.displayProfileImage(profileImageView, cursor.getString(indices.sender_profile_image_url)); - } else { - profileImageView.setVisibility(View.GONE); - wrapper.cancelDisplayTask(profileImageView); - } - } - - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.java b/twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.java deleted file mode 100644 index c1d5daf33..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2014 Mariotaku Lee - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.mariotaku.twidere.view.holder; - -import android.content.Context; -import android.database.Cursor; -import android.graphics.Typeface; -import android.support.annotation.UiThread; -import android.support.v7.widget.RecyclerView.ViewHolder; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageView; -import android.widget.TextView; - -import org.mariotaku.twidere.R; -import org.mariotaku.twidere.adapter.MessageEntriesAdapter; -import org.mariotaku.twidere.model.UserKey; -import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries; -import org.mariotaku.twidere.util.MediaLoaderWrapper; -import org.mariotaku.twidere.util.UserColorNameManager; -import org.mariotaku.twidere.view.NameView; -import org.mariotaku.twidere.view.ShortTimeView; -import org.mariotaku.twidere.view.iface.IColorLabelView; - -import static org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText; - -public class MessageEntryViewHolder extends ViewHolder implements OnClickListener { - - public final ImageView profileImage; - public final NameView nameView; - public final TextView textView; - public final ShortTimeView timeView; - private final MessageEntriesAdapter adapter; - private final IColorLabelView content; - - public MessageEntryViewHolder(final MessageEntriesAdapter adapter, final View itemView) { - super(itemView); - this.adapter = adapter; - content = (IColorLabelView) itemView.findViewById(R.id.content); - profileImage = (ImageView) itemView.findViewById(R.id.profileImage); - nameView = (NameView) itemView.findViewById(R.id.name); - textView = (TextView) itemView.findViewById(R.id.text); - timeView = (ShortTimeView) itemView.findViewById(R.id.time); - - setTextSize(adapter.getTextSize()); - itemView.setOnClickListener(this); - profileImage.setOnClickListener(this); - } - - @UiThread - public void displayMessage(Cursor cursor, boolean isUnread) { - final Context context = adapter.getContext(); - final MediaLoaderWrapper loader = adapter.getMediaLoader(); - final UserColorNameManager manager = adapter.getUserColorNameManager(); - - final UserKey accountKey = UserKey.valueOf(cursor.getString(ConversationEntries.IDX_ACCOUNT_KEY)); - final UserKey conversationId = UserKey.valueOf(cursor.getString(ConversationEntries.IDX_CONVERSATION_ID)); - final long timestamp = cursor.getLong(ConversationEntries.IDX_MESSAGE_TIMESTAMP); - final boolean isOutgoing = cursor.getInt(ConversationEntries.IDX_IS_OUTGOING) == 1; - - final String name = cursor.getString(ConversationEntries.IDX_NAME); - final String screenName = cursor.getString(ConversationEntries.IDX_SCREEN_NAME); - - nameView.setName(manager.getUserNickname(conversationId, name)); - nameView.setScreenName("@" + screenName); - nameView.updateText(adapter.getBidiFormatter()); - textView.setText(toPlainText(cursor.getString(ConversationEntries.IDX_TEXT_UNESCAPED))); - timeView.setTime(timestamp); - if (isOutgoing) { - timeView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_indicator_sent, 0); - } else { - timeView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); - } - nameView.setTypeface(null, isUnread && !isOutgoing ? Typeface.BOLD : Typeface.NORMAL); - textView.setTypeface(null, isUnread && !isOutgoing ? Typeface.BOLD : Typeface.NORMAL); - if (adapter.shouldShowAccountsColor()) { - // FIXME draw account color - } else { - content.drawEnd(); - } - content.drawStart(manager.getUserColor(conversationId)); - - final String profileImage = cursor.getString(ConversationEntries.IDX_PROFILE_IMAGE_URL); - loader.displayProfileImage(this.profileImage, profileImage); - } - - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.profileImage: { - adapter.onUserProfileClick(getLayoutPosition()); - break; - } - default: { - if (v == itemView) { - adapter.onMessageClick(getLayoutPosition()); - } - break; - } - } - } - - public void setTextSize(final float textSize) { - nameView.setPrimaryTextSize(textSize * 1.1f); - nameView.setSecondaryTextSize(textSize); - textView.setTextSize(textSize); - timeView.setTextSize(textSize * 0.85f); - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageViewHolder.java b/twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageViewHolder.java deleted file mode 100644 index b3b3bd1d3..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/view/holder/MessageViewHolder.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2014 Mariotaku Lee - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.mariotaku.twidere.view.holder; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.support.v7.widget.RecyclerView.ViewHolder; -import android.text.SpannableStringBuilder; -import android.view.View; -import android.widget.TextView; - -import org.mariotaku.messagebubbleview.library.MessageBubbleView; -import org.mariotaku.twidere.R; -import org.mariotaku.twidere.adapter.MessageConversationAdapter; -import org.mariotaku.twidere.model.ParcelableDirectMessageCursorIndices; -import org.mariotaku.twidere.model.ParcelableMedia; -import org.mariotaku.twidere.model.SpanItem; -import org.mariotaku.twidere.model.UserKey; -import org.mariotaku.twidere.model.util.ParcelableStatusUtils; -import org.mariotaku.twidere.util.JsonSerializer; -import org.mariotaku.twidere.util.MediaLoaderWrapper; -import org.mariotaku.twidere.util.ThemeUtils; -import org.mariotaku.twidere.util.TwidereColorUtils; -import org.mariotaku.twidere.util.TwidereLinkify; -import org.mariotaku.twidere.util.Utils; -import org.mariotaku.twidere.view.CardMediaContainer; - -public class MessageViewHolder extends ViewHolder { - - public final CardMediaContainer mediaContainer; - public final TextView textView, time; - - private final MessageBubbleView messageContent; - protected final MessageConversationAdapter adapter; - - private final int textColorPrimary, textColorPrimaryInverse, textColorSecondary, textColorSecondaryInverse; - - - public MessageViewHolder(final MessageConversationAdapter adapter, final View itemView) { - super(itemView); - this.adapter = adapter; - final Context context = itemView.getContext(); - final TypedArray a = context.obtainStyledAttributes(R.styleable.MessageViewHolder); - textColorPrimary = a.getColor(R.styleable.MessageViewHolder_android_textColorPrimary, 0); - textColorPrimaryInverse = a.getColor(R.styleable.MessageViewHolder_android_textColorPrimaryInverse, 0); - textColorSecondary = a.getColor(R.styleable.MessageViewHolder_android_textColorSecondary, 0); - textColorSecondaryInverse = a.getColor(R.styleable.MessageViewHolder_android_textColorSecondaryInverse, 0); - a.recycle(); - messageContent = (MessageBubbleView) itemView.findViewById(R.id.messageContent); - messageContent.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - itemView.getParent().showContextMenuForChild(itemView); - return true; - } - }); - messageContent.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - itemView.getParent().showContextMenuForChild(itemView); - } - }); - textView = (TextView) itemView.findViewById(R.id.text); - time = (TextView) itemView.findViewById(R.id.time); - mediaContainer = (CardMediaContainer) itemView.findViewById(R.id.media_preview_container); - mediaContainer.setStyle(adapter.getMediaPreviewStyle()); - } - - public void displayMessage(Cursor cursor, ParcelableDirectMessageCursorIndices indices) { - final Context context = adapter.getContext(); - final TwidereLinkify linkify = adapter.getLinkify(); - final MediaLoaderWrapper loader = adapter.getMediaLoader(); - - final UserKey accountKey = UserKey.valueOf(cursor.getString(indices.account_key)); - final long timestamp = cursor.getLong(indices.timestamp); - final ParcelableMedia[] media = JsonSerializer.parseArray(cursor.getString(indices.media), - ParcelableMedia.class); - final SpanItem[] spans = JsonSerializer.parseArray(cursor.getString(indices.spans), - SpanItem.class); - final SpannableStringBuilder text = SpannableStringBuilder.valueOf(cursor.getString(indices.text_unescaped)); - ParcelableStatusUtils.INSTANCE.applySpans(text, spans); - // Detect entity support - linkify.applyAllLinks(text, accountKey, false, true); - textView.setText(text); - time.setText(Utils.formatToLongTimeString(context, timestamp)); - mediaContainer.setVisibility(media != null && media.length > 0 ? View.VISIBLE : View.GONE); - mediaContainer.displayMedia(loader, media, accountKey, adapter.getOnMediaClickListener(), adapter.getMediaLoadingHandler(), getLayoutPosition(), true - ); - } - - public void setMessageColor(int color) { - final ColorStateList colorStateList = ColorStateList.valueOf(color); - messageContent.setBubbleColor(colorStateList); - final int textLuminancePrimary = TwidereColorUtils.getYIQLuminance(textColorPrimary); - final int textPrimaryDark, textPrimaryLight, textSecondaryDark, textSecondaryLight; - if (textLuminancePrimary < 128) { - textPrimaryDark = textColorPrimary; - textPrimaryLight = textColorPrimaryInverse; - textSecondaryDark = textColorSecondary; - textSecondaryLight = textColorSecondaryInverse; - } else { - textPrimaryDark = textColorPrimaryInverse; - textPrimaryLight = textColorPrimary; - textSecondaryDark = textColorSecondaryInverse; - textSecondaryLight = textColorSecondary; - } - final int textContrastPrimary = TwidereColorUtils.getContrastYIQ(color, - ThemeUtils.ACCENT_COLOR_THRESHOLD, textPrimaryDark, textPrimaryLight); - final int textContrastSecondary = TwidereColorUtils.getContrastYIQ(color, - ThemeUtils.ACCENT_COLOR_THRESHOLD, textSecondaryDark, textSecondaryLight); - textView.setTextColor(textContrastPrimary); - textView.setLinkTextColor(textContrastSecondary); - time.setTextColor(textContrastSecondary); - } - - public void setTextSize(final float textSize) { - textView.setTextSize(textSize); - time.setTextSize(textSize * 0.75f); - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/holder/UserListViewHolder.java b/twidere/src/main/java/org/mariotaku/twidere/view/holder/UserListViewHolder.java deleted file mode 100644 index c9f52e545..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/view/holder/UserListViewHolder.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2015 Mariotaku Lee - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.mariotaku.twidere.view.holder; - -import android.content.Context; -import android.support.v7.widget.RecyclerView.ViewHolder; -import android.text.TextUtils; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import org.mariotaku.twidere.R; -import org.mariotaku.twidere.adapter.iface.IUserListsAdapter; -import org.mariotaku.twidere.model.ParcelableUserList; -import org.mariotaku.twidere.util.MediaLoaderWrapper; -import org.mariotaku.twidere.util.UserColorNameManager; -import org.mariotaku.twidere.util.Utils; -import org.mariotaku.twidere.view.iface.IColorLabelView; - -import java.util.Locale; - -/** - * Created by mariotaku on 15/4/29. - */ -public class UserListViewHolder extends ViewHolder implements View.OnClickListener, View.OnLongClickListener { - - private final IUserListsAdapter adapter; - - private final IColorLabelView itemContent; - private final ImageView profileImageView; - private final TextView nameView; - private final TextView createdByView; - private final TextView descriptionView; - private final TextView membersCountView; - private final TextView subscribersCountView; - - private IUserListsAdapter.UserListClickListener userListClickListener; - - public UserListViewHolder(IUserListsAdapter adapter, View itemView) { - super(itemView); - itemContent = (IColorLabelView) itemView.findViewById(R.id.itemContent); - this.adapter = adapter; - profileImageView = (ImageView) itemView.findViewById(R.id.profileImage); - nameView = (TextView) itemView.findViewById(R.id.name); - createdByView = (TextView) itemView.findViewById(R.id.createdBy); - descriptionView = (TextView) itemView.findViewById(R.id.description); - membersCountView = (TextView) itemView.findViewById(R.id.membersCount); - subscribersCountView = (TextView) itemView.findViewById(R.id.subscribersCount); - } - - public void displayUserList(ParcelableUserList userList) { - - final Context context = itemView.getContext(); - final MediaLoaderWrapper loader = adapter.getMediaLoader(); - final UserColorNameManager manager = adapter.getUserColorNameManager(); - - itemContent.drawStart(manager.getUserColor(userList.user_key)); - nameView.setText(userList.name); - final boolean nameFirst = adapter.getNameFirst(); - final String createdByDisplayName = manager.getDisplayName(userList, nameFirst); - createdByView.setText(context.getString(R.string.created_by, createdByDisplayName)); - - if (adapter.getProfileImageEnabled()) { - profileImageView.setVisibility(View.VISIBLE); - loader.displayProfileImage(profileImageView, userList.user_profile_image_url); - } else { - profileImageView.setVisibility(View.GONE); - loader.cancelDisplayTask(profileImageView); - } - descriptionView.setVisibility(TextUtils.isEmpty(userList.description) ? View.GONE : View.VISIBLE); - descriptionView.setText(userList.description); - membersCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), userList.members_count)); - subscribersCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), userList.subscribers_count)); - } - - public void setOnClickListeners() { - setUserListClickListener(adapter.getUserListClickListener()); - } - - @Override - public void onClick(View v) { - if (userListClickListener == null) return; - switch (v.getId()) { - case R.id.itemContent: { - userListClickListener.onUserListClick(this, getLayoutPosition()); - break; - } - } - } - - @Override - public boolean onLongClick(View v) { - if (userListClickListener == null) return false; - switch (v.getId()) { - case R.id.itemContent: { - return userListClickListener.onUserListLongClick(this, getLayoutPosition()); - } - } - return false; - } - - public void setUserListClickListener(IUserListsAdapter.UserListClickListener listener) { - userListClickListener = listener; - ((View) itemContent).setOnClickListener(this); - ((View) itemContent).setOnLongClickListener(this); - } - - public void setupViewOptions() { - setTextSize(adapter.getTextSize()); - } - - public void setTextSize(final float textSize) { - nameView.setTextSize(textSize); - createdByView.setTextSize(textSize * 0.75f); - } - -} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt index a21b56000..6a911cd6e 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt @@ -624,6 +624,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener if (mediaMenuItem != null && mediaMenuItem.hasSubMenu()) { MenuUtils.addIntentToMenu(this, mediaMenuItem.subMenu, imageExtensionsIntent, MENU_GROUP_IMAGE_EXTENSION) } + updateViewStyle() setMenu() updateLocationState() notifyAccountSelectionChanged() @@ -633,6 +634,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener updateAttachedMediaView() } + private fun updateViewStyle() { + accountProfileImage.style = preferences[profileImageStyleKey] + } + override fun dispatchKeyEvent(event: KeyEvent): Boolean { val keyCode = event.keyCode if (KeyEvent.isModifierKey(keyCode)) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt index 536d6d7c1..da0250d7a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt @@ -19,35 +19,22 @@ package org.mariotaku.twidere.adapter +import android.annotation.SuppressLint import android.content.Context import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.list_item_simple_user.view.* import org.mariotaku.twidere.R -import org.mariotaku.twidere.TwidereConstants -import org.mariotaku.twidere.constant.SharedPreferenceConstants import org.mariotaku.twidere.model.AccountDetails import org.mariotaku.twidere.model.UserKey -import org.mariotaku.twidere.util.MediaLoaderWrapper -import org.mariotaku.twidere.util.dagger.GeneralComponentHelper -import javax.inject.Inject class AccountsSpinnerAdapter( context: Context, itemViewResource: Int = R.layout.list_item_simple_user -) : ArrayAdapter(context, itemViewResource) { +) : BaseArrayAdapter(context, itemViewResource) { - @Inject - lateinit var mediaLoader: MediaLoaderWrapper - private val displayProfileImage: Boolean private var dummyItemText: String? = null - init { - GeneralComponentHelper.build(context).inject(this) - displayProfileImage = context.getSharedPreferences(TwidereConstants.SHARED_PREFERENCES_NAME, - Context.MODE_PRIVATE).getBoolean(SharedPreferenceConstants.KEY_DISPLAY_PROFILE_IMAGE, true) - } - constructor(context: Context, accounts: Collection) : this(context) { addAll(accounts) } @@ -73,34 +60,26 @@ class AccountsSpinnerAdapter( val text2 = view.screenName val icon = view.profileImage if (!item.dummy) { - if (text1 != null) { - text1.visibility = View.VISIBLE - text1.text = item.user.name - } - if (text2 != null) { - text2.visibility = View.VISIBLE - text2.text = String.format("@%s", item.user.screen_name) - } + text1?.visibility = View.VISIBLE + text1?.text = item.user.name + text2?.visibility = View.VISIBLE + @SuppressLint("SetTextI18n") + text2?.text = "@${item.user.screen_name}" if (icon != null) { - icon.visibility = View.VISIBLE - if (displayProfileImage) { + if (profileImageEnabled) { + icon.visibility = View.VISIBLE + icon.style = profileImageStyle mediaLoader.displayProfileImage(icon, item.user) } else { + icon.visibility = View.GONE mediaLoader.cancelDisplayTask(icon) - // icon.setImageResource(R.drawable.ic_profile_image_default); } } } else { - if (text1 != null) { - text1.visibility = View.VISIBLE - text1.text = dummyItemText - } - if (text2 != null) { - text2.visibility = View.GONE - } - if (icon != null) { - icon.visibility = View.GONE - } + text1?.visibility = View.VISIBLE + text1?.text = dummyItemText + text2?.visibility = View.GONE + icon?.visibility = View.GONE } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/BaseArrayAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/BaseArrayAdapter.kt index 148c7bbdc..9d8d3969b 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/BaseArrayAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/BaseArrayAdapter.kt @@ -48,10 +48,10 @@ open class BaseArrayAdapter( @Inject lateinit var preferences: SharedPreferencesWrapper - override val profileImageStyle: Int - override val textSize: Float - override val profileImageEnabled: Boolean - override val isShowAbsoluteTime: Boolean + final override val profileImageStyle: Int + final override val textSize: Float + final override val profileImageEnabled: Boolean + final override val isShowAbsoluteTime: Boolean val nameFirst: Boolean init { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt new file mode 100644 index 000000000..34c85813b --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt @@ -0,0 +1,170 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.adapter + +import android.content.Context +import android.database.Cursor +import android.graphics.PorterDuff.Mode +import android.support.v4.widget.SimpleCursorAdapter +import android.text.TextUtils +import android.view.View +import android.widget.TextView +import org.apache.commons.lang3.StringUtils +import org.mariotaku.kpreferences.get +import org.mariotaku.twidere.R +import org.mariotaku.twidere.TwidereConstants.* +import org.mariotaku.twidere.constant.displayProfileImageKey +import org.mariotaku.twidere.constant.profileImageStyleKey +import org.mariotaku.twidere.model.UserKey +import org.mariotaku.twidere.provider.TwidereDataStore.Suggestions +import org.mariotaku.twidere.util.MediaLoaderWrapper +import org.mariotaku.twidere.util.SharedPreferencesWrapper +import org.mariotaku.twidere.util.UserColorNameManager +import org.mariotaku.twidere.util.dagger.GeneralComponentHelper +import org.mariotaku.twidere.view.ProfileImageView +import javax.inject.Inject + +class ComposeAutoCompleteAdapter(context: Context) : SimpleCursorAdapter(context, + R.layout.list_item_auto_complete, null, emptyArray(), intArrayOf(), 0) { + + @Inject + lateinit var mediaLoader: MediaLoaderWrapper + @Inject + lateinit var preferences: SharedPreferencesWrapper + @Inject + lateinit var userColorNameManager: UserColorNameManager + + private val displayProfileImage: Boolean + private val profileImageStyle: Int + + private var mTypeIdx: Int = 0 + private var mIconIdx: Int = 0 + private var mTitleIdx: Int = 0 + private var mSummaryIdx: Int = 0 + private var mExtraIdIdx: Int = 0 + private var mValueIdx: Int = 0 + var accountKey: UserKey? = null + private var mToken: Char = ' ' + + init { + GeneralComponentHelper.build(context).inject(this) + displayProfileImage = preferences[displayProfileImageKey] + profileImageStyle = preferences[profileImageStyleKey] + } + + override fun bindView(view: View, context: Context?, cursor: Cursor) { + val text1 = view.findViewById(android.R.id.text1) as TextView + val text2 = view.findViewById(android.R.id.text2) as TextView + val icon = view.findViewById(android.R.id.icon) as ProfileImageView + + icon.style = profileImageStyle + + if (Suggestions.AutoComplete.TYPE_USERS == cursor.getString(mTypeIdx)) { + text1.text = userColorNameManager.getUserNickname(cursor.getString(mExtraIdIdx), + cursor.getString(mTitleIdx)) + text2.text = String.format("@%s", cursor.getString(mSummaryIdx)) + if (displayProfileImage) { + val profileImageUrl = cursor.getString(mIconIdx) + mediaLoader.displayProfileImage(icon, profileImageUrl) + } else { + mediaLoader.cancelDisplayTask(icon) + } + + icon.clearColorFilter() + } else { + text1.text = String.format("#%s", cursor.getString(mTitleIdx)) + text2.setText(R.string.hashtag) + + icon.setImageResource(R.drawable.ic_action_hashtag) + icon.setColorFilter(text1.currentTextColor, Mode.SRC_ATOP) + } + icon.visibility = if (displayProfileImage) View.VISIBLE else View.GONE + super.bindView(view, context, cursor) + } + + fun closeCursor() { + val cursor = swapCursor(null) ?: return + if (!cursor.isClosed) { + cursor.close() + } + } + + override fun convertToString(cursor: Cursor?): CharSequence { + when (StringUtils.defaultIfEmpty(cursor!!.getString(mTypeIdx), "")) { + Suggestions.AutoComplete.TYPE_HASHTAGS -> { + return '#' + cursor.getString(mValueIdx) + } + Suggestions.AutoComplete.TYPE_USERS -> { + return '@' + cursor.getString(mValueIdx) + } + } + return cursor.getString(mValueIdx) + } + + override fun runQueryOnBackgroundThread(constraint: CharSequence): Cursor? { + if (TextUtils.isEmpty(constraint)) return null + val token = constraint[0] + if (getNormalizedSymbol(token) == getNormalizedSymbol(mToken)) { + val filter = filterQueryProvider + if (filter != null) return filter.runQuery(constraint) + } + mToken = token + val builder = Suggestions.AutoComplete.CONTENT_URI.buildUpon() + builder.appendQueryParameter(QUERY_PARAM_QUERY, constraint.subSequence(1, constraint.length).toString()) + when (getNormalizedSymbol(token)) { + '#' -> { + builder.appendQueryParameter(QUERY_PARAM_TYPE, Suggestions.AutoComplete.TYPE_HASHTAGS) + } + '@' -> { + builder.appendQueryParameter(QUERY_PARAM_TYPE, Suggestions.AutoComplete.TYPE_USERS) + } + else -> { + return null + } + } + builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, accountKey.toString()) + return mContext.contentResolver.query(builder.build(), Suggestions.AutoComplete.COLUMNS, + null, null, null) + } + + override fun swapCursor(cursor: Cursor?): Cursor? { + if (cursor != null) { + mTypeIdx = cursor.getColumnIndex(Suggestions.AutoComplete.TYPE) + mTitleIdx = cursor.getColumnIndex(Suggestions.AutoComplete.TITLE) + mSummaryIdx = cursor.getColumnIndex(Suggestions.AutoComplete.SUMMARY) + mExtraIdIdx = cursor.getColumnIndex(Suggestions.AutoComplete.EXTRA_ID) + mIconIdx = cursor.getColumnIndex(Suggestions.AutoComplete.ICON) + mValueIdx = cursor.getColumnIndex(Suggestions.AutoComplete.VALUE) + } + return super.swapCursor(cursor) + } + + companion object { + + private fun getNormalizedSymbol(character: Char): Char { + when (character) { + '\uff20', '@' -> return '@' + '\uff03', '#' -> return '#' + } + return '\u0000' + } + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt index 1e694bd02..da691c8da 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt @@ -200,10 +200,9 @@ class ParcelableActivitiesAdapter( } ITEM_VIEW_TYPE_TITLE_SUMMARY -> { val view = inflater.inflate(R.layout.card_item_activity_summary_compact, parent, false) - val holder = ActivityTitleSummaryViewHolder(this, - view) + val holder = ActivityTitleSummaryViewHolder(view, this) holder.setOnClickListeners() - holder.setTextSize(textSize) + holder.setupViewOptions() return holder } ITEM_VIEW_TYPE_GAP -> { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableGroupsAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableGroupsAdapter.kt index 6f5ff7dfd..e3d4def4a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableGroupsAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableGroupsAdapter.kt @@ -63,7 +63,7 @@ class ParcelableGroupsAdapter(context: Context) : LoadMoreSupportAdapter(context), IUserListsAdapter> { - override val showAccountsColor: Boolean - get() = false - override val nameFirst: Boolean + override val showAccountsColor: Boolean = false + override val nameFirst: Boolean = preferences[nameFirstKey] override var userListClickListener: IUserListsAdapter.UserListClickListener? = null private val inflater: LayoutInflater = LayoutInflater.from(context) private var data: List? = null - init { - nameFirst = preferences[nameFirstKey] - } - fun getData(): List? { return data } @@ -62,7 +56,7 @@ class ParcelableUserListsAdapter( } private fun bindUserList(holder: UserListViewHolder, position: Int) { - holder.displayUserList(getUserList(position)) + holder.displayUserList(getUserList(position)!!) } override fun getItemCount(): Int { @@ -131,9 +125,8 @@ class ParcelableUserListsAdapter( fun createUserListViewHolder(adapter: IUserListsAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): UserListViewHolder { - val view: View - view = inflater.inflate(R.layout.list_item_user_list, parent, false) - val holder = UserListViewHolder(adapter, view) + val view = inflater.inflate(R.layout.list_item_user_list, parent, false) + val holder = UserListViewHolder(view, adapter) holder.setOnClickListeners() holder.setupViewOptions() return holder diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/UserAutoCompleteAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/UserAutoCompleteAdapter.kt index f321a7dae..34be86dec 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/UserAutoCompleteAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/UserAutoCompleteAdapter.kt @@ -19,19 +19,22 @@ package org.mariotaku.twidere.adapter +import android.annotation.SuppressLint import android.content.Context import android.database.Cursor import android.net.Uri import android.support.v4.widget.SimpleCursorAdapter import android.text.TextUtils import android.view.View -import android.widget.ImageView import android.widget.TextView +import org.mariotaku.kpreferences.get import org.mariotaku.sqliteqb.library.Columns import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.sqliteqb.library.OrderBy import org.mariotaku.twidere.R -import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_DISPLAY_PROFILE_IMAGE +import org.mariotaku.twidere.constant.displayProfileImageKey +import org.mariotaku.twidere.constant.profileImageStyleKey +import org.mariotaku.twidere.model.ParcelableUserCursorIndices import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers import org.mariotaku.twidere.util.MediaLoaderWrapper @@ -39,49 +42,53 @@ import org.mariotaku.twidere.util.SharedPreferencesWrapper import org.mariotaku.twidere.util.UserColorNameManager import org.mariotaku.twidere.util.Utils import org.mariotaku.twidere.util.dagger.GeneralComponentHelper +import org.mariotaku.twidere.view.ProfileImageView import javax.inject.Inject -class UserAutoCompleteAdapter(context: Context) : SimpleCursorAdapter(context, R.layout.list_item_auto_complete, null, UserAutoCompleteAdapter.FROM, UserAutoCompleteAdapter.TO, 0) { +class UserAutoCompleteAdapter(val context: Context) : SimpleCursorAdapter(context, + R.layout.list_item_auto_complete, null, emptyArray(), + intArrayOf(), 0) { @Inject lateinit var profileImageLoader: MediaLoaderWrapper @Inject - lateinit var mPreferences: SharedPreferencesWrapper + lateinit var preferences: SharedPreferencesWrapper @Inject - lateinit var mUserColorNameManager: UserColorNameManager + lateinit var userColorNameManager: UserColorNameManager - private val mDisplayProfileImage: Boolean + private val displayProfileImage: Boolean + private var profileImageStyle: Int - private var mIdIdx: Int = 0 - private var mNameIdx: Int = 0 - private var mScreenNameIdx: Int = 0 - private var mProfileImageIdx: Int = 0 - private var mAccountKey: UserKey? = null + private var indices: ParcelableUserCursorIndices? = null + + private var accountKey: UserKey? = null init { GeneralComponentHelper.build(context).inject(this) - mDisplayProfileImage = mPreferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true) + displayProfileImage = preferences[displayProfileImageKey] + profileImageStyle = preferences[profileImageStyleKey] } override fun bindView(view: View, context: Context?, cursor: Cursor) { + val indices = this.indices!! val text1 = view.findViewById(android.R.id.text1) as TextView val text2 = view.findViewById(android.R.id.text2) as TextView - val icon = view.findViewById(android.R.id.icon) as ImageView + val icon = view.findViewById(android.R.id.icon) as ProfileImageView - // Clear images in order to prevent images in recycled view shown. - icon.setImageDrawable(null) + icon.style = profileImageStyle - text1.text = mUserColorNameManager.getUserNickname(cursor.getString(mIdIdx), cursor.getString(mNameIdx)) - text2.text = String.format("@%s", cursor.getString(mScreenNameIdx)) - if (mDisplayProfileImage) { - val profileImageUrl = cursor.getString(mProfileImageIdx) + text1.text = userColorNameManager.getUserNickname(cursor.getString(indices.key), cursor.getString(indices.name)) + @SuppressLint("SetTextI18n") + text2.text = "@${cursor.getString(indices.screen_name)}" + if (displayProfileImage) { + val profileImageUrl = cursor.getString(indices.profile_image_url) profileImageLoader.displayProfileImage(icon, profileImageUrl) } else { profileImageLoader.cancelDisplayTask(icon) } - icon.visibility = if (mDisplayProfileImage) View.VISIBLE else View.GONE + icon.visibility = if (displayProfileImage) View.VISIBLE else View.GONE super.bindView(view, context, cursor) } @@ -93,7 +100,7 @@ class UserAutoCompleteAdapter(context: Context) : SimpleCursorAdapter(context, R } override fun convertToString(cursor: Cursor?): CharSequence { - return cursor!!.getString(mScreenNameIdx) + return cursor!!.getString(indices!!.screen_name) } override fun runQueryOnBackgroundThread(constraint: CharSequence): Cursor? { @@ -102,7 +109,7 @@ class UserAutoCompleteAdapter(context: Context) : SimpleCursorAdapter(context, R if (filter != null) return filter.runQuery(constraint) val query = constraint.toString() val queryEscaped = query.replace("_", "^_") - val nicknameKeys = Utils.getMatchedNicknameKeys(query, mUserColorNameManager) + val nicknameKeys = Utils.getMatchedNicknameKeys(query, userColorNameManager) val usersSelection = Expression.or( Expression.likeRaw(Columns.Column(CachedUsers.SCREEN_NAME), "?||'%'", "^"), Expression.likeRaw(Columns.Column(CachedUsers.NAME), "?||'%'", "^"), @@ -111,31 +118,23 @@ class UserAutoCompleteAdapter(context: Context) : SimpleCursorAdapter(context, R val order = arrayOf(CachedUsers.LAST_SEEN, CachedUsers.SCORE, CachedUsers.SCREEN_NAME, CachedUsers.NAME) val ascending = booleanArrayOf(false, false, true, true) val orderBy = OrderBy(order, ascending) - val uri = Uri.withAppendedPath(CachedUsers.CONTENT_URI_WITH_SCORE, mAccountKey.toString()) - return mContext.contentResolver.query(uri, CachedUsers.COLUMNS, usersSelection.sql, + val uri = Uri.withAppendedPath(CachedUsers.CONTENT_URI_WITH_SCORE, accountKey.toString()) + @SuppressLint("Recycle") + val cursor = context.contentResolver.query(uri, CachedUsers.COLUMNS, usersSelection.sql, selectionArgs, orderBy.sql) + return cursor } fun setAccountKey(accountKey: UserKey) { - mAccountKey = accountKey + this.accountKey = accountKey } override fun swapCursor(cursor: Cursor?): Cursor? { if (cursor != null) { - mIdIdx = cursor.getColumnIndex(CachedUsers.USER_KEY) - mNameIdx = cursor.getColumnIndex(CachedUsers.NAME) - mScreenNameIdx = cursor.getColumnIndex(CachedUsers.SCREEN_NAME) - mProfileImageIdx = cursor.getColumnIndex(CachedUsers.PROFILE_IMAGE_URL) + indices = ParcelableUserCursorIndices(cursor) } return super.swapCursor(cursor) } - companion object { - - private val FROM = arrayOfNulls(0) - private val TO = IntArray(0) - } - - } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt index 51c4bd3bd..bece95d91 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt @@ -53,6 +53,7 @@ import android.view.View.OnClickListener import android.view.animation.DecelerateInterpolator import android.widget.ImageView import kotlinx.android.synthetic.main.header_drawer_account_selector.view.* +import org.mariotaku.kpreferences.get import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe import org.mariotaku.ktextension.convert import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe @@ -65,6 +66,7 @@ import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.CustomTabType import org.mariotaku.twidere.annotation.Referral import org.mariotaku.twidere.constant.KeyboardShortcutConstants.* +import org.mariotaku.twidere.constant.profileImageStyleKey import org.mariotaku.twidere.extension.model.setActivated import org.mariotaku.twidere.fragment.AccountsDashboardFragment.AccountsInfo import org.mariotaku.twidere.menu.AccountToggleProvider @@ -159,7 +161,7 @@ class AccountsDashboardFragment : BaseSupportFragment(), LoaderCallbacks? = null set(value) { @@ -619,9 +627,6 @@ class AccountsDashboardFragment : BaseSupportFragment(), LoaderCallbacks> { val fragmentArgs = arguments val accountKey = fragmentArgs.getParcelable(EXTRA_ACCOUNT_KEY) @@ -406,6 +405,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks>, data: SingleResponse) { val activity = activity ?: return @@ -746,7 +746,10 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks + private val profileImageViews: Array private val profileImageSpace: View private var mActivityEventListener: IActivitiesAdapter.ActivityEventListener? = null @@ -66,11 +69,11 @@ class ActivityTitleSummaryViewHolder(private val adapter: ParcelableActivitiesAd profileImagesContainer = itemView.findViewById(R.id.profile_images_container) as ViewGroup profileImageViews = arrayOf( - itemView.findViewById(R.id.activity_profile_image_0) as ImageView, - itemView.findViewById(R.id.activity_profile_image_1) as ImageView, - itemView.findViewById(R.id.activity_profile_image_2) as ImageView, - itemView.findViewById(R.id.activity_profile_image_3) as ImageView, - itemView.findViewById(R.id.activity_profile_image_4) as ImageView + itemView.findViewById(R.id.activity_profile_image_0) as ProfileImageView, + itemView.findViewById(R.id.activity_profile_image_1) as ProfileImageView, + itemView.findViewById(R.id.activity_profile_image_2) as ProfileImageView, + itemView.findViewById(R.id.activity_profile_image_3) as ProfileImageView, + itemView.findViewById(R.id.activity_profile_image_4) as ProfileImageView ) profileImageMoreNumber = itemView.findViewById(R.id.activity_profile_image_more_number) as BadgeView @@ -110,10 +113,15 @@ class ActivityTitleSummaryViewHolder(private val adapter: ParcelableActivitiesAd } - fun setTextSize(textSize: Float) { + fun setupViewOptions() { + val textSize = adapter.textSize titleView.textSize = textSize summaryView.textSize = textSize * 0.85f timeView.textSize = textSize * 0.80f + + profileImageViews.forEach { + it.style = adapter.profileImageStyle + } } private fun displayUserProfileImages(statuses: Array?) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/GroupViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/GroupViewHolder.kt new file mode 100644 index 000000000..0a0ba4db9 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/GroupViewHolder.kt @@ -0,0 +1,135 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.view.holder + +import android.support.v7.widget.RecyclerView.ViewHolder +import android.text.TextUtils +import android.view.View +import android.widget.TextView +import kotlinx.android.synthetic.main.card_item_group_compact.view.* +import org.mariotaku.twidere.R +import org.mariotaku.twidere.adapter.iface.IGroupsAdapter +import org.mariotaku.twidere.model.ParcelableGroup +import org.mariotaku.twidere.model.util.UserKeyUtils +import org.mariotaku.twidere.util.Utils +import org.mariotaku.twidere.view.ColorLabelRelativeLayout +import org.mariotaku.twidere.view.NameView +import org.mariotaku.twidere.view.ProfileImageView +import java.util.* + +/** + * Created by mariotaku on 15/4/29. + */ +class GroupViewHolder(private val adapter: IGroupsAdapter<*>, itemView: View) : ViewHolder(itemView), View.OnClickListener, View.OnLongClickListener { + + private val itemContent: ColorLabelRelativeLayout + private val profileImageView: ProfileImageView + private val nameView: NameView + private val externalIndicator: TextView + private val descriptionView: TextView + private val membersCountView: TextView + private val adminsCountView: TextView + + private var groupClickListener: IGroupsAdapter.GroupAdapterListener? = null + + init { + itemContent = itemView.itemContent + profileImageView = itemView.profileImage + nameView = itemView.name + externalIndicator = itemView.externalIndicator + descriptionView = itemView.description + membersCountView = itemView.membersCount + adminsCountView = itemView.adminsCount + } + + fun displayGroup(group: ParcelableGroup) { + val context = itemView.context + val loader = adapter.mediaLoader + val formatter = adapter.bidiFormatter + + nameView.setName(group.fullname) + nameView.setScreenName("!" + group.nickname) + + nameView.updateText(formatter) + val groupHost = UserKeyUtils.getUserHost(group.url, group.account_key.host) + if (UserKeyUtils.isSameHost(group.account_key.host, groupHost)) { + externalIndicator.visibility = View.GONE + } else { + externalIndicator.visibility = View.VISIBLE + externalIndicator.text = context.getString(R.string.external_group_host_format, + groupHost) + } + if (adapter.profileImageEnabled) { + profileImageView.visibility = View.VISIBLE + loader.displayProfileImage(profileImageView, group.homepage_logo) + } else { + profileImageView.visibility = View.GONE + loader.cancelDisplayTask(profileImageView) + } + descriptionView.visibility = if (TextUtils.isEmpty(group.description)) View.GONE else View.VISIBLE + descriptionView.text = formatter.unicodeWrap(group.description) + membersCountView.text = Utils.getLocalizedNumber(Locale.getDefault(), group.member_count) + adminsCountView.text = Utils.getLocalizedNumber(Locale.getDefault(), group.admin_count) + } + + fun setOnClickListeners() { + setGroupClickListener(adapter.groupAdapterListener) + } + + override fun onClick(v: View) { + val listener = groupClickListener ?: return + when (v.id) { + R.id.itemContent -> { + listener.onGroupClick(this, layoutPosition) + } + } + } + + override fun onLongClick(v: View): Boolean { + val listener = groupClickListener ?: return false + when (v.id) { + R.id.itemContent -> { + return listener.onGroupLongClick(this, layoutPosition) + } + } + return false + } + + fun setGroupClickListener(listener: IGroupsAdapter.GroupAdapterListener?) { + groupClickListener = listener + itemContent.setOnClickListener(this) + itemContent.setOnLongClickListener(this) + } + + fun setupViewOptions() { + profileImageView.style = adapter.profileImageStyle + setTextSize(adapter.textSize) + } + + fun setTextSize(textSize: Float) { + descriptionView.textSize = textSize + externalIndicator.textSize = textSize + nameView.setPrimaryTextSize(textSize) + nameView.setSecondaryTextSize(textSize * 0.75f) + membersCountView.textSize = textSize + adminsCountView.textSize = textSize + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.kt new file mode 100644 index 000000000..4c6f0f1df --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/IncomingMessageViewHolder.kt @@ -0,0 +1,56 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.view.holder + +import android.database.Cursor +import android.view.View +import org.mariotaku.twidere.R +import org.mariotaku.twidere.adapter.MessageConversationAdapter +import org.mariotaku.twidere.model.ParcelableDirectMessageCursorIndices +import org.mariotaku.twidere.view.ProfileImageView + +/** + * Created by mariotaku on 15/4/25. + */ +class IncomingMessageViewHolder( + adapter: MessageConversationAdapter, + itemView: View +) : MessageViewHolder(adapter, itemView) { + + private val profileImageView = itemView.findViewById(R.id.profileImage) as ProfileImageView + + init { + profileImageView.style = adapter.profileImageStyle + } + + override fun displayMessage(cursor: Cursor, indices: ParcelableDirectMessageCursorIndices) { + super.displayMessage(cursor, indices) + val wrapper = adapter.mediaLoader + if (adapter.profileImageEnabled) { + profileImageView.visibility = View.VISIBLE + wrapper.displayProfileImage(profileImageView, cursor.getString(indices.sender_profile_image_url)) + } else { + profileImageView.visibility = View.GONE + wrapper.cancelDisplayTask(profileImageView) + } + } + + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.kt new file mode 100644 index 000000000..d852edec4 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageEntryViewHolder.kt @@ -0,0 +1,115 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.view.holder + +import android.database.Cursor +import android.graphics.Typeface +import android.support.annotation.UiThread +import android.support.v7.widget.RecyclerView.ViewHolder +import android.view.View +import android.view.View.OnClickListener +import android.widget.TextView +import org.mariotaku.twidere.R +import org.mariotaku.twidere.adapter.MessageEntriesAdapter +import org.mariotaku.twidere.model.UserKey +import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries +import org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText +import org.mariotaku.twidere.view.NameView +import org.mariotaku.twidere.view.ProfileImageView +import org.mariotaku.twidere.view.ShortTimeView +import org.mariotaku.twidere.view.iface.IColorLabelView + +class MessageEntryViewHolder(private val adapter: MessageEntriesAdapter, itemView: View) : ViewHolder(itemView), OnClickListener { + + val profileImageView: ProfileImageView + val nameView: NameView + val textView: TextView + val timeView: ShortTimeView + private val content: IColorLabelView + + init { + content = itemView.findViewById(R.id.content) as IColorLabelView + profileImageView = itemView.findViewById(R.id.profileImage) as ProfileImageView + nameView = itemView.findViewById(R.id.name) as NameView + textView = itemView.findViewById(R.id.text) as TextView + timeView = itemView.findViewById(R.id.time) as ShortTimeView + + profileImageView.style = adapter.profileImageStyle + setTextSize(adapter.textSize) + itemView.setOnClickListener(this) + profileImageView.setOnClickListener(this) + } + + @UiThread + fun displayMessage(cursor: Cursor, isUnread: Boolean) { + val context = adapter.context + val loader = adapter.mediaLoader + val manager = adapter.userColorNameManager + + val accountKey = UserKey.valueOf(cursor.getString(ConversationEntries.IDX_ACCOUNT_KEY)) + val conversationId = UserKey.valueOf(cursor.getString(ConversationEntries.IDX_CONVERSATION_ID)) + val timestamp = cursor.getLong(ConversationEntries.IDX_MESSAGE_TIMESTAMP) + val isOutgoing = cursor.getInt(ConversationEntries.IDX_IS_OUTGOING) == 1 + + val name = cursor.getString(ConversationEntries.IDX_NAME) + val screenName = cursor.getString(ConversationEntries.IDX_SCREEN_NAME) + + nameView.setName(manager.getUserNickname(conversationId, name)) + nameView.setScreenName("@" + screenName) + nameView.updateText(adapter.bidiFormatter) + textView.text = toPlainText(cursor.getString(ConversationEntries.IDX_TEXT_UNESCAPED)) + timeView.setTime(timestamp) + if (isOutgoing) { + timeView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_indicator_sent, 0) + } else { + timeView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0) + } + nameView.setTypeface(null, if (isUnread && !isOutgoing) Typeface.BOLD else Typeface.NORMAL) + textView.setTypeface(null, if (isUnread && !isOutgoing) Typeface.BOLD else Typeface.NORMAL) + if (adapter.shouldShowAccountsColor()) { + // FIXME draw account color + } else { + content.drawEnd() + } + content.drawStart(manager.getUserColor(conversationId)) + + val profileImage = cursor.getString(ConversationEntries.IDX_PROFILE_IMAGE_URL) + loader.displayProfileImage(this.profileImageView, profileImage) + } + + override fun onClick(v: View) { + when (v) { + profileImageView -> { + adapter.onUserProfileClick(layoutPosition) + } + itemView -> { + adapter.onMessageClick(layoutPosition) + } + } + } + + fun setTextSize(textSize: Float) { + nameView.setPrimaryTextSize(textSize * 1.1f) + nameView.setSecondaryTextSize(textSize) + textView.textSize = textSize + timeView.textSize = textSize * 0.85f + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageViewHolder.kt new file mode 100644 index 000000000..a4c5113fc --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MessageViewHolder.kt @@ -0,0 +1,134 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.view.holder + +import android.content.res.ColorStateList +import android.database.Cursor +import android.support.v7.widget.RecyclerView.ViewHolder +import android.text.SpannableStringBuilder +import android.view.View +import android.widget.TextView +import org.mariotaku.messagebubbleview.library.MessageBubbleView +import org.mariotaku.twidere.R +import org.mariotaku.twidere.adapter.MessageConversationAdapter +import org.mariotaku.twidere.model.ParcelableDirectMessageCursorIndices +import org.mariotaku.twidere.model.ParcelableMedia +import org.mariotaku.twidere.model.SpanItem +import org.mariotaku.twidere.model.UserKey +import org.mariotaku.twidere.model.util.ParcelableStatusUtils +import org.mariotaku.twidere.util.JsonSerializer +import org.mariotaku.twidere.util.ThemeUtils +import org.mariotaku.twidere.util.TwidereColorUtils +import org.mariotaku.twidere.util.Utils +import org.mariotaku.twidere.view.CardMediaContainer + +open class MessageViewHolder( + protected val adapter: MessageConversationAdapter, + itemView: View +) : ViewHolder(itemView) { + + val mediaContainer: CardMediaContainer + val textView: TextView + val time: TextView + + private val messageContent: MessageBubbleView + + private val textColorPrimary: Int + private val textColorPrimaryInverse: Int + private val textColorSecondary: Int + private val textColorSecondaryInverse: Int + + + init { + val context = itemView.context + val a = context.obtainStyledAttributes(R.styleable.MessageViewHolder) + textColorPrimary = a.getColor(R.styleable.MessageViewHolder_android_textColorPrimary, 0) + textColorPrimaryInverse = a.getColor(R.styleable.MessageViewHolder_android_textColorPrimaryInverse, 0) + textColorSecondary = a.getColor(R.styleable.MessageViewHolder_android_textColorSecondary, 0) + textColorSecondaryInverse = a.getColor(R.styleable.MessageViewHolder_android_textColorSecondaryInverse, 0) + a.recycle() + messageContent = itemView.findViewById(R.id.messageContent) as MessageBubbleView + messageContent.setOnLongClickListener { + itemView.parent.showContextMenuForChild(itemView) + true + } + messageContent.setOnClickListener { itemView.parent.showContextMenuForChild(itemView) } + textView = itemView.findViewById(R.id.text) as TextView + time = itemView.findViewById(R.id.time) as TextView + mediaContainer = itemView.findViewById(R.id.media_preview_container) as CardMediaContainer + mediaContainer.setStyle(adapter.mediaPreviewStyle) + } + + open fun displayMessage(cursor: Cursor, indices: ParcelableDirectMessageCursorIndices) { + val context = adapter.context + val linkify = adapter.linkify + val loader = adapter.mediaLoader + + val accountKey = UserKey.valueOf(cursor.getString(indices.account_key)) + val timestamp = cursor.getLong(indices.timestamp) + val media = JsonSerializer.parseArray(cursor.getString(indices.media), + ParcelableMedia::class.java) + val spans = JsonSerializer.parseArray(cursor.getString(indices.spans), + SpanItem::class.java) + val text = SpannableStringBuilder.valueOf(cursor.getString(indices.text_unescaped)) + ParcelableStatusUtils.applySpans(text, spans) + // Detect entity support + linkify.applyAllLinks(text, accountKey, false, true) + textView.text = text + time.text = Utils.formatToLongTimeString(context, timestamp) + mediaContainer.visibility = if (media != null && media.isNotEmpty()) View.VISIBLE else View.GONE + mediaContainer.displayMedia(loader, media, accountKey, adapter.onMediaClickListener, adapter.mediaLoadingHandler, layoutPosition.toLong(), true + ) + } + + fun setMessageColor(color: Int) { + val colorStateList = ColorStateList.valueOf(color) + messageContent.bubbleColor = colorStateList + val textLuminancePrimary = TwidereColorUtils.getYIQLuminance(textColorPrimary) + val textPrimaryDark: Int + val textPrimaryLight: Int + val textSecondaryDark: Int + val textSecondaryLight: Int + if (textLuminancePrimary < 128) { + textPrimaryDark = textColorPrimary + textPrimaryLight = textColorPrimaryInverse + textSecondaryDark = textColorSecondary + textSecondaryLight = textColorSecondaryInverse + } else { + textPrimaryDark = textColorPrimaryInverse + textPrimaryLight = textColorPrimary + textSecondaryDark = textColorSecondaryInverse + textSecondaryLight = textColorSecondary + } + val textContrastPrimary = TwidereColorUtils.getContrastYIQ(color, + ThemeUtils.ACCENT_COLOR_THRESHOLD, textPrimaryDark, textPrimaryLight) + val textContrastSecondary = TwidereColorUtils.getContrastYIQ(color, + ThemeUtils.ACCENT_COLOR_THRESHOLD, textSecondaryDark, textSecondaryLight) + textView.setTextColor(textContrastPrimary) + textView.setLinkTextColor(textContrastSecondary) + time.setTextColor(textContrastSecondary) + } + + fun setTextSize(textSize: Float) { + textView.textSize = textSize + time.textSize = textSize * 0.75f + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt index 8b129da54..78a170d66 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt @@ -24,6 +24,7 @@ import org.mariotaku.twidere.model.util.ParcelableStatusUtils import org.mariotaku.twidere.util.* import org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText import org.mariotaku.twidere.util.Utils.getUserTypeIconRes +import org.mariotaku.twidere.view.ProfileImageView import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder import java.lang.ref.WeakReference @@ -35,7 +36,7 @@ import java.lang.ref.WeakReference */ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View) : ViewHolder(itemView), Constants, IStatusViewHolder { - override val profileImageView: ImageView by lazy { itemView.profileImage } + override val profileImageView: ProfileImageView by lazy { itemView.profileImage } override val profileTypeView: ImageView by lazy { itemView.profileType } private val itemContent by lazy { itemView.itemContent } @@ -460,6 +461,8 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View) fun setupViewOptions() { setTextSize(adapter.textSize) + profileImageView.style = adapter.profileImageStyle + mediaPreview.setStyle(adapter.mediaPreviewStyle) quotedMediaPreview.setStyle(adapter.mediaPreviewStyle) // profileImageView.setStyle(adapter.getProfileImageStyle()); diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserListViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserListViewHolder.kt new file mode 100644 index 000000000..7c7a23690 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserListViewHolder.kt @@ -0,0 +1,126 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.view.holder + +import android.support.v7.widget.RecyclerView.ViewHolder +import android.text.TextUtils +import android.view.View +import android.widget.TextView +import kotlinx.android.synthetic.main.list_item_user_list.view.* +import org.mariotaku.twidere.R +import org.mariotaku.twidere.adapter.iface.IUserListsAdapter +import org.mariotaku.twidere.model.ParcelableUserList +import org.mariotaku.twidere.util.Utils +import org.mariotaku.twidere.view.ColorLabelRelativeLayout +import org.mariotaku.twidere.view.ProfileImageView +import java.util.* + +/** + * Created by mariotaku on 15/4/29. + */ +class UserListViewHolder( + itemView: View, + private val adapter: IUserListsAdapter<*> +) : ViewHolder(itemView), View.OnClickListener, View.OnLongClickListener { + + private val itemContent: ColorLabelRelativeLayout + private val profileImageView: ProfileImageView + private val nameView: TextView + private val createdByView: TextView + private val descriptionView: TextView + private val membersCountView: TextView + private val subscribersCountView: TextView + + private var userListClickListener: IUserListsAdapter.UserListClickListener? = null + + init { + itemContent = itemView.itemContent + profileImageView = itemView.profileImage + nameView = itemView.name + createdByView = itemView.createdBy + descriptionView = itemView.description + membersCountView = itemView.membersCount + subscribersCountView = itemView.subscribersCount + } + + fun displayUserList(userList: ParcelableUserList) { + val context = itemView.context + val loader = adapter.mediaLoader + val manager = adapter.userColorNameManager + + itemContent.drawStart(manager.getUserColor(userList.user_key)) + nameView.text = userList.name + val nameFirst = adapter.nameFirst + val createdByDisplayName = manager.getDisplayName(userList, nameFirst) + createdByView.text = context.getString(R.string.created_by, createdByDisplayName) + + if (adapter.profileImageEnabled) { + profileImageView.visibility = View.VISIBLE + loader.displayProfileImage(profileImageView, userList.user_profile_image_url) + } else { + profileImageView.visibility = View.GONE + loader.cancelDisplayTask(profileImageView) + } + descriptionView.visibility = if (TextUtils.isEmpty(userList.description)) View.GONE else View.VISIBLE + descriptionView.text = userList.description + membersCountView.text = Utils.getLocalizedNumber(Locale.getDefault(), userList.members_count) + subscribersCountView.text = Utils.getLocalizedNumber(Locale.getDefault(), userList.subscribers_count) + } + + fun setOnClickListeners() { + setUserListClickListener(adapter.userListClickListener) + } + + override fun onClick(v: View) { + val listener = userListClickListener ?: return + when (v.id) { + R.id.itemContent -> { + listener.onUserListClick(this, layoutPosition) + } + } + } + + override fun onLongClick(v: View): Boolean { + val listener = userListClickListener ?: return false + when (v.id) { + R.id.itemContent -> { + return listener.onUserListLongClick(this, layoutPosition) + } + } + return false + } + + fun setUserListClickListener(listener: IUserListsAdapter.UserListClickListener?) { + userListClickListener = listener + itemContent.setOnClickListener(this) + itemContent.setOnLongClickListener(this) + } + + fun setupViewOptions() { + profileImageView.style = adapter.profileImageStyle + setTextSize(adapter.textSize) + } + + fun setTextSize(textSize: Float) { + nameView.textSize = textSize + createdByView.textSize = textSize * 0.75f + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt index f4ca84dfd..134f99bb7 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt @@ -34,6 +34,7 @@ import org.mariotaku.twidere.model.util.UserKeyUtils import org.mariotaku.twidere.util.Utils import org.mariotaku.twidere.util.Utils.getUserTypeIconRes import org.mariotaku.twidere.view.NameView +import org.mariotaku.twidere.view.ProfileImageView import org.mariotaku.twidere.view.iface.IColorLabelView import java.util.* @@ -44,7 +45,7 @@ class UserViewHolder( ) : ViewHolder(itemView), OnClickListener, OnLongClickListener { private val itemContent: IColorLabelView - val profileImageView: ImageView + val profileImageView: ProfileImageView val profileTypeView: ImageView private val nameView: NameView private val externalIndicator: TextView @@ -270,6 +271,7 @@ class UserViewHolder( } fun setupViewOptions() { + profileImageView.style = adapter.profileImageStyle setTextSize(adapter.textSize) } diff --git a/twidere/src/main/res/layout/list_item_auto_complete.xml b/twidere/src/main/res/layout/list_item_auto_complete.xml index 4e3e6b34e..afcd6b03b 100644 --- a/twidere/src/main/res/layout/list_item_auto_complete.xml +++ b/twidere/src/main/res/layout/list_item_auto_complete.xml @@ -17,7 +17,8 @@ ~ along with this program. If not, see . --> - + android:scaleType="fitCenter"/> + android:maxLines="1" + android:textAppearance="?android:attr/textAppearanceMedium"/> + android:maxLines="1" + android:textAppearance="?android:attr/textAppearanceSmall"/> \ No newline at end of file diff --git a/twidere/src/main/res/layout/list_item_message_entry.xml b/twidere/src/main/res/layout/list_item_message_entry.xml index f9749b1e0..4b3186c2b 100644 --- a/twidere/src/main/res/layout/list_item_message_entry.xml +++ b/twidere/src/main/res/layout/list_item_message_entry.xml @@ -33,7 +33,7 @@ app:ignorePadding="true" tools:context=".adapter.MessageEntriesAdapter"> - + tools:text="12:00"/> + tools:text="@string/sample_status_text"/> \ No newline at end of file