1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-17 04:00:48 +01:00

started to re-implement twitter activity feature

This commit is contained in:
Mariotaku Lee 2015-01-03 23:16:50 +08:00
parent 5c355a1b12
commit efd8ec1c27
74 changed files with 3330 additions and 1122 deletions

View File

@ -7,8 +7,8 @@ android {
defaultConfig {
applicationId "org.mariotaku.twidere"
minSdkVersion 14
targetSdkVersion 19
versionCode 98
targetSdkVersion 21
versionCode 99
versionName "0.3.0-dev"
}

View File

@ -0,0 +1,46 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.support.v4.app.Fragment;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity;
/**
* Created by mariotaku on 15/1/1.
*/
public final class TwitterCardFragmentFactoryImpl extends TwitterCardFragmentFactory {
@Override
public Fragment createAnimatedGifFragment(ParcelableCardEntity card) {
return null;
}
@Override
public Fragment createAudioFragment(ParcelableCardEntity card) {
return null;
}
@Override
public Fragment createPlayerFragment(ParcelableCardEntity card) {
return null;
}
}

View File

@ -0,0 +1,85 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.net.Uri;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.OnInitializedListener;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import com.google.android.youtube.player.YouTubePlayerSupportFragment;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity.ParcelableValueItem;
/**
* Created by mariotaku on 15/1/1.
*/
public final class TwitterCardFragmentFactoryImpl extends TwitterCardFragmentFactory {
private static final String YOUTUBE_DATA_API_KEY = "AIzaSyCVdCIMFFxdNqHnCPrJ9yKUzoTfs8jhYGc";
@Override
public Fragment createAnimatedGifFragment(ParcelableCardEntity card) {
return null;
}
@Override
public Fragment createAudioFragment(ParcelableCardEntity card) {
return null;
}
@Override
public Fragment createPlayerFragment(ParcelableCardEntity card) {
// final ParcelableValueItem app_url_resolved = ParcelableCardEntity.getValue(card, "app_url_resolved");
// if (app_url_resolved != null) {
// final Uri uri = Uri.parse((String) app_url_resolved.value);
// final String paramV = uri.getQueryParameter("v");
// if ("www.youtube.com".equals(uri.getHost()) && paramV != null) {
// final YouTubePlayerSupportFragment fragment = YouTubePlayerSupportFragment.newInstance();
// fragment.initialize(YOUTUBE_DATA_API_KEY, new OnInitializedListener() {
// @Override
// public void onInitializationSuccess(Provider provider, YouTubePlayer player, boolean wasRestored) {
// if (!wasRestored) {
// player.cueVideo(paramV);
// }
// }
//
// @Override
// public void onInitializationFailure(Provider provider, YouTubeInitializationResult errorReason) {
// final FragmentActivity activity = fragment.getActivity();
// if (activity == null) return;
//// if (errorReason.isUserRecoverableError()) {
//// errorReason.getErrorDialog(activity, RECOVERY_DIALOG_REQUEST).show();
//// } else {
//// Toast.makeText(activity, errorReason.toString(), Toast.LENGTH_LONG).show();
//// }
// }
// });
// return fragment;
// }
// }
return null;
}
}

View File

@ -105,6 +105,7 @@ import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereValidator;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.accessor.ViewAccessor;
import org.mariotaku.twidere.util.menu.TwidereMenuInfo;
@ -137,7 +138,7 @@ import static org.mariotaku.twidere.util.Utils.getAccountIds;
import static org.mariotaku.twidere.util.Utils.getAccountName;
import static org.mariotaku.twidere.util.Utils.getAccountScreenName;
import static org.mariotaku.twidere.util.Utils.getDefaultTextSize;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.Utils.getImageUploadStatus;
import static org.mariotaku.twidere.util.Utils.getQuoteStatus;
import static org.mariotaku.twidere.util.Utils.getShareStatus;
@ -932,12 +933,12 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
final String action = intent.getAction();
if (INTENT_ACTION_REPLY.equals(action)) {
if (mInReplyToStatus == null) return false;
final String display_name = getDisplayName(this, mInReplyToStatus.user_id, mInReplyToStatus.user_name,
final String display_name = UserColorNameUtils.getDisplayName(this, mInReplyToStatus.user_id, mInReplyToStatus.user_name,
mInReplyToStatus.user_screen_name);
setTitle(getString(R.string.reply_to, display_name));
} else if (INTENT_ACTION_QUOTE.equals(action)) {
if (mInReplyToStatus == null) return false;
final String display_name = getDisplayName(this, mInReplyToStatus.user_id, mInReplyToStatus.user_name,
final String display_name = UserColorNameUtils.getDisplayName(this, mInReplyToStatus.user_id, mInReplyToStatus.user_name,
mInReplyToStatus.user_screen_name);
setTitle(getString(R.string.quote_user, display_name));
mSubtitleView.setVisibility(mInReplyToStatus.user_is_protected
@ -947,7 +948,7 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
setTitle(R.string.edit_draft);
} else if (INTENT_ACTION_MENTION.equals(action)) {
if (mMentionUser == null) return false;
final String display_name = getDisplayName(this, mMentionUser.id, mMentionUser.name,
final String display_name = UserColorNameUtils.getDisplayName(this, mMentionUser.id, mMentionUser.name,
mMentionUser.screen_name);
setTitle(getString(R.string.mention_user, display_name));
} else if (INTENT_ACTION_REPLY_MULTIPLE.equals(action)) {

View File

@ -67,7 +67,7 @@ import static org.mariotaku.twidere.util.CustomTabUtils.findTabIconKey;
import static org.mariotaku.twidere.util.CustomTabUtils.getIconMap;
import static org.mariotaku.twidere.util.CustomTabUtils.getTabConfiguration;
import static org.mariotaku.twidere.util.CustomTabUtils.getTabTypeName;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
public class CustomTabEditorActivity extends BaseSupportDialogActivity implements OnClickListener {

View File

@ -0,0 +1,243 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IActivitiesAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.ActivityTitleSummaryViewHolder;
import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
/**
* Created by mariotaku on 15/1/3.
*/
public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> implements Constants,
IActivitiesAdapter<Data> {
private static final int ITEM_VIEW_TYPE_STUB = 0;
private static final int ITEM_VIEW_TYPE_GAP = 1;
private static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 2;
private static final int ITEM_VIEW_TYPE_TITLE_SUMMARY = 3;
private static final int ITEM_VIEW_TYPE_STATUS = 4;
private final Context mContext;
private final LayoutInflater mInflater;
private final ImageLoaderWrapper mImageLoader;
private final ImageLoadingHandler mLoadingHandler;
private final AsyncTwitterWrapper mTwitterWrapper;
private final int mCardBackgroundColor;
private final int mTextSize;
private final int mProfileImageStyle, mMediaPreviewStyle;
private boolean mLoadMoreIndicatorEnabled;
protected AbsActivitiesAdapter(Context context) {
mContext = context;
final TwidereApplication app = TwidereApplication.getInstance(context);
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context);
mInflater = LayoutInflater.from(context);
mImageLoader = app.getImageLoaderWrapper();
mLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
mTwitterWrapper = app.getTwitterWrapper();
final SharedPreferencesWrapper preferences = SharedPreferencesWrapper.getInstance(context,
SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mTextSize = preferences.getInt(KEY_TEXT_SIZE, context.getResources().getInteger(R.integer.default_text_size));
mProfileImageStyle = Utils.getProfileImageStyle(preferences.getString(KEY_PROFILE_IMAGE_STYLE, null));
mMediaPreviewStyle = Utils.getMediaPreviewStyle(preferences.getString(KEY_MEDIA_PREVIEW_STYLE, null));
}
public abstract ParcelableActivity getActivity(int position);
public abstract int getActivityCount();
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
}
public abstract Data getData();
public abstract void setData(Data data);
@Override
public ImageLoaderWrapper getImageLoader() {
return mImageLoader;
}
@Override
public Context getContext() {
return mContext;
}
@Override
public ImageLoadingHandler getImageLoadingHandler() {
return mLoadingHandler;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;
}
@Override
public int getMediaPreviewStyle() {
return mMediaPreviewStyle;
}
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return mTwitterWrapper;
}
@Override
public float getTextSize() {
return mTextSize;
}
public boolean hasLoadMoreIndicator() {
return mLoadMoreIndicatorEnabled;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ITEM_VIEW_TYPE_STATUS: {
final View view = mInflater.inflate(R.layout.card_item_status_compat, parent, false);
final StatusViewHolder holder = new StatusViewHolder(view);
holder.setTextSize(getTextSize());
return holder;
}
case ITEM_VIEW_TYPE_TITLE_SUMMARY: {
final View view = mInflater.inflate(R.layout.list_item_activity_about_me_status, parent, false);
final ActivityTitleSummaryViewHolder holder = new ActivityTitleSummaryViewHolder(this, view);
holder.setTextSize(getTextSize());
return holder;
}
case ITEM_VIEW_TYPE_GAP: {
final View view = mInflater.inflate(R.layout.card_item_gap, parent, false);
return new GapViewHolder(this, view);
}
default: {
final View view = mInflater.inflate(R.layout.list_item_two_line, parent, false);
return new StubViewHolder(view);
}
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case ITEM_VIEW_TYPE_STATUS: {
final ParcelableActivity activity = getActivity(position);
final ParcelableStatus status;
if (activity.action == ParcelableActivity.ACTION_MENTION) {
status = activity.target_object_statuses[0];
} else {
status = activity.target_statuses[0];
}
final StatusViewHolder statusViewHolder = (StatusViewHolder) holder;
statusViewHolder.displayStatus(getContext(), getImageLoader(),
getImageLoadingHandler(), getTwitterWrapper(),
getProfileImageStyle(), getMediaPreviewStyle(), status, null);
break;
}
case ITEM_VIEW_TYPE_TITLE_SUMMARY: {
((ActivityTitleSummaryViewHolder) holder).displayActivity(getActivity(position));
break;
}
case ITEM_VIEW_TYPE_STUB: {
((StubViewHolder) holder).displayActivity(getActivity(position));
break;
}
}
}
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return ITEM_VIEW_TYPE_LOAD_INDICATOR;
} else if (isGapItem(position)) {
return ITEM_VIEW_TYPE_GAP;
}
switch (getActivityAction(position)) {
case ParcelableActivity.ACTION_MENTION:
case ParcelableActivity.ACTION_REPLY: {
return ITEM_VIEW_TYPE_STATUS;
}
case ParcelableActivity.ACTION_FOLLOW:
case ParcelableActivity.ACTION_FAVORITE:
case ParcelableActivity.ACTION_RETWEET: {
return ITEM_VIEW_TYPE_TITLE_SUMMARY;
}
}
return ITEM_VIEW_TYPE_STUB;
}
public final int getItemCount() {
return getActivityCount() + (mLoadMoreIndicatorEnabled ? 1 : 0);
}
public void setLoadMoreIndicatorEnabled(boolean enabled) {
if (mLoadMoreIndicatorEnabled == enabled) return;
mLoadMoreIndicatorEnabled = enabled;
notifyDataSetChanged();
}
protected abstract int getActivityAction(int position);
private static class StubViewHolder extends ViewHolder {
private final TextView text1, text2;
public StubViewHolder(View itemView) {
super(itemView);
text1 = (TextView) itemView.findViewById(android.R.id.text1);
text2 = (TextView) itemView.findViewById(android.R.id.text2);
}
public void displayActivity(ParcelableActivity activity) {
text1.setText(String.valueOf(activity.action));
text2.setText(activity.toString());
}
}
}

View File

@ -49,11 +49,6 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
private boolean mLoadMoreIndicatorEnabled;
private StatusAdapterListener mStatusAdapterListener;
@Override
public int getMediaPreviewStyle() {
return mMediaPreviewStyle;
}
public AbsStatusesAdapter(Context context, boolean compact) {
mContext = context;
final TwidereApplication app = TwidereApplication.getInstance(context);
@ -74,23 +69,31 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
mMediaPreviewStyle = Utils.getMediaPreviewStyle(preferences.getString(KEY_MEDIA_PREVIEW_STYLE, null));
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;
}
public abstract D getData();
public abstract void setData(D data);
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return mTwitterWrapper;
public void onUserProfileClick(StatusViewHolder holder, int position) {
final Context context = getContext();
final ParcelableStatus status = getStatus(position);
final View profileImageView = holder.getProfileImageView();
final View profileTypeView = holder.getProfileTypeView();
if (context instanceof FragmentActivity) {
final Bundle options = Utils.makeSceneTransitionOption((FragmentActivity) context,
new Pair<>(profileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE),
new Pair<>(profileTypeView, UserFragment.TRANSITION_NAME_PROFILE_TYPE));
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, options);
} else {
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, null);
}
}
@Override
public float getTextSize() {
return mTextSize;
public final void onStatusClick(StatusViewHolder holder, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onStatusClick(holder, position);
}
}
@Override
@ -109,26 +112,23 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
}
@Override
public final void onStatusClick(StatusViewHolder holder, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onStatusClick(holder, position);
}
public int getProfileImageStyle() {
return mProfileImageStyle;
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
final Context context = getContext();
final ParcelableStatus status = getStatus(position);
final View profileImageView = holder.getProfileImageView();
final View profileTypeView = holder.getProfileTypeView();
if (context instanceof FragmentActivity) {
final Bundle options = Utils.makeSceneTransitionOption((FragmentActivity) context,
new Pair<>(profileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE),
new Pair<>(profileTypeView, UserFragment.TRANSITION_NAME_PROFILE_TYPE));
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, options);
} else {
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, null);
}
public int getMediaPreviewStyle() {
return mMediaPreviewStyle;
}
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return mTwitterWrapper;
}
@Override
public float getTextSize() {
return mTextSize;
}
public boolean hasLoadMoreIndicator() {

View File

@ -32,13 +32,14 @@ import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.view.holder.ActivityListViewHolder;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.Utils.isCompactCards;
public abstract class BaseParcelableActivitiesAdapter extends BaseArrayAdapter<ParcelableActivity> implements
@ -94,9 +95,9 @@ public abstract class BaseParcelableActivitiesAdapter extends BaseArrayAdapter<P
holder.setAccountColor(getAccountColor(getContext(), item.account_id));
}
if (mShowAbsoluteTime) {
holder.time.setTime(item.activity_timestamp);
holder.time.setTime(item.timestamp);
} else {
holder.time.setTime(item.activity_timestamp);
holder.time.setTime(item.timestamp);
}
bindView(position, holder, item);
return view;
@ -157,13 +158,13 @@ public abstract class BaseParcelableActivitiesAdapter extends BaseArrayAdapter<P
protected String getName(final ParcelableStatus status) {
if (status == null) return null;
return getDisplayName(getContext(), status.user_id, status.user_name, status.user_screen_name,
return UserColorNameUtils.getDisplayName(getContext(), status.user_id, status.user_name, status.user_screen_name,
isDisplayNameFirst(), isNicknameOnly());
}
protected String getName(final ParcelableUser user) {
if (user == null) return null;
return getDisplayName(getContext(), user.id, user.name, user.screen_name, isDisplayNameFirst(),
return UserColorNameUtils.getDisplayName(getContext(), user.id, user.name, user.screen_name, isDisplayNameFirst(),
isNicknameOnly());
}

View File

@ -42,8 +42,8 @@ import static org.mariotaku.twidere.provider.TweetStore.DirectMessages.Conversat
import static org.mariotaku.twidere.provider.TweetStore.DirectMessages.ConversationEntries.IDX_SCREEN_NAME;
import static org.mariotaku.twidere.provider.TweetStore.DirectMessages.ConversationEntries.IDX_TEXT;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.openUserProfile;

View File

@ -34,10 +34,9 @@ import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.DirectMessageConversationViewHolder;
import java.util.Locale;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.findDirectMessageInDatabases;
import static org.mariotaku.twidere.util.Utils.formatToLongTimeString;
@ -152,7 +151,20 @@ public class DirectMessagesConversationAdapter extends BaseCursorAdapter impleme
@Override
public void setImagePreviewScaleType(final String scaleTypeString) {
final ScaleType scaleType = ScaleType.valueOf(scaleTypeString.toUpperCase(Locale.US));
final ScaleType scaleType;
switch (Utils.getMediaPreviewStyle(scaleTypeString)) {
case VALUE_MEDIA_PREVIEW_STYLE_CODE_CROP: {
scaleType = ScaleType.CENTER_CROP;
break;
}
case VALUE_MEDIA_PREVIEW_STYLE_CODE_SCALE: {
scaleType = ScaleType.CENTER_INSIDE;
break;
}
default: {
return;
}
}
mImagePreviewScaleType = scaleType;
}

View File

@ -1,18 +1,18 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
@ -20,273 +20,12 @@
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.text.Html;
import android.text.TextUtils;
import android.view.View;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableLocation;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.view.holder.ActivityListViewHolder;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.getCardHighlightColor;
public class ParcelableActivitiesAboutMeAdapter extends BaseParcelableActivitiesAdapter {
private final ImageLoadingHandler mImageLoadingHandler;
private boolean mGapDisallowed;
private boolean mIndicateMyStatusDisabled;
private boolean mFavoritesHighlightDisabled;
private boolean mDisplayImagePreview;
private boolean mDisplaySensitiveContents;
public ParcelableActivitiesAboutMeAdapter(final Context context, final boolean compactCards) {
super(context, compactCards);
mImageLoadingHandler = new ImageLoadingHandler();
/**
* Created by mariotaku on 15/1/3.
*/
public class ParcelableActivitiesAboutMeAdapter extends ParcelableActivitiesAdapter {
protected ParcelableActivitiesAboutMeAdapter(Context context) {
super(context);
}
@Override
public void bindView(final int position, final ActivityListViewHolder holder, final ParcelableActivity item) {
if (item == null) return;
final ParcelableUser[] sources = item.sources;
if (sources == null || sources.length == 0) return;
final ParcelableStatus[] targetStatuses = item.target_statuses;
final int action = item.action;
final boolean displayProfileImage = shouldDisplayProfileImage();
final TwidereLinkify linkify = getLinkify();
final int highlightOption = getLinkHighlightOption();
final Context context = getContext();
final ParcelableUser firstSource = sources[0];
final ParcelableStatus[] targetObjects = item.target_object_statuses;
final String sourceName = getName(firstSource);
switch (action) {
case ParcelableActivity.ACTION_FAVORITE: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.VISIBLE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.activity_profile_images_container.setVisibility(displayProfileImage ? View.VISIBLE : View.GONE);
holder.name.setSingleLine(false);
if (targetStatuses != null && targetStatuses.length > 0) {
final ParcelableStatus status = targetStatuses[0];
if (highlightOption != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
holder.text.setText(Html.fromHtml(status.text_html));
linkify.applyAllLinks(holder.text, status.account_id, status.is_possibly_sensitive);
holder.text.setMovementMethod(null);
} else {
holder.text.setText(status.text_unescaped);
}
}
if (sources.length == 1) {
holder.name.setText(context.getString(R.string.activity_about_me_favorite, sourceName));
} else {
holder.name.setText(context.getString(R.string.activity_about_me_favorite_multi, sourceName,
sources.length - 1));
}
displayActivityUserProfileImages(holder, sources);
break;
}
case ParcelableActivity.ACTION_FOLLOW: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.GONE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.name.setSingleLine(false);
if (sources.length == 1) {
holder.name.setText(context.getString(R.string.activity_about_me_follow, sourceName));
} else {
holder.name.setText(context.getString(R.string.activity_about_me_follow_multi, sourceName,
sources.length - 1));
}
displayActivityUserProfileImages(holder, sources);
break;
}
case ParcelableActivity.ACTION_MENTION: {
if (targetObjects != null && targetObjects.length > 0) {
final ParcelableStatus status = targetObjects[0];
displayStatus(status, holder, position);
}
break;
}
case ParcelableActivity.ACTION_REPLY: {
if (targetStatuses != null && targetStatuses.length > 0) {
final ParcelableStatus status = targetStatuses[0];
displayStatus(status, holder, position);
}
break;
}
case ParcelableActivity.ACTION_RETWEET: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.VISIBLE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.name.setSingleLine(false);
if (targetObjects != null && targetObjects.length > 0) {
final ParcelableStatus status = targetObjects[0];
if (highlightOption != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
holder.text.setText(Html.fromHtml(status.text_html));
linkify.applyAllLinks(holder.text, status.account_id, status.is_possibly_sensitive);
holder.text.setMovementMethod(null);
} else {
holder.text.setText(status.text_unescaped);
}
}
if (sources.length == 1) {
holder.name.setText(context.getString(R.string.activity_about_me_retweet, sourceName));
} else {
holder.name.setText(context.getString(R.string.activity_about_me_retweet_multi, sourceName,
sources.length - 1));
}
holder.activity_profile_images_container.setVisibility(View.VISIBLE);
displayActivityUserProfileImages(holder, sources);
break;
}
case ParcelableActivity.ACTION_LIST_MEMBER_ADDED: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.GONE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.name.setSingleLine(false);
if (sources.length == 1) {
if (item.target_object_user_lists != null && item.target_object_user_lists.length > 0) {
final ParcelableUserList list = item.target_object_user_lists[0];
holder.name.setText(context.getString(R.string.activity_about_me_list_member_added_with_name,
sourceName, list.name));
} else {
holder.name
.setText(context.getString(R.string.activity_about_me_list_member_added, sourceName));
}
} else {
holder.name.setText(context.getString(R.string.activity_about_me_list_member_added_multi,
sourceName, sources.length - 1));
}
displayActivityUserProfileImages(holder, sources);
break;
}
}
}
private void displayStatus(final ParcelableStatus status, final ActivityListViewHolder holder, final int position) {
final boolean showGap = status.is_gap && !mGapDisallowed && position != getCount() - 1;
final boolean displayProfileImage = isDisplayProfileImage();
final Context context = getContext();
holder.setShowAsGap(showGap);
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.VISIBLE);
holder.text.setVisibility(View.VISIBLE);
holder.profile_image.setVisibility(displayProfileImage ? View.VISIBLE : View.GONE);
holder.activity_profile_images_container.setVisibility(View.GONE);
holder.name.setSingleLine(true);
holder.text.setSingleLine(false);
if (!showGap) {
final TwidereLinkify linkify = getLinkify();
final int highlightOption = getLinkHighlightOption();
final boolean showAccountColor = isShowAccountColor();
// Clear images in prder to prevent images in recycled view shown.
holder.profile_image.setImageDrawable(null);
holder.my_profile_image.setImageDrawable(null);
holder.image_preview.setImageDrawable(null);
holder.setAccountColorEnabled(showAccountColor);
if (highlightOption != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
holder.text.setText(Html.fromHtml(status.text_html));
linkify.applyAllLinks(holder.text, status.account_id, status.is_possibly_sensitive);
holder.text.setMovementMethod(null);
} else {
holder.text.setText(status.text_unescaped);
}
if (showAccountColor) {
holder.setAccountColor(getAccountColor(context, status.account_id));
}
final boolean isMyStatus = status.account_id == status.user_id;
final boolean hasMedia = status.first_media != null;
holder.setUserColor(getUserColor(context, status.user_id));
holder.setHighlightColor(getCardHighlightColor(context.getResources(), false,
!mFavoritesHighlightDisabled && status.is_favorite, status.is_retweet));
holder.setTextSize(getTextSize());
holder.setIsMyStatus(isMyStatus && !mIndicateMyStatusDisabled);
holder.setUserType(status.user_is_verified, status.user_is_protected);
holder.setDisplayNameFirst(isDisplayNameFirst());
holder.setNicknameOnly(isNicknameOnly());
final String nick = getUserNickname(context, status.user_id);
holder.name.setText(TextUtils.isEmpty(nick) ? status.user_name : isNicknameOnly() ? nick : context
.getString(R.string.name_with_nickname, status.user_name, nick));
holder.screen_name.setText("@" + status.user_screen_name);
holder.time.setTime(status.timestamp);
holder.setStatusType(!mFavoritesHighlightDisabled && status.is_favorite,
ParcelableLocation.isValidLocation(status.location), hasMedia, status.is_possibly_sensitive);
holder.setIsReplyRetweet(status.in_reply_to_status_id > 0, status.is_retweet);
if (status.is_retweet) {
holder.setRetweetedBy(status.retweet_count, status.retweeted_by_id, status.retweeted_by_name,
status.retweeted_by_screen_name);
} else if (status.in_reply_to_status_id > 0) {
holder.setReplyTo(status.in_reply_to_user_id, status.in_reply_to_name, status.in_reply_to_screen_name);
}
if (displayProfileImage) {
setProfileImage(holder.my_profile_image, status);
setProfileImage(holder.profile_image, status);
holder.profile_image.setTag(position);
holder.my_profile_image.setTag(position);
} else {
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
}
final boolean hasPreview = mDisplayImagePreview && hasMedia;
holder.image_preview_container.setVisibility(hasPreview ? View.VISIBLE : View.GONE);
if (hasPreview) {
if (status.is_possibly_sensitive && !mDisplaySensitiveContents) {
holder.image_preview.setImageDrawable(null);
holder.image_preview.setBackgroundResource(R.drawable.image_preview_nsfw);
holder.image_preview_progress.setVisibility(View.GONE);
} else if (!status.first_media.equals(mImageLoadingHandler.getLoadingUri(holder.image_preview))) {
holder.image_preview.setBackgroundResource(0);
final ImageLoaderWrapper imageLoader = getImageLoader();
imageLoader.displayPreviewImage(holder.image_preview, status.first_media, mImageLoadingHandler);
}
holder.image_preview.setTag(position);
}
// holder.item_menu.setTag(position);
}
}
}

View File

@ -0,0 +1,292 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.text.Html;
import android.text.TextUtils;
import android.view.View;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableLocation;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.view.holder.ActivityListViewHolder;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.getCardHighlightColor;
public class ParcelableActivitiesAboutMeListAdapter extends BaseParcelableActivitiesAdapter {
private final ImageLoadingHandler mImageLoadingHandler;
private boolean mGapDisallowed;
private boolean mIndicateMyStatusDisabled;
private boolean mFavoritesHighlightDisabled;
private boolean mDisplayImagePreview;
private boolean mDisplaySensitiveContents;
public ParcelableActivitiesAboutMeListAdapter(final Context context, final boolean compactCards) {
super(context, compactCards);
mImageLoadingHandler = new ImageLoadingHandler();
}
@Override
public void bindView(final int position, final ActivityListViewHolder holder, final ParcelableActivity item) {
if (item == null) return;
final ParcelableUser[] sources = item.sources;
if (sources == null || sources.length == 0) return;
final ParcelableStatus[] targetStatuses = item.target_statuses;
final int action = item.action;
final boolean displayProfileImage = shouldDisplayProfileImage();
final TwidereLinkify linkify = getLinkify();
final int highlightOption = getLinkHighlightOption();
final Context context = getContext();
final ParcelableUser firstSource = sources[0];
final ParcelableStatus[] targetObjects = item.target_object_statuses;
final String sourceName = getName(firstSource);
switch (action) {
case ParcelableActivity.ACTION_FAVORITE: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.VISIBLE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.activity_profile_images_container.setVisibility(displayProfileImage ? View.VISIBLE : View.GONE);
holder.name.setSingleLine(false);
if (targetStatuses != null && targetStatuses.length > 0) {
final ParcelableStatus status = targetStatuses[0];
if (highlightOption != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
holder.text.setText(Html.fromHtml(status.text_html));
linkify.applyAllLinks(holder.text, status.account_id, status.is_possibly_sensitive);
holder.text.setMovementMethod(null);
} else {
holder.text.setText(status.text_unescaped);
}
}
if (sources.length == 1) {
holder.name.setText(context.getString(R.string.activity_about_me_favorite, sourceName));
} else {
holder.name.setText(context.getString(R.string.activity_about_me_favorite_multi, sourceName,
sources.length - 1));
}
displayActivityUserProfileImages(holder, sources);
break;
}
case ParcelableActivity.ACTION_FOLLOW: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.GONE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.name.setSingleLine(false);
if (sources.length == 1) {
holder.name.setText(context.getString(R.string.activity_about_me_follow, sourceName));
} else {
holder.name.setText(context.getString(R.string.activity_about_me_follow_multi, sourceName,
sources.length - 1));
}
displayActivityUserProfileImages(holder, sources);
break;
}
case ParcelableActivity.ACTION_MENTION: {
if (targetObjects != null && targetObjects.length > 0) {
final ParcelableStatus status = targetObjects[0];
displayStatus(status, holder, position);
}
break;
}
case ParcelableActivity.ACTION_REPLY: {
if (targetStatuses != null && targetStatuses.length > 0) {
final ParcelableStatus status = targetStatuses[0];
displayStatus(status, holder, position);
}
break;
}
case ParcelableActivity.ACTION_RETWEET: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.VISIBLE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.name.setSingleLine(false);
if (targetObjects != null && targetObjects.length > 0) {
final ParcelableStatus status = targetObjects[0];
if (highlightOption != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
holder.text.setText(Html.fromHtml(status.text_html));
linkify.applyAllLinks(holder.text, status.account_id, status.is_possibly_sensitive);
holder.text.setMovementMethod(null);
} else {
holder.text.setText(status.text_unescaped);
}
}
if (sources.length == 1) {
holder.name.setText(context.getString(R.string.activity_about_me_retweet, sourceName));
} else {
holder.name.setText(context.getString(R.string.activity_about_me_retweet_multi, sourceName,
sources.length - 1));
}
holder.activity_profile_images_container.setVisibility(View.VISIBLE);
displayActivityUserProfileImages(holder, sources);
break;
}
case ParcelableActivity.ACTION_LIST_MEMBER_ADDED: {
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.GONE);
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
holder.text.setVisibility(View.GONE);
holder.reply_retweet_status.setVisibility(View.GONE);
holder.name.setSingleLine(false);
if (sources.length == 1) {
if (item.target_object_user_lists != null && item.target_object_user_lists.length > 0) {
final ParcelableUserList list = item.target_object_user_lists[0];
holder.name.setText(context.getString(R.string.activity_about_me_list_member_added_with_name,
sourceName, list.name));
} else {
holder.name
.setText(context.getString(R.string.activity_about_me_list_member_added, sourceName));
}
} else {
holder.name.setText(context.getString(R.string.activity_about_me_list_member_added_multi,
sourceName, sources.length - 1));
}
displayActivityUserProfileImages(holder, sources);
break;
}
}
}
private void displayStatus(final ParcelableStatus status, final ActivityListViewHolder holder, final int position) {
final boolean showGap = status.is_gap && !mGapDisallowed && position != getCount() - 1;
final boolean displayProfileImage = isDisplayProfileImage();
final Context context = getContext();
holder.setShowAsGap(showGap);
holder.name.setVisibility(View.VISIBLE);
holder.screen_name.setVisibility(View.VISIBLE);
holder.text.setVisibility(View.VISIBLE);
holder.profile_image.setVisibility(displayProfileImage ? View.VISIBLE : View.GONE);
holder.activity_profile_images_container.setVisibility(View.GONE);
holder.name.setSingleLine(true);
holder.text.setSingleLine(false);
if (!showGap) {
final TwidereLinkify linkify = getLinkify();
final int highlightOption = getLinkHighlightOption();
final boolean showAccountColor = isShowAccountColor();
// Clear images in prder to prevent images in recycled view shown.
holder.profile_image.setImageDrawable(null);
holder.my_profile_image.setImageDrawable(null);
holder.image_preview.setImageDrawable(null);
holder.setAccountColorEnabled(showAccountColor);
if (highlightOption != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
holder.text.setText(Html.fromHtml(status.text_html));
linkify.applyAllLinks(holder.text, status.account_id, status.is_possibly_sensitive);
holder.text.setMovementMethod(null);
} else {
holder.text.setText(status.text_unescaped);
}
if (showAccountColor) {
holder.setAccountColor(getAccountColor(context, status.account_id));
}
final boolean isMyStatus = status.account_id == status.user_id;
final boolean hasMedia = status.first_media != null;
holder.setUserColor(getUserColor(context, status.user_id));
holder.setHighlightColor(getCardHighlightColor(context.getResources(), false,
!mFavoritesHighlightDisabled && status.is_favorite, status.is_retweet));
holder.setTextSize(getTextSize());
holder.setIsMyStatus(isMyStatus && !mIndicateMyStatusDisabled);
holder.setUserType(status.user_is_verified, status.user_is_protected);
holder.setDisplayNameFirst(isDisplayNameFirst());
holder.setNicknameOnly(isNicknameOnly());
final String nick = getUserNickname(context, status.user_id);
holder.name.setText(TextUtils.isEmpty(nick) ? status.user_name : isNicknameOnly() ? nick : context
.getString(R.string.name_with_nickname, status.user_name, nick));
holder.screen_name.setText("@" + status.user_screen_name);
holder.time.setTime(status.timestamp);
holder.setStatusType(!mFavoritesHighlightDisabled && status.is_favorite,
ParcelableLocation.isValidLocation(status.location), hasMedia, status.is_possibly_sensitive);
holder.setIsReplyRetweet(status.in_reply_to_status_id > 0, status.is_retweet);
if (status.is_retweet) {
holder.setRetweetedBy(status.retweet_count, status.retweeted_by_id, status.retweeted_by_name,
status.retweeted_by_screen_name);
} else if (status.in_reply_to_status_id > 0) {
holder.setReplyTo(status.in_reply_to_user_id, status.in_reply_to_name, status.in_reply_to_screen_name);
}
if (displayProfileImage) {
setProfileImage(holder.my_profile_image, status);
setProfileImage(holder.profile_image, status);
holder.profile_image.setTag(position);
holder.my_profile_image.setTag(position);
} else {
holder.profile_image.setVisibility(View.GONE);
holder.my_profile_image.setVisibility(View.GONE);
}
final boolean hasPreview = mDisplayImagePreview && hasMedia;
holder.image_preview_container.setVisibility(hasPreview ? View.VISIBLE : View.GONE);
if (hasPreview) {
if (status.is_possibly_sensitive && !mDisplaySensitiveContents) {
holder.image_preview.setImageDrawable(null);
holder.image_preview.setBackgroundResource(R.drawable.image_preview_nsfw);
holder.image_preview_progress.setVisibility(View.GONE);
} else if (!status.first_media.equals(mImageLoadingHandler.getLoadingUri(holder.image_preview))) {
holder.image_preview.setBackgroundResource(0);
final ImageLoaderWrapper imageLoader = getImageLoader();
imageLoader.displayPreviewImage(holder.image_preview, status.first_media, mImageLoadingHandler);
}
holder.image_preview.setTag(position);
}
// holder.item_menu.setTag(position);
}
}
}

View File

@ -0,0 +1,90 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView.ViewHolder;
import org.mariotaku.twidere.model.ParcelableActivity;
import java.util.List;
/**
* Created by mariotaku on 15/1/3.
*/
public class ParcelableActivitiesAdapter extends AbsActivitiesAdapter<List<ParcelableActivity>> {
private List<ParcelableActivity> mData;
public ParcelableActivitiesAdapter(Context context) {
super(context);
}
@Override
public boolean isGapItem(int position) {
return false;
}
@Override
public void onGapClick(ViewHolder holder, int position) {
}
@Override
protected int getActivityAction(int position) {
return mData.get(position).action;
}
@Override
public ParcelableActivity getActivity(int position) {
if (hasLoadMoreIndicator() && position == getItemCount() - 1) return null;
return mData.get(position);
}
@Override
public void onItemActionClick(ViewHolder holder, int id, int position) {
}
@Override
public int getActivityCount() {
if (mData == null) return 0;
return mData.size();
}
@Override
public void onItemMenuClick(ViewHolder holder, int position) {
}
public void setData(List<ParcelableActivity> data) {
mData = data;
notifyDataSetChanged();
}
@Override
public List<ParcelableActivity> getData() {
return mData;
}
}

View File

@ -32,6 +32,7 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.UserListListViewHolder;
@ -39,7 +40,7 @@ import java.util.List;
import java.util.Locale;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.Utils.getLocalizedNumber;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
@ -91,7 +92,7 @@ public class ParcelableUserListsAdapter extends BaseArrayAdapter<ParcelableUserL
holder.position = position;
final ParcelableUserList user_list = getItem(position);
final String display_name = getDisplayName(mContext, user_list.user_id, user_list.user_name,
final String display_name = UserColorNameUtils.getDisplayName(mContext, user_list.user_id, user_list.user_name,
user_list.user_screen_name, isDisplayNameFirst(), isNicknameOnly(), false);
holder.setTextSize(getTextSize());
holder.name.setText(user_list.name);

View File

@ -36,8 +36,8 @@ import org.mariotaku.twidere.view.holder.UserListViewHolder;
import java.util.List;
import java.util.Locale;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.getLocalizedNumber;

View File

@ -28,12 +28,13 @@ import org.mariotaku.twidere.adapter.iface.IBaseAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.view.holder.TwoLineWithIconViewHolder;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.configBaseAdapter;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
public class SimpleParcelableUserListsAdapter extends BaseArrayAdapter<ParcelableUserList> implements IBaseAdapter {
@ -73,7 +74,7 @@ public class SimpleParcelableUserListsAdapter extends BaseArrayAdapter<Parcelabl
holder.icon.setImageDrawable(null);
final ParcelableUserList user_list = getItem(position);
final String display_name = getDisplayName(mContext, user_list.user_id, user_list.user_name,
final String display_name = UserColorNameUtils.getDisplayName(mContext, user_list.user_id, user_list.user_name,
user_list.user_screen_name, isDisplayNameFirst(), isNicknameOnly(), false);
holder.text1.setText(user_list.name);
holder.text2.setText(mContext.getString(R.string.created_by, display_name));

View File

@ -33,7 +33,7 @@ import org.mariotaku.twidere.view.holder.TwoLineWithIconViewHolder;
import java.util.List;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
import static org.mariotaku.twidere.util.Utils.configBaseAdapter;
import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;

View File

@ -46,7 +46,7 @@ import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.Utils;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
public class UserHashtagAutoCompleteAdapter extends SimpleCursorAdapter implements Constants {

View File

@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.State;
import android.view.View;
@ -108,6 +109,11 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
final Adapter adapter = parent.getAdapter();
if (adapter != null && parent.getChildPosition(view) == adapter.getItemCount() - 1) {
outRect.setEmpty();
return;
}
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {

View File

@ -0,0 +1,41 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter.iface;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
/**
* Created by mariotaku on 14/11/18.
*/
public interface IActivitiesAdapter<Data> extends IContentCardAdapter {
ParcelableActivity getActivity(int position);
int getActivityCount();
void onStatusClick(StatusViewHolder holder, int position);
void onUserProfileClick(StatusViewHolder holder, int position);
void setData(Data data);
}

View File

@ -0,0 +1,47 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter.iface;
import android.content.Context;
import android.support.v7.widget.RecyclerView.ViewHolder;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
/**
* Created by mariotaku on 15/1/3.
*/
public interface IContentCardAdapter extends IGapSupportedAdapter, ICardSupportedAdapter {
ImageLoaderWrapper getImageLoader();
Context getContext();
ImageLoadingHandler getImageLoadingHandler();
int getProfileImageStyle();
int getMediaPreviewStyle();
AsyncTwitterWrapper getTwitterWrapper();
float getTextSize();
}

View File

@ -1,39 +1,20 @@
package org.mariotaku.twidere.adapter.iface;
import android.content.Context;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
/**
* Created by mariotaku on 14/11/18.
*/
public interface IStatusesAdapter<Data> extends IGapSupportedAdapter, ICardSupportedAdapter {
ImageLoaderWrapper getImageLoader();
Context getContext();
ImageLoadingHandler getImageLoadingHandler();
public interface IStatusesAdapter<Data> extends IContentCardAdapter {
ParcelableStatus getStatus(int position);
int getStatusCount();
int getProfileImageStyle();
int getMediaPreviewStyle();
void onStatusClick(StatusViewHolder holder, int position);
void setData(Data data);
void onUserProfileClick(StatusViewHolder holder, int position);
void setData(Data data);
AsyncTwitterWrapper getTwitterWrapper();
float getTextSize();
void onStatusClick(StatusViewHolder holder, int position);
}

View File

@ -63,7 +63,7 @@ import java.io.File;
import edu.ucdavis.earlybird.UCDService;
import twitter4j.http.HostAddressResolver;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.initUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.initUserColor;
import static org.mariotaku.twidere.util.Utils.getBestCacheDir;
import static org.mariotaku.twidere.util.Utils.getInternalCacheDir;
import static org.mariotaku.twidere.util.Utils.initAccountColor;

View File

@ -19,7 +19,7 @@
package org.mariotaku.twidere.fragment;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import android.app.Activity;
import android.content.Intent;
@ -40,6 +40,7 @@ import android.widget.Switch;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.util.UserColorNameUtils;
public abstract class BaseAccountPreferenceFragment extends PreferenceFragment implements Constants,
OnCheckedChangeListener, OnSharedPreferenceChangeListener {
@ -59,7 +60,7 @@ public abstract class BaseAccountPreferenceFragment extends PreferenceFragment i
final Activity activity = getActivity();
final Intent intent = activity.getIntent();
if (account != null && intent.hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
final String name = getDisplayName(getActivity(), account.account_id, account.name, account.screen_name);
final String name = UserColorNameUtils.getDisplayName(getActivity(), account.account_id, account.name, account.screen_name);
activity.setTitle(name);
}
updatePreferenceScreen();

View File

@ -50,8 +50,9 @@ import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.support.BaseSupportListFragment;
import org.mariotaku.twidere.provider.TweetStore.Filters;
import org.mariotaku.twidere.util.UserColorNameUtils;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
public abstract class BaseFiltersFragment extends BaseSupportListFragment implements LoaderManager.LoaderCallbacks<Cursor>,
MultiChoiceModeListener {
@ -281,7 +282,7 @@ public abstract class BaseFiltersFragment extends BaseSupportListFragment implem
final long user_id = cursor.getLong(mUserIdIdx);
final String name = cursor.getString(mNameIdx);
final String screen_name = cursor.getString(mScreenNameIdx);
final String display_name = getDisplayName(context, user_id, name, screen_name, mNameFirst,
final String display_name = UserColorNameUtils.getDisplayName(context, user_id, name, screen_name, mNameFirst,
mNicknameOnly);
text1.setText(display_name);
}

View File

@ -0,0 +1,278 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.squareup.otto.Bus;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.AbsActivitiesAdapter;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.util.AccelerateSmoothScroller;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
/**
* Created by mariotaku on 14/11/5.
*/
public abstract class AbsActivitiesFragment<Data> extends BaseSupportFragment implements LoaderCallbacks<Data>,
OnRefreshListener, DrawerCallback, RefreshScrollTopInterface {
private final Object mStatusesBusCallback;
protected AbsActivitiesFragment() {
mStatusesBusCallback = createMessageBusCallback();
}
private View mContentView;
private SharedPreferences mPreferences;
private View mProgressContainer;
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private AbsActivitiesAdapter<Data> mAdapter;
private SimpleDrawerCallback mDrawerCallback;
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (isRefreshing()) return;
if (mAdapter.hasLoadMoreIndicator()
&& layoutManager.findLastVisibleItemPosition() == mAdapter.getItemCount() - 1) {
onLoadMoreStatuses();
}
}
};
@Override
public boolean canScroll(float dy) {
return mDrawerCallback.canScroll(dy);
}
@Override
public void cancelTouch() {
mDrawerCallback.cancelTouch();
}
@Override
public void fling(float velocity) {
mDrawerCallback.fling(velocity);
}
@Override
public boolean isScrollContent(float x, float y) {
return mDrawerCallback.isScrollContent(x, y);
}
@Override
public void scrollBy(float dy) {
mDrawerCallback.scrollBy(dy);
}
@Override
public boolean shouldLayoutHeaderBottom() {
return mDrawerCallback.shouldLayoutHeaderBottom();
}
@Override
public void topChanged(int offset) {
mDrawerCallback.topChanged(offset);
}
public AbsActivitiesAdapter<Data> getAdapter() {
return mAdapter;
}
public SharedPreferences getSharedPreferences() {
if (mPreferences != null) return mPreferences;
return mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
public abstract int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds);
public boolean isRefreshing() {
return mSwipeRefreshLayout.isRefreshing();
}
public void setRefreshing(boolean refreshing) {
mSwipeRefreshLayout.setRefreshing(refreshing);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recycler_view, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final View view = getView();
if (view == null) throw new AssertionError();
final Context context = view.getContext();
final boolean compact = Utils.isCompactCards(context);
mDrawerCallback = new SimpleDrawerCallback(mRecyclerView);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeColors(ThemeUtils.getUserAccentColor(context));
mAdapter = onCreateAdapter(context, compact);
mAdapter.setLoadMoreIndicatorEnabled(true);
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.addItemDecoration(new DividerItemDecoration(context, layoutManager.getOrientation()));
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setOnScrollListener(mOnScrollListener);
getLoaderManager().initLoader(0, getArguments(), this);
setListShown(false);
}
@Override
public void onStart() {
super.onStart();
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
bus.register(mStatusesBusCallback);
}
@Override
public void onStop() {
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
bus.unregister(mStatusesBusCallback);
super.onStop();
}
@Override
public void onLoadFinished(Loader<Data> loader, Data data) {
setRefreshing(false);
mAdapter.setData(data);
setListShown(true);
}
@Override
public void onLoaderReset(Loader<Data> loader) {
}
@Override
public void onRefresh() {
triggerRefresh();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
mContentView = view.findViewById(R.id.fragment_content);
mProgressContainer = view.findViewById(R.id.progress_container);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_layout);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
super.onViewCreated(view, savedInstanceState);
}
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
mContentView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
}
@Override
public boolean scrollToStart() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
final int tabPosition = getTabPosition();
if (twitter != null && tabPosition != -1) {
twitter.clearUnreadCountAsync(tabPosition);
}
// mRecyclerView.smoothScrollToPosition(0);
final LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
final AccelerateSmoothScroller smoothScroller = new AccelerateSmoothScroller(getActivity(), 2) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
if (getChildCount() == 0) {
return null;
}
final int firstChildPos = layoutManager.getPosition(layoutManager.getChildAt(0));
final int direction = targetPosition < firstChildPos != layoutManager.getReverseLayout() ? -1 : 1;
if (layoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) {
return new PointF(direction, 0);
} else {
return new PointF(0, direction);
}
}
};
smoothScroller.setTargetPosition(0);
layoutManager.startSmoothScroll(smoothScroller);
return true;
}
protected abstract long[] getAccountIds();
protected Data getAdapterData() {
return mAdapter.getData();
}
protected void setAdapterData(Data data) {
mAdapter.setData(data);
}
protected Object createMessageBusCallback() {
return new StatusesBusCallback();
}
protected abstract AbsActivitiesAdapter<Data> onCreateAdapter(Context context, boolean compact);
protected abstract void onLoadMoreStatuses();
private void setListShown(boolean shown) {
mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE);
}
protected final class StatusesBusCallback {
protected StatusesBusCallback() {
}
}
}

View File

@ -3,6 +3,7 @@ package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
@ -27,6 +28,7 @@ import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AccelerateSmoothScroller;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.util.ThemeUtils;
@ -66,7 +68,8 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (isRefreshing()) return;
if (layoutManager.findLastVisibleItemPosition() == mAdapter.getItemCount() - 1) {
if (mAdapter.hasLoadMoreIndicator()
&& layoutManager.findLastVisibleItemPosition() == mAdapter.getItemCount() - 1) {
onLoadMoreStatuses();
}
}
@ -261,7 +264,26 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
if (twitter != null && tabPosition != -1) {
twitter.clearUnreadCountAsync(tabPosition);
}
mRecyclerView.smoothScrollToPosition(0);
// mRecyclerView.smoothScrollToPosition(0);
final LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
final AccelerateSmoothScroller smoothScroller = new AccelerateSmoothScroller(getActivity(), 2) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
if (getChildCount() == 0) {
return null;
}
final int firstChildPos = layoutManager.getPosition(layoutManager.getChildAt(0));
final int direction = targetPosition < firstChildPos != layoutManager.getReverseLayout() ? -1 : 1;
if (layoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) {
return new PointF(direction, 0);
} else {
return new PointF(0, direction);
}
}
};
smoothScroller.setTargetPosition(0);
layoutManager.startSmoothScroll(smoothScroller);
return true;
}

View File

@ -19,90 +19,27 @@
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.ListView;
import org.mariotaku.twidere.adapter.BaseParcelableActivitiesAdapter;
import org.mariotaku.twidere.adapter.ParcelableActivitiesAboutMeAdapter;
import org.mariotaku.twidere.loader.support.ActivitiesAboutMeLoader;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import java.util.Arrays;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.openStatus;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
import static org.mariotaku.twidere.util.Utils.openUsers;
public class ActivitiesAboutMeFragment extends BaseActivitiesListFragment {
@Override
public BaseParcelableActivitiesAdapter createListAdapter(final Context context, final boolean compactCards) {
return new ParcelableActivitiesAboutMeAdapter(context, compactCards);
}
public class ActivitiesAboutMeFragment extends ParcelableActivitiesFragment {
@Override
public Loader<List<ParcelableActivity>> onCreateLoader(final int id, final Bundle args) {
setProgressBarIndeterminateVisibility(true);
return new ActivitiesAboutMeLoader(getActivity(), getAccountIds(), getData(), getSavedActivitiesFileArgs(),
true);
}
@Override
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
final int adapter_pos = position - l.getHeaderViewsCount();
final ParcelableActivity item = getListAdapter().getItem(adapter_pos);
if (item == null) return;
final ParcelableUser[] sources = item.sources;
if (sources == null || sources.length == 0) return;
final ParcelableStatus[] target_statuses = item.target_statuses;
final ParcelableStatus[] target_objects = item.target_object_statuses;
switch (item.action) {
case ParcelableActivity.ACTION_FAVORITE: {
if (sources.length == 1) {
openUserProfile(getActivity(), sources[0], null);
} else {
final List<ParcelableUser> users = Arrays.asList(sources);
openUsers(getActivity(), users);
}
break;
}
case ParcelableActivity.ACTION_FOLLOW: {
if (sources.length == 1) {
openUserProfile(getActivity(), sources[0], null);
} else {
final List<ParcelableUser> users = Arrays.asList(sources);
openUsers(getActivity(), users);
}
break;
}
case ParcelableActivity.ACTION_MENTION: {
if (target_objects != null && target_objects.length > 0) {
openStatus(getActivity(), target_objects[0], null);
}
break;
}
case ParcelableActivity.ACTION_REPLY: {
if (target_statuses != null && target_statuses.length > 0) {
openStatus(getActivity(), target_statuses[0], null);
}
break;
}
case ParcelableActivity.ACTION_RETWEET: {
if (sources.length == 1) {
openUserProfile(getActivity(), sources[0], null);
} else {
final List<ParcelableUser> users = Arrays.asList(sources);
openUsers(getActivity(), users);
}
break;
}
}
final long[] accountIds = args.getLongArray(EXTRA_ACCOUNT_IDS);
final long[] sinceIds = args.getLongArray(EXTRA_SINCE_IDS);
final long[] maxIds = args.getLongArray(EXTRA_MAX_IDS);
final long accountId = accountIds != null ? accountIds[0] : -1;
final long sinceId = sinceIds != null ? sinceIds[0] : -1;
final long maxId = maxIds != null ? maxIds[0] : -1;
return new ActivitiesAboutMeLoader(getActivity(), accountId, sinceId, maxId, getAdapterData(),
getSavedActivitiesFileArgs(), getTabPosition());
}
@Override

View File

@ -0,0 +1,118 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.ListView;
import org.mariotaku.twidere.adapter.BaseParcelableActivitiesAdapter;
import org.mariotaku.twidere.adapter.ParcelableActivitiesAboutMeListAdapter;
import org.mariotaku.twidere.loader.support.ActivitiesAboutMeLoader;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import java.util.Arrays;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.openStatus;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
import static org.mariotaku.twidere.util.Utils.openUsers;
public class ActivitiesAboutMeListFragment extends BaseActivitiesListFragment {
@Override
public BaseParcelableActivitiesAdapter createListAdapter(final Context context, final boolean compactCards) {
return new ParcelableActivitiesAboutMeListAdapter(context, compactCards);
}
@Override
public Loader<List<ParcelableActivity>> onCreateLoader(final int id, final Bundle args) {
setProgressBarIndeterminateVisibility(true);
return new ActivitiesAboutMeLoader(getActivity(), getAccountIds()[0], -1, -1, getData(),
getSavedActivitiesFileArgs(), getTabPosition());
}
@Override
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
final int adapter_pos = position - l.getHeaderViewsCount();
final ParcelableActivity item = getListAdapter().getItem(adapter_pos);
if (item == null) return;
final ParcelableUser[] sources = item.sources;
if (sources == null || sources.length == 0) return;
final ParcelableStatus[] target_statuses = item.target_statuses;
final ParcelableStatus[] target_objects = item.target_object_statuses;
switch (item.action) {
case ParcelableActivity.ACTION_FAVORITE: {
if (sources.length == 1) {
openUserProfile(getActivity(), sources[0], null);
} else {
final List<ParcelableUser> users = Arrays.asList(sources);
openUsers(getActivity(), users);
}
break;
}
case ParcelableActivity.ACTION_FOLLOW: {
if (sources.length == 1) {
openUserProfile(getActivity(), sources[0], null);
} else {
final List<ParcelableUser> users = Arrays.asList(sources);
openUsers(getActivity(), users);
}
break;
}
case ParcelableActivity.ACTION_MENTION: {
if (target_objects != null && target_objects.length > 0) {
openStatus(getActivity(), target_objects[0], null);
}
break;
}
case ParcelableActivity.ACTION_REPLY: {
if (target_statuses != null && target_statuses.length > 0) {
openStatus(getActivity(), target_statuses[0], null);
}
break;
}
case ParcelableActivity.ACTION_RETWEET: {
if (sources.length == 1) {
openUserProfile(getActivity(), sources[0], null);
} else {
final List<ParcelableUser> users = Arrays.asList(sources);
openUsers(getActivity(), users);
}
break;
}
}
}
@Override
protected String[] getSavedActivitiesFileArgs() {
final Bundle args = getArguments();
if (args != null && args.containsKey(EXTRA_ACCOUNT_ID)) {
final long account_id = args.getLong(EXTRA_ACCOUNT_ID, -1);
return new String[]{AUTHORITY_ACTIVITIES_ABOUT_ME, "account" + account_id};
}
return new String[]{AUTHORITY_ACTIVITIES_ABOUT_ME};
}
}

View File

@ -50,8 +50,8 @@ public class ActivitiesByFriendsFragment extends BaseActivitiesListFragment {
@Override
public Loader<List<ParcelableActivity>> onCreateLoader(final int id, final Bundle args) {
setProgressBarIndeterminateVisibility(true);
return new ActivitiesAboutMeLoader(getActivity(), getAccountIds(), getData(), getSavedActivitiesFileArgs(),
getTabPosition() >= 0);
return new ActivitiesAboutMeLoader(getActivity(), getAccountIds()[0], -1, -1, getData(),
getSavedActivitiesFileArgs(), getTabPosition());
}
@Override

View File

@ -20,7 +20,7 @@
package org.mariotaku.twidere.fragment.support;
import static org.mariotaku.twidere.util.ContentValuesCreator.makeFilteredUserContentValues;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.content.ContentResolverUtils.bulkDelete;
import static org.mariotaku.twidere.util.content.ContentResolverUtils.bulkInsert;
@ -45,6 +45,7 @@ import org.mariotaku.twidere.util.ContentValuesCreator;
import org.mariotaku.twidere.util.HtmlEscapeHelper;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.UserColorNameUtils;
import java.util.ArrayList;
import java.util.HashSet;
@ -167,10 +168,10 @@ public class AddStatusFilterDialogFragment extends BaseSupportDialogFragment imp
private String getName(final Object value) {
if (value instanceof ParcelableUserMention) {
final ParcelableUserMention mention = (ParcelableUserMention) value;
return getDisplayName(getActivity(), mention.id, mention.name, mention.screen_name);
return UserColorNameUtils.getDisplayName(getActivity(), mention.id, mention.name, mention.screen_name);
} else if (value instanceof ParcelableStatus) {
final ParcelableStatus status = (ParcelableStatus) value;
return getDisplayName(getActivity(), status.user_id, status.user_name, status.user_screen_name);
return UserColorNameUtils.getDisplayName(getActivity(), status.user_id, status.user_name, status.user_screen_name);
} else
return ParseUtils.parseString(value);
}

View File

@ -27,7 +27,7 @@ import android.support.v4.content.Loader;
import android.widget.ListView;
import org.mariotaku.twidere.adapter.BaseParcelableActivitiesAdapter;
import org.mariotaku.twidere.loader.support.Twitter4JActivitiesLoader;
import org.mariotaku.twidere.loader.support.Twitter4JActivitiesLoaderOld;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.util.ArrayUtils;
import org.mariotaku.twidere.util.Utils;
@ -81,8 +81,8 @@ public abstract class BaseActivitiesListFragment extends BasePullToRefreshListFr
setProgressBarIndeterminateVisibility(false);
mData = data;
mAdapter.setData(data);
if (loader instanceof Twitter4JActivitiesLoader) {
final boolean multipleAccounts = ((Twitter4JActivitiesLoader) loader).getAccountIds().length > 1;
if (loader instanceof Twitter4JActivitiesLoaderOld) {
final boolean multipleAccounts = ((Twitter4JActivitiesLoaderOld) loader).getAccountIds().length > 1;
mAdapter.setShowAccountColor(multipleAccounts);
}
setRefreshing(false);

View File

@ -30,7 +30,7 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.UserColorNameUtils;
public class CreateUserBlockDialogFragment extends BaseSupportDialogFragment implements DialogInterface.OnClickListener {
@ -56,7 +56,7 @@ public class CreateUserBlockDialogFragment extends BaseSupportDialogFragment imp
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final ParcelableUser user = getUser();
if (user != null) {
final String display_name = Utils.getDisplayName(wrapped, user.id, user.name, user.screen_name);
final String display_name = UserColorNameUtils.getDisplayName(wrapped, user.id, user.name, user.screen_name);
builder.setTitle(getString(R.string.block_user, display_name));
builder.setMessage(getString(R.string.block_user_confirm_message, display_name));
}

View File

@ -31,7 +31,7 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.UserColorNameUtils;
public class CreateUserMuteDialogFragment extends BaseSupportDialogFragment implements DialogInterface.OnClickListener {
@ -58,7 +58,7 @@ public class CreateUserMuteDialogFragment extends BaseSupportDialogFragment impl
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final ParcelableUser user = getUser();
if (user != null) {
final String displayName = Utils.getDisplayName(wrapped, user.id, user.name, user.screen_name);
final String displayName = UserColorNameUtils.getDisplayName(wrapped, user.id, user.name, user.screen_name);
builder.setTitle(getString(R.string.mute_user, displayName));
builder.setMessage(getString(R.string.mute_user_confirm_message, displayName));
}

View File

@ -33,7 +33,7 @@ import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.UserColorNameUtils;
public class DeleteUserListMembersDialogFragment extends BaseSupportDialogFragment implements
DialogInterface.OnClickListener {
@ -64,7 +64,7 @@ public class DeleteUserListMembersDialogFragment extends BaseSupportDialogFragme
if (users == null || userList == null) throw new NullPointerException();
if (users.length == 1) {
final ParcelableUser user = users[0];
final String displayName = Utils.getDisplayName(wrapped, user.id, user.name, user.screen_name);
final String displayName = UserColorNameUtils.getDisplayName(wrapped, user.id, user.name, user.screen_name);
builder.setTitle(getString(R.string.delete_user, displayName));
builder.setMessage(getString(R.string.delete_user_from_list_confirm, displayName, userList.name));
} else {

View File

@ -31,7 +31,7 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.UserColorNameUtils;
public class DestroyFriendshipDialogFragment extends BaseSupportDialogFragment implements
DialogInterface.OnClickListener {
@ -59,7 +59,7 @@ public class DestroyFriendshipDialogFragment extends BaseSupportDialogFragment i
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final ParcelableUser user = getUser();
if (user != null) {
final String display_name = Utils.getDisplayName(getActivity(), user.id, user.name, user.screen_name);
final String display_name = UserColorNameUtils.getDisplayName(getActivity(), user.id, user.name, user.screen_name);
builder.setTitle(getString(R.string.unfollow_user, display_name));
builder.setMessage(getString(R.string.unfollow_user_confirm_message, display_name));
}

View File

@ -86,6 +86,7 @@ import org.mariotaku.twidere.util.ClipboardUtils;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.TwidereValidator;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.message.TaskStateChangedEvent;
import org.mariotaku.twidere.view.StatusTextCountView;
@ -337,7 +338,7 @@ public class DirectMessagesConversationFragment extends BaseSupportFragment impl
}
final FragmentActivity activity = getActivity();
if (mRecipient != null) {
activity.setTitle(Utils.getDisplayName(activity, mRecipient));
activity.setTitle(UserColorNameUtils.getDisplayName(activity, mRecipient));
} else {
activity.setTitle(R.string.direct_messages);
}

View File

@ -0,0 +1,101 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import com.squareup.otto.Bus;
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter;
import org.mariotaku.twidere.adapter.iface.IActivitiesAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableActivity;
import java.util.List;
/**
* Created by mariotaku on 14/12/3.
*/
public abstract class ParcelableActivitiesFragment extends AbsActivitiesFragment<List<ParcelableActivity>> {
@Override
public int getStatuses(long[] accountIds, final long[] maxIds, final long[] sinceIds) {
final Bundle args = new Bundle(getArguments());
args.putLongArray(EXTRA_ACCOUNT_IDS, accountIds);
args.putLongArray(EXTRA_MAX_IDS, maxIds);
args.putLongArray(EXTRA_SINCE_IDS, sinceIds);
getLoaderManager().restartLoader(0, args, this);
return -1;
}
@Override
public void onStart() {
super.onStart();
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
bus.register(this);
}
@Override
public void onStop() {
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
bus.unregister(this);
super.onStop();
}
@Override
protected long[] getAccountIds() {
return new long[]{getAccountId()};
}
@Override
protected ParcelableActivitiesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableActivitiesAdapter(context);
}
@Override
protected void onLoadMoreStatuses() {
final IActivitiesAdapter<List<ParcelableActivity>> adapter = getAdapter();
final long[] maxIds = new long[]{adapter.getActivity(adapter.getActivityCount() - 1).min_position};
getStatuses(getAccountIds(), maxIds, null);
}
@Override
public boolean triggerRefresh() {
final IActivitiesAdapter<List<ParcelableActivity>> adapter = getAdapter();
final long[] accountIds = getAccountIds();
if (adapter.getActivityCount() > 0) {
final long[] sinceIds = new long[]{adapter.getActivity(0).max_position};
getStatuses(accountIds, null, sinceIds);
} else {
getStatuses(accountIds, null, null);
}
return true;
}
protected long getAccountId() {
final Bundle args = getArguments();
return args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
}
protected abstract String[] getSavedActivitiesFileArgs();
}

View File

@ -30,7 +30,7 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.UserColorNameUtils;
public class ReportSpamDialogFragment extends BaseSupportDialogFragment implements DialogInterface.OnClickListener {
@ -56,7 +56,7 @@ public class ReportSpamDialogFragment extends BaseSupportDialogFragment implemen
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final ParcelableUser user = getUser();
if (user != null) {
final String display_name = Utils.getDisplayName(getActivity(), user.id, user.name, user.screen_name);
final String display_name = UserColorNameUtils.getDisplayName(getActivity(), user.id, user.name, user.screen_name);
builder.setTitle(getString(R.string.report_user, display_name));
builder.setMessage(getString(R.string.report_user_confirm_message, display_name));
}

View File

@ -19,8 +19,8 @@
package org.mariotaku.twidere.fragment.support;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.clearUserNickname;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.setUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.clearUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.setUserNickname;
import android.app.AlertDialog;
import android.app.Dialog;

View File

@ -26,6 +26,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
@ -52,7 +53,6 @@ import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
@ -87,10 +87,12 @@ import org.mariotaku.twidere.util.MediaPreviewUtils.OnMediaClickListener;
import org.mariotaku.twidere.util.OnLinkClickHandler;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.util.TwitterCardUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.ShapedImageView;
import org.mariotaku.twidere.view.StatusTextView;
import org.mariotaku.twidere.view.TwidereMenuBar;
import org.mariotaku.twidere.view.TwitterCardContainer;
import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
@ -102,11 +104,11 @@ import java.util.Locale;
import twitter4j.TwitterException;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.clearUserColor;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.clearUserNickname;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.setUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.clearUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.clearUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.setUserColor;
import static org.mariotaku.twidere.util.Utils.findStatus;
import static org.mariotaku.twidere.util.Utils.formatToLongTimeString;
import static org.mariotaku.twidere.util.Utils.getLocalizedNumber;
@ -484,7 +486,18 @@ public class StatusFragment extends BaseSupportFragment
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
final Context context = getContext();
final ParcelableStatus status = getStatus(position);
final View profileImageView = holder.getProfileImageView();
final View profileTypeView = holder.getProfileTypeView();
if (context instanceof FragmentActivity) {
final Bundle options = Utils.makeSceneTransitionOption((FragmentActivity) context,
new Pair<>(profileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE),
new Pair<>(profileTypeView, UserFragment.TRANSITION_NAME_PROFILE_TYPE));
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, options);
} else {
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, null);
}
}
@Override
@ -771,7 +784,7 @@ public class StatusFragment extends BaseSupportFragment
private final LinearLayout mediaPreviewGrid;
private final View locationContainer;
private final FrameLayout twitterCard;
private final TwitterCardContainer twitterCard;
public DetailStatusViewHolder(StatusAdapter adapter, View itemView) {
super(itemView);
@ -796,7 +809,7 @@ public class StatusFragment extends BaseSupportFragment
mediaPreviewGrid = (LinearLayout) itemView.findViewById(R.id.media_preview_grid);
locationContainer = itemView.findViewById(R.id.location_container);
profileContainer = itemView.findViewById(R.id.profile_container);
twitterCard = (FrameLayout) itemView.findViewById(R.id.twitter_card);
twitterCard = (TwitterCardContainer) itemView.findViewById(R.id.twitter_card);
setIsRecyclable(false);
initViews();
@ -1007,9 +1020,15 @@ public class StatusFragment extends BaseSupportFragment
mediaPreviewGrid.removeAllViews();
}
if (Utils.isCardSupported(status.card)) {
if (TwitterCardUtils.isCardSupported(status.card)) {
final Point size = TwitterCardUtils.getCardSize(status.card);
twitterCard.setVisibility(View.VISIBLE);
final Fragment cardFragment = Utils.createTwitterCardFragment(status.card);
if (size != null) {
twitterCard.setCardSize(size.x, size.y);
} else {
twitterCard.setCardSize(0, 0);
}
final Fragment cardFragment = TwitterCardUtils.createCardFragment(status.card);
final FragmentManager fm = fragment.getChildFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.twitter_card, cardFragment);

View File

@ -35,4 +35,12 @@ public class SupportBrowserFragment extends BaseSupportWebViewFragment {
view.loadUrl(ParseUtils.parseString(uri, "about:blank"));
}
public static SupportBrowserFragment show(String uri) {
final Bundle args = new Bundle();
args.putString(EXTRA_URI, uri);
final SupportBrowserFragment fragment = new SupportBrowserFragment();
fragment.setArguments(args);
return fragment;
}
}

View File

@ -106,7 +106,7 @@ import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.util.TwidereLinkify.OnLinkClickListener;
import org.mariotaku.twidere.util.UserColorNicknameUtils;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.menu.TwidereMenuInfo;
import org.mariotaku.twidere.util.message.FriendshipUpdatedEvent;
@ -129,15 +129,15 @@ import twitter4j.TwitterException;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.ParseUtils.parseLong;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.clearUserColor;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.clearUserNickname;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNicknameUtils.getUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.clearUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.clearUserNickname;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
import static org.mariotaku.twidere.util.Utils.addIntentToMenu;
import static org.mariotaku.twidere.util.Utils.formatToLongTimeString;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.getAccountScreenName;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.Utils.getErrorMessage;
import static org.mariotaku.twidere.util.Utils.getLocalizedNumber;
import static org.mariotaku.twidere.util.Utils.getOriginalTwitterProfileImage;
@ -439,7 +439,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
if (relationship == null || relationship.getTargetUserId() != user.id) {
getFriendship();
}
activity.setTitle(getDisplayName(activity, user, true));
activity.setTitle(UserColorNameUtils.getDisplayName(activity, user, true));
updateTitleColor();
invalidateOptionsMenu();
}
@ -560,7 +560,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
if (resultCode == Activity.RESULT_OK) {
if (data == null) return;
final int color = data.getIntExtra(EXTRA_COLOR, Color.TRANSPARENT);
UserColorNicknameUtils.setUserColor(getActivity(), mUser.id, color);
UserColorNameUtils.setUserColor(getActivity(), mUser.id, color);
} else if (resultCode == ColorPickerDialogActivity.RESULT_CLEARED) {
clearUserColor(getActivity(), mUser.id);
}
@ -709,7 +709,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final boolean isMyself = user.account_id == user.id;
final MenuItem mentionItem = menu.findItem(MENU_MENTION);
if (mentionItem != null) {
mentionItem.setTitle(getString(R.string.mention_user_name, getDisplayName(getActivity(), user)));
mentionItem.setTitle(getString(R.string.mention_user_name, UserColorNameUtils.getDisplayName(getActivity(), user)));
}
Utils.setMenuItemAvailability(menu, MENU_MENTION, !isMyself);
// final MenuItem followItem = menu.findItem(MENU_FOLLOW);

View File

@ -69,6 +69,7 @@ import org.mariotaku.twidere.util.OnLinkClickHandler;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.view.ColorLabelRelativeLayout;
import org.mariotaku.twidere.view.HeaderDrawerLayout;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
@ -81,7 +82,7 @@ import twitter4j.UserList;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.Utils.addIntentToMenu;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
import static org.mariotaku.twidere.util.Utils.setMenuItemAvailability;
@ -191,7 +192,7 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
mUserList = userList;
mProfileContainer.drawEnd(getAccountColor(getActivity(), userList.account_id));
mListNameView.setText(userList.name);
final String display_name = getDisplayName(getActivity(), userList.user_id, userList.user_name,
final String display_name = UserColorNameUtils.getDisplayName(getActivity(), userList.user_id, userList.user_name,
userList.user_screen_name, false);
mCreatedByView.setText(getString(R.string.created_by, display_name));
final String description = userList.description;

View File

@ -20,27 +20,34 @@
package org.mariotaku.twidere.loader.support;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import org.mariotaku.twidere.model.ParcelableActivity;
import java.util.List;
import twitter4j.Activity;
import twitter4j.Paging;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import java.util.List;
public class ActivitiesAboutMeLoader extends Twitter4JActivitiesLoader {
public ActivitiesAboutMeLoader(final Context context, final long[] accountIds, final List<ParcelableActivity> data,
final String[] saveFileArgs, final boolean useCache) {
super(context, accountIds, data, saveFileArgs, useCache);
}
public ActivitiesAboutMeLoader(final Context context, final long accountId, long sinceId,
long maxId, final List<ParcelableActivity> data,
final String[] saveFileArgs, final int position) {
super(context, accountId, sinceId, maxId, data, saveFileArgs, position);
}
@Override
protected List<Activity> getActivities(final Twitter twitter, final Paging paging) throws TwitterException {
if (twitter == null) return null;
return twitter.getActivitiesAboutMe(paging);
}
@Override
protected List<Activity> getActivities(final Twitter twitter, final Paging paging) throws TwitterException {
if (twitter == null) return null;
return twitter.getActivitiesAboutMe(paging);
}
@Override
protected boolean shouldFilterActivity(SQLiteDatabase database, ParcelableActivity activity) {
return false;
}
}

View File

@ -23,24 +23,25 @@ import android.content.Context;
import org.mariotaku.twidere.model.ParcelableActivity;
import java.util.List;
import twitter4j.Activity;
import twitter4j.Paging;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import java.util.List;
public class ActivitiesByFriendsLoader extends Twitter4JActivitiesLoaderOld {
public class ActivitiesByFriendsLoader extends Twitter4JActivitiesLoader {
public ActivitiesByFriendsLoader(final Context context, final long[] accountIds, long[] sinceIds,
long[] maxIds, final List<ParcelableActivity> data,
final String[] saveFileArgs, final boolean useCache) {
super(context, accountIds, sinceIds, maxIds, data, saveFileArgs, useCache);
}
public ActivitiesByFriendsLoader(final Context context, final long[] accountIds,
final List<ParcelableActivity> data, final String[] saveFileArgs, final boolean useCache) {
super(context, accountIds, data, saveFileArgs, useCache);
}
@Override
protected List<Activity> getActivities(final Twitter twitter, final Paging paging) throws TwitterException {
if (twitter == null) return null;
return twitter.getActivitiesByFriends(paging);
}
@Override
protected List<Activity> getActivities(final Twitter twitter, final Paging paging) throws TwitterException {
if (twitter == null) return null;
return twitter.getActivitiesByFriends(paging);
}
}

View File

@ -0,0 +1,87 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader.support;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList;
import java.util.List;
public abstract class ParcelableActivitiesLoader extends AsyncTaskLoader<List<ParcelableActivity>> implements Constants {
private final List<ParcelableActivity> mData = new NoDuplicatesArrayList<>();
private final boolean mFirstLoad;
private final int mTabPosition;
private Long mLastViewedId;
public ParcelableActivitiesLoader(final Context context, final List<ParcelableActivity> data, final int tab_position) {
super(context);
mFirstLoad = data == null;
if (data != null) {
mData.addAll(data);
}
mTabPosition = tab_position;
}
public Long getLastViewedId() {
return mLastViewedId;
}
protected boolean containsStatus(final long id) {
for (final ParcelableActivity activity : mData) {
if (activity.max_position <= id && activity.min_position >= id) return true;
}
return false;
}
protected boolean deleteStatus(final List<ParcelableActivity> activities, final long id) {
if (activities == null || activities.isEmpty()) return false;
boolean result = false;
for (final ParcelableActivity activity : activities.toArray(new ParcelableActivity[activities.size()])) {
if (id <= activity.max_position && id >= activity.min_position) {
result |= activities.remove(activity);
}
}
return result;
}
protected List<ParcelableActivity> getData() {
return mData;
}
protected int getTabPosition() {
return mTabPosition;
}
protected boolean isFirstLoad() {
return mFirstLoad;
}
@Override
protected void onStartLoading() {
forceLoad();
}
}

View File

@ -34,8 +34,6 @@ public abstract class ParcelableStatusesLoader extends AsyncTaskLoader<List<Parc
private final boolean mFirstLoad;
private final int mTabPosition;
private Long mLastViewedId;
public ParcelableStatusesLoader(final Context context, final List<ParcelableStatus> data, final int tab_position) {
super(context);
mFirstLoad = data == null;
@ -45,10 +43,6 @@ public abstract class ParcelableStatusesLoader extends AsyncTaskLoader<List<Parc
mTabPosition = tab_position;
}
public Long getLastViewedId() {
return mLastViewedId;
}
protected boolean containsStatus(final long status_id) {
for (final ParcelableStatus status : mData) {
if (status.id == status_id) return true;
@ -84,8 +78,5 @@ public abstract class ParcelableStatusesLoader extends AsyncTaskLoader<List<Parc
forceLoad();
}
protected void setLastViewedId(final Long id) {
mLastViewedId = id;
}
}

View File

@ -1,151 +1,178 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader.support;
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.v4.content.AsyncTaskLoader;
import android.database.sqlite.SQLiteDatabase;
import android.os.Handler;
import org.mariotaku.jsonserializer.JSONFileIO;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import twitter4j.Activity;
import twitter4j.Paging;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
import static org.mariotaku.twidere.util.Utils.truncateActivities;
public abstract class Twitter4JActivitiesLoader extends AsyncTaskLoader<List<ParcelableActivity>> implements Constants {
private final Context mContext;
public abstract class Twitter4JActivitiesLoader extends ParcelableActivitiesLoader {
private final long[] mAccountIds;
private final List<ParcelableActivity> mData = new NoDuplicatesArrayList<ParcelableActivity>();
private final boolean mIsFirstLoad;
private final boolean mUseCache;
private final Context mContext;
private final long mAccountIds;
private final long mMaxId, mSinceId;
private final SQLiteDatabase mDatabase;
private final Handler mHandler;
private final Object[] mSavedStatusesFileArgs;
private Comparator<ParcelableActivity> mComparator;
private final Object[] mSavedActivitiesFileArgs;
public Twitter4JActivitiesLoader(final Context context, final long accountId, final long sinceId,
final long maxId, final List<ParcelableActivity> data, final String[] savedStatusesArgs,
final int tabPosition) {
super(context, data, tabPosition);
mContext = context;
mAccountIds = accountId;
mSinceId = sinceId;
mMaxId = maxId;
mDatabase = TwidereApplication.getInstance(context).getSQLiteDatabase();
mHandler = new Handler();
mSavedStatusesFileArgs = savedStatusesArgs;
}
public Twitter4JActivitiesLoader(final Context context, final long[] accountIds,
final List<ParcelableActivity> data, final String[] saveFileArgs, final boolean useCache) {
super(context);
mContext = context;
mAccountIds = accountIds;
mIsFirstLoad = data == null;
if (data != null) {
mData.addAll(data);
}
mUseCache = useCache;
mSavedActivitiesFileArgs = saveFileArgs;
}
@SuppressWarnings("unchecked")
@Override
public final List<ParcelableActivity> loadInBackground() {
final File serializationFile = getSerializationFile();
final List<ParcelableActivity> data = getData();
if (isFirstLoad() && getTabPosition() >= 0 && serializationFile != null) {
final List<ParcelableActivity> cached = getCachedData(serializationFile);
if (cached != null) {
data.addAll(cached);
if (mComparator != null) {
Collections.sort(data, mComparator);
} else {
Collections.sort(data);
}
return new CopyOnWriteArrayList<>(data);
}
}
final List<Activity> activities;
final boolean truncated;
final Context context = getContext();
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int loadItemLimit = prefs.getInt(KEY_LOAD_ITEM_LIMIT, DEFAULT_LOAD_ITEM_LIMIT);
try {
final Paging paging = new Paging();
paging.setCount(loadItemLimit);
if (mMaxId > 0) {
paging.setMaxId(mMaxId);
}
if (mSinceId > 0) {
paging.setSinceId(mSinceId);
}
activities = new ArrayList<>();
truncated = truncateActivities(getActivities(getTwitter(), paging), activities, mSinceId);
} catch (final TwitterException e) {
// mHandler.post(new ShowErrorRunnable(e));
e.printStackTrace();
return new CopyOnWriteArrayList<>(data);
}
// final long minStatusId = activities.isEmpty() ? -1 : Collections.min(activities).getId();
// final boolean insertGap = minStatusId > 0 && activities.size() > 1 && !data.isEmpty() && !truncated;
// mHandler.post(CacheUsersStatusesTask.getRunnable(context, new StatusListResponse(mAccountIds, activities)));
for (final Activity activity : activities) {
final long id = activity.getMaxPosition();
deleteStatus(data, id);
// final boolean deleted = deleteStatus(data, id);
// final boolean isGap = minStatusId == id && insertGap && !deleted;
data.add(new ParcelableActivity(activity, mAccountIds));
}
final ParcelableActivity[] array = data.toArray(new ParcelableActivity[data.size()]);
// for (int i = 0, size = array.length; i < size; i++) {
// final ParcelableActivity status = array[i];
// if (shouldFilterActivity(mDatabase, status) && !status.is_gap && i != size - 1) {
// deleteStatus(data, status.max_position);
// }
// }
if (mComparator != null) {
Collections.sort(data, mComparator);
} else {
Collections.sort(data);
}
saveCachedData(serializationFile, data);
return new CopyOnWriteArrayList<>(data);
}
public final long[] getAccountIds() {
return mAccountIds;
}
public final void setComparator(Comparator<ParcelableActivity> comparator) {
mComparator = comparator;
}
@Override
public final List<ParcelableActivity> loadInBackground() {
if (mAccountIds == null) return Collections.emptyList();
final File serializationFile = getSerializationFile();
if (mIsFirstLoad && mUseCache && serializationFile != null) {
final List<ParcelableActivity> cached = getCachedData(serializationFile);
if (cached != null) {
Collections.sort(cached);
return new CopyOnWriteArrayList<ParcelableActivity>(cached);
}
}
final SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int loadItemLimit = prefs.getInt(KEY_LOAD_ITEM_LIMIT, DEFAULT_LOAD_ITEM_LIMIT);
final List<ParcelableActivity> result = new ArrayList<ParcelableActivity>();
for (final long accountId : mAccountIds) {
final List<Activity> activities;
try {
final Paging paging = new Paging();
paging.setCount(Math.min(100, loadItemLimit));
activities = getActivities(getTwitter(accountId), paging);
} catch (final TwitterException e) {
e.printStackTrace();
final List<ParcelableActivity> cached = getCachedData(serializationFile);
if (cached == null) return Collections.emptyList();
return new CopyOnWriteArrayList<ParcelableActivity>(cached);
}
if (activities == null) return new CopyOnWriteArrayList<ParcelableActivity>(mData);
for (final Activity activity : activities) {
result.add(new ParcelableActivity(activity, accountId));
}
}
Collections.sort(result);
saveCachedData(serializationFile, result);
return new CopyOnWriteArrayList<ParcelableActivity>(result);
}
protected abstract List<Activity> getActivities(Twitter twitter, Paging paging) throws TwitterException;
protected abstract List<Activity> getActivities(Twitter twitter, Paging paging) throws TwitterException;
protected final Twitter getTwitter() {
return getTwitterInstance(mContext, mAccountIds, true, true);
}
protected final Twitter getTwitter(final long accountId) {
return getTwitterInstance(mContext, accountId, true);
}
protected abstract boolean shouldFilterActivity(final SQLiteDatabase database, final ParcelableActivity activity);
@Override
protected void onStartLoading() {
forceLoad();
}
private List<ParcelableActivity> getCachedData(final File file) {
if (file == null) return null;
try {
return JSONFileIO.readArrayList(file);
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
private List<ParcelableActivity> getCachedData(final File file) {
if (file == null) return null;
try {
return JSONFileIO.readArrayList(file);
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
private File getSerializationFile() {
if (mSavedStatusesFileArgs == null) return null;
try {
return JSONFileIO.getSerializationFile(mContext, mSavedStatusesFileArgs);
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
private File getSerializationFile() {
if (mSavedActivitiesFileArgs == null) return null;
try {
return JSONFileIO.getSerializationFile(mContext, mSavedActivitiesFileArgs);
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
private void saveCachedData(final File file, final List<ParcelableActivity> data) {
if (file == null || data == null) return;
final SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int databaseItemLimit = prefs.getInt(KEY_DATABASE_ITEM_LIMIT, DEFAULT_DATABASE_ITEM_LIMIT);
try {
final List<ParcelableActivity> activities = data.subList(0, Math.min(databaseItemLimit, data.size()));
JSONFileIO.writeArray(file, activities.toArray(new ParcelableActivity[activities.size()]));
} catch (final IOException e) {
e.printStackTrace();
}
}
private void saveCachedData(final File file, final List<ParcelableActivity> data) {
if (file == null || data == null) return;
final SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int databaseItemLimit = prefs.getInt(KEY_DATABASE_ITEM_LIMIT, DEFAULT_DATABASE_ITEM_LIMIT);
try {
final List<ParcelableActivity> activities = data.subList(0, Math.min(databaseItemLimit, data.size()));
JSONFileIO.writeArray(file, activities.toArray(new ParcelableActivity[activities.size()]));
} catch (final IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,162 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader.support;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.v4.content.AsyncTaskLoader;
import org.mariotaku.jsonserializer.JSONFileIO;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import twitter4j.Activity;
import twitter4j.Paging;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
public abstract class Twitter4JActivitiesLoaderOld extends AsyncTaskLoader<List<ParcelableActivity>> implements Constants {
private final Context mContext;
private final long[] mAccountIds;
private final long[] mSinceIds, mMaxIds;
private final List<ParcelableActivity> mData = new NoDuplicatesArrayList<>();
private final boolean mIsFirstLoad;
private final boolean mUseCache;
private final Object[] mSavedActivitiesFileArgs;
public Twitter4JActivitiesLoaderOld(final Context context, final long[] accountIds,
final long[] sinceIds, final long[] maxIds,
final List<ParcelableActivity> data, final String[] saveFileArgs, final boolean useCache) {
super(context);
mContext = context;
mAccountIds = accountIds;
mSinceIds = sinceIds;
mMaxIds = maxIds;
mIsFirstLoad = data == null;
if (data != null) {
mData.addAll(data);
}
mUseCache = useCache;
mSavedActivitiesFileArgs = saveFileArgs;
}
public final long[] getAccountIds() {
return mAccountIds;
}
@Override
public final List<ParcelableActivity> loadInBackground() {
if (mAccountIds == null) return Collections.emptyList();
final File serializationFile = getSerializationFile();
if (mIsFirstLoad && mUseCache && serializationFile != null) {
final List<ParcelableActivity> cached = getCachedData(serializationFile);
if (cached != null) {
Collections.sort(cached);
return new CopyOnWriteArrayList<>(cached);
}
}
final SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int loadItemLimit = prefs.getInt(KEY_LOAD_ITEM_LIMIT, DEFAULT_LOAD_ITEM_LIMIT);
final List<ParcelableActivity> result = new ArrayList<>();
for (int i = 0, j = mAccountIds.length; i < j; i++) {
final long accountId = mAccountIds[i];
final List<Activity> activities;
final Paging paging = new Paging();
paging.setCount(Math.min(100, loadItemLimit));
if (mSinceIds != null && mSinceIds.length == j) {
paging.setSinceId(mSinceIds[i]);
}
if (mMaxIds != null && mMaxIds.length == j) {
paging.setMaxId(mMaxIds[i]);
}
try {
activities = getActivities(getTwitter(accountId), paging);
} catch (final TwitterException e) {
e.printStackTrace();
final List<ParcelableActivity> cached = getCachedData(serializationFile);
if (cached == null) return Collections.emptyList();
return new CopyOnWriteArrayList<>(cached);
}
if (activities == null) return new CopyOnWriteArrayList<>(mData);
for (final Activity activity : activities) {
result.add(new ParcelableActivity(activity, accountId));
}
}
Collections.sort(result);
saveCachedData(serializationFile, result);
return new CopyOnWriteArrayList<>(result);
}
protected abstract List<Activity> getActivities(Twitter twitter, Paging paging) throws TwitterException;
protected final Twitter getTwitter(final long accountId) {
return getTwitterInstance(mContext, accountId, true);
}
@Override
protected void onStartLoading() {
forceLoad();
}
private List<ParcelableActivity> getCachedData(final File file) {
if (file == null) return null;
try {
return JSONFileIO.readArrayList(file);
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
private File getSerializationFile() {
if (mSavedActivitiesFileArgs == null) return null;
try {
return JSONFileIO.getSerializationFile(mContext, mSavedActivitiesFileArgs);
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
private void saveCachedData(final File file, final List<ParcelableActivity> data) {
if (file == null || data == null) return;
final SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int databaseItemLimit = prefs.getInt(KEY_DATABASE_ITEM_LIMIT, DEFAULT_DATABASE_ITEM_LIMIT);
try {
final List<ParcelableActivity> activities = data.subList(0, Math.min(databaseItemLimit, data.size()));
JSONFileIO.writeArray(file, activities.toArray(new ParcelableActivity[activities.size()]));
} catch (final IOException e) {
e.printStackTrace();
}
}
}

View File

@ -176,7 +176,7 @@ public class ParcelableAccount implements Parcelable {
if (context == null) return Collections.emptyList();
final ArrayList<ParcelableAccount> accounts = new ArrayList<>();
final Cursor cur = ContentResolverUtils.query(context.getContentResolver(),
Accounts.CONTENT_URI, Accounts.COLUMNS_NO_CREDENTIALS,
Accounts.CONTENT_URI, Accounts.COLUMNS,
activatedOnly ? Accounts.IS_ACTIVATED + " = 1" : null, null, Accounts.SORT_POSITION);
if (cur == null) return accounts;
final Indices indices = new Indices(cur);

View File

@ -19,159 +19,167 @@
package org.mariotaku.twidere.model;
import android.support.annotation.NonNull;
import org.mariotaku.jsonserializer.JSONParcel;
import org.mariotaku.jsonserializer.JSONParcelable;
import twitter4j.Activity;
import java.util.Arrays;
import java.util.Date;
import twitter4j.Activity;
import twitter4j.Status;
import twitter4j.User;
import twitter4j.UserList;
public class ParcelableActivity implements Comparable<ParcelableActivity>, JSONParcelable {
public static final JSONParcelable.Creator<ParcelableActivity> JSON_CREATOR = new JSONParcelable.Creator<ParcelableActivity>() {
@Override
public ParcelableActivity createFromParcel(final JSONParcel in) {
return new ParcelableActivity(in);
}
public static final JSONParcelable.Creator<ParcelableActivity> JSON_CREATOR = new JSONParcelable.Creator<ParcelableActivity>() {
@Override
public ParcelableActivity createFromParcel(final JSONParcel in) {
return new ParcelableActivity(in);
}
@Override
public ParcelableActivity[] newArray(final int size) {
return new ParcelableActivity[size];
}
};
@Override
public ParcelableActivity[] newArray(final int size) {
return new ParcelableActivity[size];
}
};
public final static int ACTION_FAVORITE = Activity.Action.ACTION_FAVORITE;
public final static int ACTION_FOLLOW = Activity.Action.ACTION_FOLLOW;
public final static int ACTION_MENTION = Activity.Action.ACTION_MENTION;
public final static int ACTION_REPLY = Activity.Action.ACTION_REPLY;
public final static int ACTION_RETWEET = Activity.Action.ACTION_RETWEET;
public final static int ACTION_LIST_MEMBER_ADDED = Activity.Action.ACTION_LIST_MEMBER_ADDED;
public final static int ACTION_LIST_CREATED = Activity.Action.ACTION_LIST_CREATED;
public final static int ACTION_FAVORITE = Activity.Action.ACTION_FAVORITE;
public final static int ACTION_FOLLOW = Activity.Action.ACTION_FOLLOW;
public final static int ACTION_MENTION = Activity.Action.ACTION_MENTION;
public final static int ACTION_REPLY = Activity.Action.ACTION_REPLY;
public final static int ACTION_RETWEET = Activity.Action.ACTION_RETWEET;
public final static int ACTION_LIST_MEMBER_ADDED = Activity.Action.ACTION_LIST_MEMBER_ADDED;
public final static int ACTION_LIST_CREATED = Activity.Action.ACTION_LIST_CREATED;
public final static int ACTION_FAVORITED_RETWEET = Activity.Action.ACTION_FAVORITED_RETWEET;
public final static int ACTION_RETWEETED_RETWEET = Activity.Action.ACTION_RETWEETED_RETWEET;
public final long account_id, activity_timestamp, max_position, min_position;
public final int action;
public final long account_id, timestamp, max_position, min_position;
public final int action;
public final ParcelableUser[] sources;
public final ParcelableUser[] target_users;
public final ParcelableStatus[] target_statuses;
public final ParcelableUserList[] target_user_lists;
public final ParcelableUser[] sources;
public final ParcelableUser[] target_users;
public final ParcelableStatus[] target_statuses;
public final ParcelableUserList[] target_user_lists;
public final ParcelableUserList[] target_object_user_lists;
public final ParcelableStatus[] target_object_statuses;
public final ParcelableUserList[] target_object_user_lists;
public final ParcelableStatus[] target_object_statuses;
public ParcelableActivity(final Activity activity, final long account_id) {
this.account_id = account_id;
activity_timestamp = getTime(activity.getCreatedAt());
action = activity.getAction().getActionId();
max_position = activity.getMaxPosition();
min_position = activity.getMinPosition();
final int sources_size = activity.getSourcesSize();
sources = new ParcelableUser[sources_size];
for (int i = 0; i < sources_size; i++) {
sources[i] = new ParcelableUser(activity.getSources()[i], account_id);
}
final int targets_size = activity.getTargetsSize();
if (action == ACTION_FOLLOW || action == ACTION_MENTION || action == ACTION_LIST_MEMBER_ADDED) {
target_users = new ParcelableUser[targets_size];
target_statuses = null;
target_user_lists = null;
for (int i = 0; i < targets_size; i++) {
target_users[i] = new ParcelableUser(activity.getTargetUsers()[i], account_id);
}
} else if (action == ACTION_LIST_CREATED) {
target_user_lists = new ParcelableUserList[targets_size];
target_statuses = null;
target_users = null;
for (int i = 0; i < targets_size; i++) {
target_user_lists[i] = new ParcelableUserList(activity.getTargetUserLists()[i], account_id);
}
} else {
target_statuses = new ParcelableStatus[targets_size];
target_users = null;
target_user_lists = null;
for (int i = 0; i < targets_size; i++) {
target_statuses[i] = new ParcelableStatus(activity.getTargetStatuses()[i], account_id, false);
}
}
final int target_objects_size = activity.getTargetObjectsSize();
if (action == ACTION_LIST_MEMBER_ADDED) {
target_object_user_lists = new ParcelableUserList[target_objects_size];
target_object_statuses = null;
for (int i = 0; i < target_objects_size; i++) {
target_object_user_lists[i] = new ParcelableUserList(activity.getTargetObjectUserLists()[i], account_id);
}
} else if (action == ACTION_LIST_CREATED) {
target_object_user_lists = null;
target_object_statuses = null;
} else {
target_object_statuses = new ParcelableStatus[target_objects_size];
target_object_user_lists = null;
for (int i = 0; i < target_objects_size; i++) {
target_object_statuses[i] = new ParcelableStatus(activity.getTargetObjectStatuses()[i], account_id,
false);
}
}
}
public ParcelableActivity(final Activity activity, final long account_id) {
this.account_id = account_id;
timestamp = activity.getCreatedAt().getTime();
action = activity.getAction().getActionId();
max_position = activity.getMaxPosition();
min_position = activity.getMinPosition();
final int sources_size = activity.getSourcesSize();
sources = new ParcelableUser[sources_size];
for (int i = 0; i < sources_size; i++) {
sources[i] = new ParcelableUser(activity.getSources()[i], account_id);
}
final int targets_size = activity.getTargetsSize();
final User[] targetUsers = activity.getTargetUsers();
if (targetUsers != null) {
target_users = new ParcelableUser[targets_size];
for (int i = 0; i < targets_size; i++) {
target_users[i] = new ParcelableUser(targetUsers[i], account_id);
}
} else {
target_users = null;
}
final UserList[] targetUserLists = activity.getTargetUserLists();
if (targetUserLists != null) {
target_user_lists = new ParcelableUserList[targets_size];
for (int i = 0; i < targets_size; i++) {
target_user_lists[i] = new ParcelableUserList(targetUserLists[i], account_id);
}
} else {
target_user_lists = null;
}
final Status[] targetStatuses = activity.getTargetStatuses();
if (targetStatuses != null) {
target_statuses = new ParcelableStatus[targets_size];
for (int i = 0; i < targets_size; i++) {
target_statuses[i] = new ParcelableStatus(targetStatuses[i], account_id, false);
}
} else {
target_statuses = null;
}
final int target_objects_size = activity.getTargetObjectsSize();
final Status[] targetObjectStatuses = activity.getTargetObjectStatuses();
if (targetObjectStatuses != null) {
target_object_statuses = new ParcelableStatus[target_objects_size];
for (int i = 0; i < target_objects_size; i++) {
target_object_statuses[i] = new ParcelableStatus(targetObjectStatuses[i], account_id, false);
}
} else {
target_object_statuses = null;
}
final UserList[] targetObjectUserLists = activity.getTargetObjectUserLists();
if (targetObjectUserLists != null) {
target_object_user_lists = new ParcelableUserList[target_objects_size];
for (int i = 0; i < target_objects_size; i++) {
target_object_user_lists[i] = new ParcelableUserList(targetObjectUserLists[i], account_id);
}
} else {
target_object_user_lists = null;
}
}
public ParcelableActivity(final JSONParcel in) {
account_id = in.readLong("account_id");
activity_timestamp = in.readLong("activity_timestamp");
max_position = in.readLong("max_position");
min_position = in.readLong("min_position");
action = in.readInt("action");
sources = in.readParcelableArray("sources", ParcelableUser.JSON_CREATOR);
target_users = in.readParcelableArray("target_users", ParcelableUser.JSON_CREATOR);
target_statuses = in.readParcelableArray("target_statuses", ParcelableStatus.JSON_CREATOR);
target_user_lists = in.readParcelableArray("target_user_lists", ParcelableUserList.JSON_CREATOR);
target_object_user_lists = in.readParcelableArray("target_object_user_lists", ParcelableUserList.JSON_CREATOR);
target_object_statuses = in.readParcelableArray("target_object_statuses", ParcelableStatus.JSON_CREATOR);
}
public ParcelableActivity(final JSONParcel in) {
account_id = in.readLong("account_id");
timestamp = in.readLong("timestamp");
max_position = in.readLong("max_position");
min_position = in.readLong("min_position");
action = in.readInt("action");
sources = in.readParcelableArray("sources", ParcelableUser.JSON_CREATOR);
target_users = in.readParcelableArray("target_users", ParcelableUser.JSON_CREATOR);
target_statuses = in.readParcelableArray("target_statuses", ParcelableStatus.JSON_CREATOR);
target_user_lists = in.readParcelableArray("target_user_lists", ParcelableUserList.JSON_CREATOR);
target_object_user_lists = in.readParcelableArray("target_object_user_lists", ParcelableUserList.JSON_CREATOR);
target_object_statuses = in.readParcelableArray("target_object_statuses", ParcelableStatus.JSON_CREATOR);
}
@Override
public int compareTo(final ParcelableActivity another) {
if (another == null) return 0;
final long delta = another.activity_timestamp - activity_timestamp;
if (delta < Integer.MIN_VALUE) return Integer.MIN_VALUE;
if (delta > Integer.MAX_VALUE) return Integer.MAX_VALUE;
return (int) delta;
}
@Override
public int compareTo(@NonNull final ParcelableActivity another) {
final long delta = another.timestamp - timestamp;
if (delta < Integer.MIN_VALUE) return Integer.MIN_VALUE;
if (delta > Integer.MAX_VALUE) return Integer.MAX_VALUE;
return (int) delta;
}
@Override
public boolean equals(final Object that) {
if (!(that instanceof ParcelableActivity)) return false;
final ParcelableActivity activity = (ParcelableActivity) that;
return max_position == activity.max_position && min_position == activity.min_position;
}
@Override
public boolean equals(final Object that) {
if (!(that instanceof ParcelableActivity)) return false;
final ParcelableActivity activity = (ParcelableActivity) that;
return max_position == activity.max_position && min_position == activity.min_position;
}
@Override
public String toString() {
return "ParcelableActivity{account_id=" + account_id + ", activity_timestamp=" + activity_timestamp
+ ", max_position=" + max_position + ", min_position=" + min_position + ", action=" + action
+ ", sources=" + Arrays.toString(sources) + ", target_users=" + Arrays.toString(target_users)
+ ", target_statuses=" + Arrays.toString(target_statuses) + ", target_user_lists="
+ Arrays.toString(target_user_lists) + ", target_object_user_lists="
+ Arrays.toString(target_object_user_lists) + ", target_object_statuses="
+ Arrays.toString(target_object_statuses) + "}";
}
@Override
public String toString() {
return "ParcelableActivity{account_id=" + account_id + ", timestamp=" + timestamp
+ ", max_position=" + max_position + ", min_position=" + min_position + ", action=" + action
+ ", sources=" + Arrays.toString(sources) + ", target_users=" + Arrays.toString(target_users)
+ ", target_statuses=" + Arrays.toString(target_statuses) + ", target_user_lists="
+ Arrays.toString(target_user_lists) + ", target_object_user_lists="
+ Arrays.toString(target_object_user_lists) + ", target_object_statuses="
+ Arrays.toString(target_object_statuses) + "}";
}
@Override
public void writeToParcel(final JSONParcel out) {
out.writeLong("account_id", account_id);
out.writeLong("activity_timestamp", activity_timestamp);
out.writeLong("max_position", max_position);
out.writeLong("min_position", min_position);
out.writeInt("action", action);
out.writeParcelableArray("sources", sources);
out.writeParcelableArray("target_users", target_users);
out.writeParcelableArray("target_statuses", target_statuses);
out.writeParcelableArray("target_user_lists", target_user_lists);
out.writeParcelableArray("target_object_user_lists", target_object_user_lists);
out.writeParcelableArray("target_object_statuses", target_object_statuses);
}
@Override
public void writeToParcel(final JSONParcel out) {
out.writeLong("account_id", account_id);
out.writeLong("timestamp", timestamp);
out.writeLong("max_position", max_position);
out.writeLong("min_position", min_position);
out.writeInt("action", action);
out.writeParcelableArray("sources", sources);
out.writeParcelableArray("target_users", target_users);
out.writeParcelableArray("target_statuses", target_statuses);
out.writeParcelableArray("target_user_lists", target_user_lists);
out.writeParcelableArray("target_object_user_lists", target_object_user_lists);
out.writeParcelableArray("target_object_statuses", target_object_statuses);
}
private static long getTime(final Date date) {
return date != null ? date.getTime() : 0;
}
}

View File

@ -81,6 +81,7 @@ import org.mariotaku.twidere.util.SQLiteDatabaseWrapper;
import org.mariotaku.twidere.util.SQLiteDatabaseWrapper.LazyLoadCallback;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.TwidereQueryBuilder;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.collection.NoDuplicatesCopyOnWriteArrayList;
import org.mariotaku.twidere.util.message.UnreadCountUpdatedEvent;
@ -108,7 +109,7 @@ import static org.mariotaku.twidere.util.Utils.getAccountIds;
import static org.mariotaku.twidere.util.Utils.getAccountNotificationId;
import static org.mariotaku.twidere.util.Utils.getAccountScreenName;
import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.Utils.getNotificationUri;
import static org.mariotaku.twidere.util.Utils.getTableId;
import static org.mariotaku.twidere.util.Utils.getTableNameById;
@ -709,7 +710,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
contentIntent.putExtra(EXTRA_EXTRA_INTENT, statusIntent);
}
final String displayName = getDisplayName(context, firstItem.sender_id, firstItem.sender_name,
final String displayName = UserColorNameUtils.getDisplayName(context, firstItem.sender_id, firstItem.sender_name,
firstItem.sender_screen_name, mNameFirst, mNickOnly);
if (usersCount > 1) {
title = resources.getString(R.string.notification_direct_message_multiple_users, displayName,
@ -730,7 +731,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
for (int i = 0; i < max; i++) {
final ParcelableDirectMessage item = messages.get(i);
if (item == null) return;
final String nameEscaped = HtmlEscapeHelper.escape(getDisplayName(context, item.sender_id,
final String nameEscaped = HtmlEscapeHelper.escape(UserColorNameUtils.getDisplayName(context, item.sender_id,
item.sender_name, item.sender_name, mNameFirst, mNickOnly));
final String textEscaped = HtmlEscapeHelper.escape(stripMentionText(item.text_unescaped,
getAccountScreenName(context, item.account_id)));
@ -787,7 +788,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
contentIntent.putExtra(EXTRA_EXTRA_INTENT, statusIntent);
}
final String displayName = getDisplayName(context, firstItem.user_id, firstItem.user_name,
final String displayName = UserColorNameUtils.getDisplayName(context, firstItem.user_id, firstItem.user_name,
firstItem.user_screen_name, mNameFirst, mNickOnly);
if (usersCount > 1) {
title = resources.getString(titleMultiple, displayName, usersCount - 1);
@ -804,7 +805,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
for (int i = 0; i < max; i++) {
final ParcelableStatus s = safeGet(statuses, i);
if (s == null) return;
final String nameEscaped = HtmlEscapeHelper.escape(getDisplayName(context, s.user_id, s.user_name,
final String nameEscaped = HtmlEscapeHelper.escape(UserColorNameUtils.getDisplayName(context, s.user_id, s.user_name,
s.user_screen_name, mNameFirst, mNickOnly));
final String textEscaped = HtmlEscapeHelper.escape(stripMentionText(s.text_unescaped,
getAccountScreenName(context, s.account_id)));

View File

@ -0,0 +1,342 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.content.Context;
import android.graphics.PointF;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
/**
* {@link RecyclerView.SmoothScroller} implementation which uses
* {@link android.view.animation.LinearInterpolator} until the target position becames a child of
* the RecyclerView and then uses
* {@link android.view.animation.DecelerateInterpolator} to slowly approach to target position.
*/
abstract public class AccelerateSmoothScroller extends RecyclerView.SmoothScroller {
private static final String TAG = "LinearSmoothScroller";
private static final boolean DEBUG = false;
private static final float MILLISECONDS_PER_INCH = 25f;
private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000;
/**
* Align child view's left or top with parent view's left or top
*
* @see #calculateDtToFit(int, int, int, int, int)
* @see #calculateDxToMakeVisible(android.view.View, int)
* @see #calculateDyToMakeVisible(android.view.View, int)
*/
public static final int SNAP_TO_START = -1;
/**
* Align child view's right or bottom with parent view's right or bottom
*
* @see #calculateDtToFit(int, int, int, int, int)
* @see #calculateDxToMakeVisible(android.view.View, int)
* @see #calculateDyToMakeVisible(android.view.View, int)
*/
public static final int SNAP_TO_END = 1;
/**
* <p>Decides if the child should be snapped from start or end, depending on where it
* currently is in relation to its parent.</p>
* <p>For instance, if the view is virtually on the left of RecyclerView, using
* {@code SNAP_TO_ANY} is the same as using {@code SNAP_TO_START}</p>
*
* @see #calculateDtToFit(int, int, int, int, int)
* @see #calculateDxToMakeVisible(android.view.View, int)
* @see #calculateDyToMakeVisible(android.view.View, int)
*/
public static final int SNAP_TO_ANY = 0;
// Trigger a scroll to a further distance than TARGET_SEEK_SCROLL_DISTANCE_PX so that if target
// view is not laid out until interim target position is reached, we can detect the case before
// scrolling slows down and reschedule another interim target scroll
private static final float TARGET_SEEK_EXTRA_SCROLL_RATIO = 1.2f;
protected final AccelerateInterpolator mLinearInterpolator = new AccelerateInterpolator();
protected final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
protected PointF mTargetVector;
private final float MILLISECONDS_PER_PX;
// Temporary variables to keep track of the interim scroll target. These values do not
// point to a real item position, rather point to an estimated location pixels.
protected int mInterimTargetDx = 0, mInterimTargetDy = 0;
public AccelerateSmoothScroller(Context context, float factor) {
MILLISECONDS_PER_PX = calculateSpeedPerPixel(context.getResources().getDisplayMetrics()) * factor;
}
/**
* {@inheritDoc}
*/
@Override
protected void onStart() {
}
/**
* {@inheritDoc}
*/
@Override
protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
final int dx = calculateDxToMakeVisible(targetView, getHorizontalSnapPreference());
final int dy = calculateDyToMakeVisible(targetView, getVerticalSnapPreference());
final int distance = (int) Math.sqrt(dx * dx + dy * dy);
final int time = calculateTimeForDeceleration(distance);
if (time > 0) {
action.update(-dx, -dy, time, mDecelerateInterpolator);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void onSeekTargetStep(int dx, int dy, RecyclerView.State state, Action action) {
if (getChildCount() == 0) {
stop();
return;
}
if (DEBUG && mTargetVector != null
&& ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) {
throw new IllegalStateException("Scroll happened in the opposite direction"
+ " of the target. Some calculations are wrong");
}
mInterimTargetDx = clampApplyScroll(mInterimTargetDx, dx);
mInterimTargetDy = clampApplyScroll(mInterimTargetDy, dy);
if (mInterimTargetDx == 0 && mInterimTargetDy == 0) {
updateActionForInterimTarget(action);
} // everything is valid, keep going
}
/**
* {@inheritDoc}
*/
@Override
protected void onStop() {
mInterimTargetDx = mInterimTargetDy = 0;
mTargetVector = null;
}
/**
* Calculates the scroll speed.
*
* @param displayMetrics DisplayMetrics to be used for real dimension calculations
* @return The time (in ms) it should take for each pixel. For instance, if returned value is
* 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.
*/
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
/**
* <p>Calculates the time for deceleration so that transition from LinearInterpolator to
* DecelerateInterpolator looks smooth.</p>
*
* @param dx Distance to scroll
* @return Time for DecelerateInterpolator to smoothly traverse the distance when transitioning
* from LinearInterpolation
*/
protected int calculateTimeForDeceleration(int dx) {
// we want to cover same area with the linear interpolator for the first 10% of the
// interpolation. After that, deceleration will take control.
// area under curve (1-(1-x)^2) can be calculated as (1 - x/3) * x * x
// which gives 0.100028 when x = .3356
// this is why we divide linear scrolling time with .3356
return (int) Math.ceil(calculateTimeForScrolling(dx) / .3356);
}
/**
* Calculates the time it should take to scroll the given distance (in pixels)
*
* @param dx Distance in pixels that we want to scroll
* @return Time in milliseconds
* @see #calculateSpeedPerPixel(android.util.DisplayMetrics)
*/
protected int calculateTimeForScrolling(int dx) {
// In a case where dx is very small, rounding may return 0 although dx > 0.
// To avoid that issue, ceil the result so that if dx > 0, we'll always return positive
// time.
return (int) Math.ceil(Math.abs(dx) * MILLISECONDS_PER_PX);
}
/**
* When scrolling towards a child view, this method defines whether we should align the left
* or the right edge of the child with the parent RecyclerView.
*
* @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
* @see #SNAP_TO_START
* @see #SNAP_TO_END
* @see #SNAP_TO_ANY
*/
protected int getHorizontalSnapPreference() {
return mTargetVector == null || mTargetVector.x == 0 ? SNAP_TO_ANY :
mTargetVector.x > 0 ? SNAP_TO_END : SNAP_TO_START;
}
/**
* When scrolling towards a child view, this method defines whether we should align the top
* or the bottom edge of the child with the parent RecyclerView.
*
* @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
* @see #SNAP_TO_START
* @see #SNAP_TO_END
* @see #SNAP_TO_ANY
*/
protected int getVerticalSnapPreference() {
return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
}
/**
* When the target scroll position is not a child of the RecyclerView, this method calculates
* a direction vector towards that child and triggers a smooth scroll.
*
* @see #computeScrollVectorForPosition(int)
*/
protected void updateActionForInterimTarget(Action action) {
// find an interim target position
PointF scrollVector = computeScrollVectorForPosition(getTargetPosition());
if (scrollVector == null || (scrollVector.x == 0 && scrollVector.y == 0)) {
Log.e(TAG, "To support smooth scrolling, you should override \n"
+ "LayoutManager#computeScrollVectorForPosition.\n"
+ "Falling back to instant scroll");
final int target = getTargetPosition();
stop();
instantScrollToPosition(target);
return;
}
normalize(scrollVector);
mTargetVector = scrollVector;
mInterimTargetDx = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.x);
mInterimTargetDy = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.y);
final int time = calculateTimeForScrolling(TARGET_SEEK_SCROLL_DISTANCE_PX);
// To avoid UI hiccups, trigger a smooth scroll to a distance little further than the
// interim target. Since we track the distance travelled in onSeekTargetStep callback, it
// won't actually scroll more than what we need.
action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO)
, (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO)
, (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator);
}
private int clampApplyScroll(int tmpDt, int dt) {
final int before = tmpDt;
tmpDt -= dt;
if (before * tmpDt <= 0) { // changed sign, reached 0 or was 0, reset
return 0;
}
return tmpDt;
}
/**
* Helper method for {@link #calculateDxToMakeVisible(android.view.View, int)} and
* {@link #calculateDyToMakeVisible(android.view.View, int)}
*/
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int
snapPreference) {
switch (snapPreference) {
case SNAP_TO_START:
return boxStart - viewStart;
case SNAP_TO_END:
return boxEnd - viewEnd;
case SNAP_TO_ANY:
final int dtStart = boxStart - viewStart;
if (dtStart > 0) {
return dtStart;
}
final int dtEnd = boxEnd - viewEnd;
if (dtEnd < 0) {
return dtEnd;
}
break;
default:
throw new IllegalArgumentException("snap preference should be one of the"
+ " constants defined in SmoothScroller, starting with SNAP_");
}
return 0;
}
/**
* Calculates the vertical scroll amount necessary to make the given view fully visible
* inside the RecyclerView.
*
* @param view The view which we want to make fully visible
* @param snapPreference The edge which the view should snap to when entering the visible
* area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
* {@link #SNAP_TO_END}.
* @return The vertical scroll amount necessary to make the view visible with the given
* snap preference.
*/
public int calculateDyToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (!layoutManager.canScrollVertically()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
final int top = layoutManager.getDecoratedTop(view) - params.topMargin;
final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin;
final int start = layoutManager.getPaddingTop();
final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom();
return calculateDtToFit(top, bottom, start, end, snapPreference);
}
/**
* Calculates the horizontal scroll amount necessary to make the given view fully visible
* inside the RecyclerView.
*
* @param view The view which we want to make fully visible
* @param snapPreference The edge which the view should snap to when entering the visible
* area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
* {@link #SNAP_TO_END}
* @return The vertical scroll amount necessary to make the view visible with the given
* snap preference.
*/
public int calculateDxToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (!layoutManager.canScrollHorizontally()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
final int left = layoutManager.getDecoratedLeft(view) - params.leftMargin;
final int right = layoutManager.getDecoratedRight(view) + params.rightMargin;
final int start = layoutManager.getPaddingLeft();
final int end = layoutManager.getWidth() - layoutManager.getPaddingRight();
return calculateDtToFit(left, right, start, end, snapPreference);
}
abstract public PointF computeScrollVectorForPosition(int targetPosition);
}

View File

@ -700,7 +700,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final String message;
if (users.length == 1) {
final ParcelableUser user = users[0];
final String displayName = Utils.getDisplayName(mContext, user.id, user.name, user.screen_name);
final String displayName = UserColorNameUtils.getDisplayName(mContext, user.id, user.name, user.screen_name);
message = mContext.getString(R.string.added_user_to_list, displayName, result.getData().name);
} else {
final Resources res = mContext.getResources();
@ -1162,7 +1162,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
if (succeed) {
if (users.length == 1) {
final ParcelableUser user = users[0];
final String displayName = Utils.getDisplayName(mContext, user.id, user.name, user.screen_name);
final String displayName = UserColorNameUtils.getDisplayName(mContext, user.id, user.name, user.screen_name);
message = mContext.getString(R.string.deleted_user_from_list, displayName, result.getData().name);
} else {
final Resources res = mContext.getResources();

View File

@ -0,0 +1,47 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.support.v4.app.Fragment;
import org.mariotaku.twidere.fragment.support.SupportBrowserFragment;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity.ParcelableValueItem;
/**
* Created by mariotaku on 15/1/1.
*/
public abstract class TwitterCardFragmentFactory {
public abstract Fragment createAnimatedGifFragment(ParcelableCardEntity card);
public abstract Fragment createAudioFragment(ParcelableCardEntity card);
public abstract Fragment createPlayerFragment(ParcelableCardEntity card);
public static TwitterCardFragmentFactory getInstance() {
return new TwitterCardFragmentFactoryImpl();
}
public static Fragment createGenericPlayerFragment(ParcelableCardEntity card) {
final ParcelableValueItem player_url = ParcelableCardEntity.getValue(card, "player_url");
return SupportBrowserFragment.show((String) player_url.value);
}
}

View File

@ -0,0 +1,71 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.graphics.Point;
import android.support.v4.app.Fragment;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity.ParcelableValueItem;
/**
* Created by mariotaku on 15/1/1.
*/
public class TwitterCardUtils {
private static final TwitterCardFragmentFactory sFactory = TwitterCardFragmentFactory.getInstance();
public static Fragment createCardFragment(ParcelableCardEntity card) {
if ("player".equals(card.name)) {
final Fragment playerFragment = sFactory.createPlayerFragment(card);
if (playerFragment != null) return playerFragment;
return TwitterCardFragmentFactory.createGenericPlayerFragment(card);
} else if ("audio".equals(card.name)) {
final Fragment playerFragment = sFactory.createAudioFragment(card);
if (playerFragment != null) return playerFragment;
return TwitterCardFragmentFactory.createGenericPlayerFragment(card);
} else if ("animated_gif".equals(card.name)) {
final Fragment playerFragment = sFactory.createAnimatedGifFragment(card);
if (playerFragment != null) return playerFragment;
return TwitterCardFragmentFactory.createGenericPlayerFragment(card);
}
return null;
}
public static Point getCardSize(ParcelableCardEntity card) {
final ParcelableValueItem player_width = ParcelableCardEntity.getValue(card, "player_width");
final ParcelableValueItem player_height = ParcelableCardEntity.getValue(card, "player_height");
if (player_width != null && player_height != null) {
final int width = ParseUtils.parseInt(String.valueOf(player_width.value));
final int height = ParseUtils.parseInt(String.valueOf(player_height.value));
if (width > 0 && height > 0) {
return new Point(width, height);
}
}
return null;
}
public static boolean isCardSupported(ParcelableCardEntity card) {
if (card == null) return false;
return "player".equals(card.name) || "audio".equals(card.name) || "animated_gif".equals(card.name);
}
}

View File

@ -0,0 +1,242 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.graphics.Color;
import android.support.v4.util.LongSparseArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import java.util.Map;
import static android.text.TextUtils.isEmpty;
public class UserColorNameUtils implements TwidereConstants {
private static LongSparseArray<Integer> sUserColors = new LongSparseArray<>();
private static LongSparseArray<String> sUserNicknames = new LongSparseArray<>();
private UserColorNameUtils() {
throw new AssertionError();
}
public static void clearUserColor(final Context context, final long user_id) {
if (context == null) return;
sUserColors.remove(user_id);
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.remove(Long.toString(user_id));
editor.apply();
}
public static void clearUserNickname(final Context context, final long user_id) {
if (context == null) return;
sUserNicknames.remove(user_id);
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.remove(Long.toString(user_id));
editor.apply();
}
public static String getDisplayName(final Context context, final long userId, final String name,
final String screenName) {
return getDisplayName(context, userId, name, screenName, false);
}
public static String getDisplayName(final Context context, final ParcelableUser user) {
return getDisplayName(context, user, false);
}
public static String getDisplayName(final Context context, final ParcelableUser user, final boolean ignoreCache) {
return getDisplayName(context, user.id, user.name, user.screen_name, ignoreCache);
}
public static String getDisplayName(final Context context, final long userId, final String name,
final String screenName, final boolean ignoreCache) {
if (context == null) return null;
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final boolean nameFirst = prefs.getBoolean(KEY_NAME_FIRST, true);
final boolean nicknameOnly = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
.getBoolean(KEY_NICKNAME_ONLY, false);
return getDisplayName(context, userId, name, screenName, nameFirst, nicknameOnly, ignoreCache);
}
public static String getDisplayName(final Context context, final long user_id, final String name,
final String screen_name, final boolean name_first, final boolean nickname_only) {
return getDisplayName(context, user_id, name, screen_name, name_first, nickname_only, false);
}
public static String getDisplayName(final Context context, final ParcelableUser user,
final boolean nameFirst, final boolean nicknameOnly,
final boolean ignoreCache) {
return getDisplayName(context, user.id, user.name, user.screen_name,
nameFirst, nicknameOnly, ignoreCache);
}
public static String getDisplayName(final Context context, final ParcelableStatus status,
final boolean nameFirst, final boolean nicknameOnly,
final boolean ignoreCache) {
return getDisplayName(context, status.user_id, status.user_name, status.user_screen_name,
nameFirst, nicknameOnly, ignoreCache);
}
public static String getDisplayName(final Context context, final long userId, final String name,
final String screenName, final boolean nameFirst,
final boolean nicknameOnly, final boolean ignoreCache) {
if (context == null) return null;
final String nick = getUserNickname(context, userId, ignoreCache);
final boolean nick_available = !isEmpty(nick);
if (nicknameOnly && nick_available) return nick;
if (!nick_available) return nameFirst && !isEmpty(name) ? name : "@" + screenName;
return context.getString(R.string.name_with_nickname, nameFirst && !isEmpty(name) ? name : "@" + screenName,
nick);
}
public static int getUserColor(final Context context, final long user_id) {
return getUserColor(context, user_id, false);
}
public static int getUserColor(final Context context, final long userId, final boolean ignoreCache) {
if (context == null || userId == -1) return Color.TRANSPARENT;
if (!ignoreCache && sUserColors.indexOfKey(userId) >= 0) return sUserColors.get(userId);
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int color = prefs.getInt(Long.toString(userId), Color.TRANSPARENT);
sUserColors.put(userId, color);
return color;
}
public static String getUserNickname(final Context context, final long userId) {
return getUserNickname(context, userId, false);
}
public static String getUserNickname(final Context context, final long userId, final boolean ignoreCache) {
if (context == null || userId == -1) return null;
if (!ignoreCache && LongSparseArrayUtils.hasKey(sUserNicknames, userId))
return sUserNicknames.get(userId);
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
final String nickname = prefs.getString(Long.toString(userId), null);
sUserNicknames.put(userId, nickname);
return nickname;
}
public static String getUserNickname(final Context context, final long user_id, final String name) {
final String nick = getUserNickname(context, user_id);
if (isEmpty(nick)) return name;
final boolean nickname_only = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
.getBoolean(KEY_NICKNAME_ONLY, false);
return nickname_only ? nick : context.getString(R.string.name_with_nickname, name, nick);
}
public static void initUserColor(final Context context) {
if (context == null) return;
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
for (final Map.Entry<String, ?> entry : prefs.getAll().entrySet()) {
sUserColors.put(ParseUtils.parseLong(entry.getKey()),
ParseUtils.parseInt(ParseUtils.parseString(entry.getValue())));
}
}
public static void registerOnUserColorChangedListener(final Context context,
final OnUserColorChangedListener listener) {
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
prefs.registerOnSharedPreferenceChangeListener(new OnColorPreferenceChangeListener(listener));
}
public static void registerOnUserNicknameChangedListener(final Context context,
final OnUserNicknameChangedListener listener) {
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
prefs.registerOnSharedPreferenceChangeListener(new OnNickPreferenceChangeListener(listener));
}
public static void setUserColor(final Context context, final long user_id, final int color) {
if (context == null || user_id == -1) return;
sUserColors.put(user_id, color);
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.putInt(String.valueOf(user_id), color);
editor.apply();
}
public static void setUserNickname(final Context context, final long user_id, final String nickname) {
if (context == null || user_id == -1) return;
sUserNicknames.put(user_id, nickname);
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.putString(String.valueOf(user_id), nickname);
editor.apply();
}
public static interface OnUserColorChangedListener {
void onUserColorChanged(long userId, int color);
}
public static interface OnUserNicknameChangedListener {
void onUserNicknameChanged(long userId, String nick);
}
private static final class OnColorPreferenceChangeListener implements OnSharedPreferenceChangeListener {
private final OnUserColorChangedListener mListener;
OnColorPreferenceChangeListener(final OnUserColorChangedListener listener) {
mListener = listener;
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
final long userId = ParseUtils.parseLong(key, -1);
if (mListener != null) {
mListener.onUserColorChanged(userId, sharedPreferences.getInt(key, 0));
}
}
}
private static final class OnNickPreferenceChangeListener implements OnSharedPreferenceChangeListener {
private final OnUserNicknameChangedListener mListener;
OnNickPreferenceChangeListener(final OnUserNicknameChangedListener listener) {
mListener = listener;
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
final long userId = ParseUtils.parseLong(key, -1);
if (mListener != null) {
mListener.onUserNicknameChanged(userId, sharedPreferences.getString(key, null));
}
}
}
}

View File

@ -1,184 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import static android.text.TextUtils.isEmpty;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.graphics.Color;
import android.support.v4.util.LongSparseArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.TwidereConstants;
import java.util.Map;
public class UserColorNicknameUtils implements TwidereConstants {
private static LongSparseArray<Integer> sUserColors = new LongSparseArray<Integer>();
private static LongSparseArray<String> sUserNicknames = new LongSparseArray<String>();
private UserColorNicknameUtils() {
throw new AssertionError();
}
public static void clearUserColor(final Context context, final long user_id) {
if (context == null) return;
sUserColors.remove(user_id);
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.remove(Long.toString(user_id));
editor.commit();
}
public static void clearUserNickname(final Context context, final long user_id) {
if (context == null) return;
sUserNicknames.remove(user_id);
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.remove(Long.toString(user_id));
editor.commit();
}
public static int getUserColor(final Context context, final long user_id) {
return getUserColor(context, user_id, false);
}
public static int getUserColor(final Context context, final long user_id, final boolean ignore_cache) {
if (context == null || user_id == -1) return Color.TRANSPARENT;
if (!ignore_cache && sUserColors.indexOfKey(user_id) >= 0) return sUserColors.get(user_id);
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
final int color = prefs.getInt(Long.toString(user_id), Color.TRANSPARENT);
sUserColors.put(user_id, color);
return color;
}
public static String getUserNickname(final Context context, final long user_id) {
return getUserNickname(context, user_id, false);
}
public static String getUserNickname(final Context context, final long user_id, final boolean ignore_cache) {
if (context == null || user_id == -1) return null;
if (!ignore_cache && LongSparseArrayUtils.hasKey(sUserNicknames, user_id)) return sUserNicknames.get(user_id);
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
final String nickname = prefs.getString(Long.toString(user_id), null);
sUserNicknames.put(user_id, nickname);
return nickname;
}
public static String getUserNickname(final Context context, final long user_id, final String name) {
final String nick = getUserNickname(context, user_id);
if (isEmpty(nick)) return name;
final boolean nickname_only = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
.getBoolean(KEY_NICKNAME_ONLY, false);
return nickname_only ? nick : context.getString(R.string.name_with_nickname, name, nick);
}
public static void initUserColor(final Context context) {
if (context == null) return;
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
for (final Map.Entry<String, ?> entry : prefs.getAll().entrySet()) {
sUserColors.put(ParseUtils.parseLong(entry.getKey()),
ParseUtils.parseInt(ParseUtils.parseString(entry.getValue())));
}
}
public static void registerOnUserColorChangedListener(final Context context,
final OnUserColorChangedListener listener) {
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
prefs.registerOnSharedPreferenceChangeListener(new OnColorPreferenceChangeListener(listener));
}
public static void registerOnUserNicknameChangedListener(final Context context,
final OnUserNicknameChangedListener listener) {
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
prefs.registerOnSharedPreferenceChangeListener(new OnNickPreferenceChangeListener(listener));
}
public static void setUserColor(final Context context, final long user_id, final int color) {
if (context == null || user_id == -1) return;
sUserColors.put(user_id, color);
final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.putInt(String.valueOf(user_id), color);
editor.commit();
}
public static void setUserNickname(final Context context, final long user_id, final String nickname) {
if (context == null || user_id == -1) return;
sUserNicknames.put(user_id, nickname);
final SharedPreferences prefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.putString(String.valueOf(user_id), nickname);
editor.commit();
}
public static interface OnUserColorChangedListener {
void onUserColorChanged(long userId, int color);
}
public static interface OnUserNicknameChangedListener {
void onUserNicknameChanged(long userId, String nick);
}
private static final class OnColorPreferenceChangeListener implements OnSharedPreferenceChangeListener {
private final OnUserColorChangedListener mListener;
OnColorPreferenceChangeListener(final OnUserColorChangedListener listener) {
mListener = listener;
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
final long userId = ParseUtils.parseLong(key, -1);
if (mListener != null) {
mListener.onUserColorChanged(userId, sharedPreferences.getInt(key, 0));
}
}
}
private static final class OnNickPreferenceChangeListener implements OnSharedPreferenceChangeListener {
private final OnUserNicknameChangedListener mListener;
OnNickPreferenceChangeListener(final OnUserNicknameChangedListener listener) {
mListener = listener;
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
final long userId = ParseUtils.parseLong(key, -1);
if (mListener != null) {
mListener.onUserNicknameChanged(userId, sharedPreferences.getString(key, null));
}
}
}
}

View File

@ -101,12 +101,6 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.OnInitializedListener;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import com.google.android.youtube.player.YouTubePlayerSupportFragment;
import org.apache.http.NameValuePair;
import org.json.JSONException;
import org.mariotaku.gallery3d.ImageViewerGLActivity;
@ -166,8 +160,6 @@ import org.mariotaku.twidere.model.ParcelableAccount.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.model.ParcelableLocation;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableStatus.ParcelableCardEntity.ParcelableValueItem;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.model.TwidereParcelable;
@ -1684,45 +1676,6 @@ public final class Utils implements Constants, TwitterConstants {
return getTwitterInstance(context, getDefaultAccountId(context), includeEntities, includeRetweets, apacheHttp);
}
public static String getDisplayName(final Context context, final long userId, final String name,
final String screenName) {
return getDisplayName(context, userId, name, screenName, false);
}
public static String getDisplayName(final Context context, final ParcelableUser user) {
return getDisplayName(context, user, false);
}
public static String getDisplayName(final Context context, final ParcelableUser user, final boolean ignoreCache) {
return getDisplayName(context, user.id, user.name, user.screen_name, ignoreCache);
}
public static String getDisplayName(final Context context, final long userId, final String name,
final String screenName, final boolean ignoreCache) {
if (context == null) return null;
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final boolean nameFirst = prefs.getBoolean(KEY_NAME_FIRST, true);
final boolean nicknameOnly = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
.getBoolean(KEY_NICKNAME_ONLY, false);
return getDisplayName(context, userId, name, screenName, nameFirst, nicknameOnly, ignoreCache);
}
public static String getDisplayName(final Context context, final long user_id, final String name,
final String screen_name, final boolean name_first, final boolean nickname_only) {
return getDisplayName(context, user_id, name, screen_name, name_first, nickname_only, false);
}
public static String getDisplayName(final Context context, final long user_id, final String name,
final String screen_name, final boolean name_first, final boolean nickname_only, final boolean ignore_cache) {
if (context == null) return null;
final String nick = UserColorNicknameUtils.getUserNickname(context, user_id, ignore_cache);
final boolean nick_available = !isEmpty(nick);
if (nickname_only && nick_available) return nick;
if (!nick_available) return name_first && !isEmpty(name) ? name : "@" + screen_name;
return context.getString(R.string.name_with_nickname, name_first && !isEmpty(name) ? name : "@" + screen_name,
nick);
}
public static String getErrorMessage(final Context context, final CharSequence message) {
if (context == null) return ParseUtils.parseString(message);
if (isEmpty(message)) return context.getString(R.string.error_unknown_error);
@ -2593,17 +2546,17 @@ public final class Utils implements Constants, TwitterConstants {
public static String getUserName(final Context context, final ParcelableStatus status) {
if (context == null || status == null) return null;
return getDisplayName(context, status.user_id, status.user_name, status.user_screen_name);
return UserColorNameUtils.getDisplayName(context, status.user_id, status.user_name, status.user_screen_name);
}
public static String getUserName(final Context context, final ParcelableUser user) {
if (context == null || user == null) return null;
return getDisplayName(context, user.id, user.name, user.screen_name);
return UserColorNameUtils.getDisplayName(context, user.id, user.name, user.screen_name);
}
public static String getUserName(final Context context, final User user) {
if (context == null || user == null) return null;
return getDisplayName(context, user.getId(), user.getName(), user.getScreenName());
return UserColorNameUtils.getDisplayName(context, user.getId(), user.getName(), user.getScreenName());
}
public static int getUserTypeIconRes(final boolean isVerified, final boolean isProtected) {
@ -2676,32 +2629,6 @@ public final class Utils implements Constants, TwitterConstants {
return plugged || level / scale > 0.15f;
}
public static boolean isCardSupported(ParcelableCardEntity card) {
return card != null && "player".equals(card.name);
}
public static Fragment createTwitterCardFragment(ParcelableCardEntity card) {
if ("player".equals(card.name)) {
final ParcelableValueItem player_url = ParcelableCardEntity.getValue(card, "player_url");
final YouTubePlayerSupportFragment fragment = YouTubePlayerSupportFragment.newInstance();
fragment.initialize("AIzaSyCVdCIMFFxdNqHnCPrJ9yKUzoTfs8jhYGc", new OnInitializedListener() {
@Override
public void onInitializationSuccess(Provider provider, YouTubePlayer player, boolean b) {
final String url = (String) player_url.value;
final String id = url.substring(url.lastIndexOf('/') + 1);
player.cueVideo(id);
}
@Override
public void onInitializationFailure(Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
}
});
return fragment;
}
return null;
}
public static boolean isCompactCards(final Context context) {
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
return prefs != null && prefs.getBoolean(KEY_COMPACT_CARDS, false);
@ -3895,6 +3822,18 @@ public final class Utils implements Constants, TwitterConstants {
return in.size() != out.size();
}
public static boolean truncateActivities(final List<twitter4j.Activity> in, final List<twitter4j.Activity> out,
final long sinceId) {
if (in == null) return false;
for (final twitter4j.Activity status : in) {
if (sinceId > 0 && status.getMaxPosition() <= sinceId) {
continue;
}
out.add(status);
}
return in.size() != out.size();
}
private static Drawable getMetadataDrawable(final PackageManager pm, final ActivityInfo info, final String key) {
if (pm == null || info == null || info.metaData == null || key == null || !info.metaData.containsKey(key))
return null;

View File

@ -36,6 +36,14 @@ public final class ViewAccessor {
}
}
public static boolean isInLayout(View view) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
return false;
} else {
return ViewAccessorJBMR2.isInLayout(view);
}
}
@SuppressWarnings("deprecation")
public static void setBackground(final View view, final Drawable background) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
@ -78,6 +86,14 @@ public final class ViewAccessor {
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
static class ViewAccessorJBMR2 {
static boolean isInLayout(final View view) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return false;
return view.isInLayout();
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
static class ViewAccessorL {
static void setBackgroundTintList(final View view, final ColorStateList list) {

View File

@ -19,8 +19,6 @@
package org.mariotaku.twidere.util.webkit;
import static org.mariotaku.twidere.util.Utils.showErrorMessage;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
@ -29,56 +27,52 @@ import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.support.annotation.NonNull;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import org.mariotaku.twidere.activity.support.BaseSupportActivity;
import org.mariotaku.twidere.fragment.BaseWebViewFragment;
import static org.mariotaku.twidere.util.Utils.showErrorMessage;
public class DefaultWebViewClient extends WebViewClient {
private final Activity mActivity;
private final SharedPreferences mPreferences;
private final Activity mActivity;
private final SharedPreferences mPreferences;
public DefaultWebViewClient(final Activity activity) {
mActivity = activity;
mPreferences = activity.getSharedPreferences(BaseWebViewFragment.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
public DefaultWebViewClient(final Activity activity) {
mActivity = activity;
mPreferences = activity.getSharedPreferences(BaseWebViewFragment.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
@Override
public void onPageFinished(final WebView view, final String url) {
super.onPageFinished(view, url);
if (mActivity instanceof BaseSupportActivity) {
mActivity.setTitle(view.getTitle());
((BaseSupportActivity) mActivity).setProgressBarIndeterminateVisibility(false);
}
}
@Override
public void onPageFinished(final WebView view, final String url) {
super.onPageFinished(view, url);
}
@Override
public void onPageStarted(final WebView view, final String url, final Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (mActivity instanceof BaseSupportActivity) {
((BaseSupportActivity) mActivity).setProgressBarIndeterminateVisibility(true);
}
}
@Override
public void onPageStarted(final WebView view, final String url, final Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
@Override
public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) {
if (mPreferences.getBoolean(BaseWebViewFragment.KEY_IGNORE_SSL_ERROR, false)) {
handler.proceed();
} else {
handler.cancel();
}
}
@Override
public void onReceivedSslError(final WebView view, @NonNull final SslErrorHandler handler,
final SslError error) {
if (mPreferences.getBoolean(BaseWebViewFragment.KEY_IGNORE_SSL_ERROR, false)) {
handler.proceed();
} else {
handler.cancel();
}
}
@Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
try {
mActivity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
} catch (final ActivityNotFoundException e) {
showErrorMessage(mActivity, null, e, false);
}
return true;
}
@Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
try {
mActivity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
} catch (final ActivityNotFoundException e) {
showErrorMessage(mActivity, null, e, false);
}
return true;
}
}

View File

@ -0,0 +1,69 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import org.mariotaku.twidere.util.accessor.ViewAccessor;
/**
* Created by mariotaku on 15/1/1.
*/
public class TwitterCardContainer extends FrameLayout {
private int mCardWidth, mCardHeight;
public TwitterCardContainer(Context context) {
super(context);
}
public TwitterCardContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TwitterCardContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setCardSize(int width, int height) {
mCardWidth = width;
mCardHeight = height;
if (!ViewAccessor.isInLayout(this)) {
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
final int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
final int height;
if (mCardWidth != 0 && mCardHeight != 0) {
height = Math.round(measuredWidth * (mCardHeight / (float) mCardWidth));
} else {
height = measuredHeight;
}
final int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY);
final int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
}
}

View File

@ -0,0 +1,158 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.view.holder;
import android.content.Context;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.AbsActivitiesAdapter;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.UserColorNameUtils;
/**
* Created by mariotaku on 15/1/3.
*/
public class ActivityTitleSummaryViewHolder extends ViewHolder {
private final AbsActivitiesAdapter adapter;
private final ImageView activityTypeView;
private final TextView titleView;
private final TextView summaryView;
private final ViewGroup profileImagesContainer;
private final TextView profileImageMoreNumber;
private final ImageView[] profileImageViews;
public ActivityTitleSummaryViewHolder(AbsActivitiesAdapter adapter, View itemView) {
super(itemView);
this.adapter = adapter;
activityTypeView = (ImageView) itemView.findViewById(R.id.activity_type);
titleView = (TextView) itemView.findViewById(R.id.title);
summaryView = (TextView) itemView.findViewById(R.id.summary);
profileImagesContainer = (ViewGroup) itemView.findViewById(R.id.profile_images_container);
profileImageViews = new ImageView[5];
profileImageViews[0] = (ImageView) itemView.findViewById(R.id.activity_profile_image_0);
profileImageViews[1] = (ImageView) itemView.findViewById(R.id.activity_profile_image_1);
profileImageViews[2] = (ImageView) itemView.findViewById(R.id.activity_profile_image_2);
profileImageViews[3] = (ImageView) itemView.findViewById(R.id.activity_profile_image_3);
profileImageViews[4] = (ImageView) itemView.findViewById(R.id.activity_profile_image_4);
profileImageMoreNumber = (TextView) itemView.findViewById(R.id.activity_profile_image_more_number);
}
public void displayActivity(ParcelableActivity activity) {
final Context context = adapter.getContext();
switch (activity.action) {
case ParcelableActivity.ACTION_FOLLOW: {
activityTypeView.setImageResource(R.drawable.ic_indicator_followers);
final String firstDisplayName = UserColorNameUtils.getDisplayName(context,
activity.sources[0]);
if (activity.sources.length > 1) {
titleView.setText(context.getString(R.string.activity_about_me_follow_multi,
firstDisplayName, activity.sources.length - 1));
} else {
titleView.setText(context.getString(R.string.activity_about_me_follow,
firstDisplayName));
}
displayUserProfileImages(activity.sources);
summaryView.setVisibility(View.GONE);
break;
}
case ParcelableActivity.ACTION_FAVORITE: {
activityTypeView.setImageResource(R.drawable.ic_indicator_starred);
final String firstDisplayName = UserColorNameUtils.getDisplayName(context,
activity.sources[0]);
if (activity.sources.length > 1) {
titleView.setText(context.getString(R.string.activity_about_me_favorite_multi,
firstDisplayName, activity.sources.length - 1));
} else {
titleView.setText(context.getString(R.string.activity_about_me_favorite,
firstDisplayName));
}
displayUserProfileImages(activity.sources);
summaryView.setText(activity.target_statuses[0].text_unescaped);
summaryView.setVisibility(View.VISIBLE);
break;
}
case ParcelableActivity.ACTION_RETWEET: {
activityTypeView.setImageResource(R.drawable.ic_indicator_retweet);
final String firstDisplayName = UserColorNameUtils.getDisplayName(context,
activity.sources[0]);
if (activity.sources.length > 1) {
titleView.setText(context.getString(R.string.activity_about_me_retweet_multi,
firstDisplayName, activity.sources.length - 1));
} else {
titleView.setText(context.getString(R.string.activity_about_me_retweet,
firstDisplayName));
}
displayUserProfileImages(activity.sources);
summaryView.setText(activity.target_statuses[0].text_unescaped);
summaryView.setVisibility(View.VISIBLE);
break;
}
}
}
public void setTextSize(float textSize) {
titleView.setTextSize(textSize);
summaryView.setTextSize(textSize * 0.85f);
}
private void displayUserProfileImages(final ParcelableUser[] statuses) {
final ImageLoaderWrapper imageLoader = adapter.getImageLoader();
if (statuses == null) {
for (final ImageView view : profileImageViews) {
imageLoader.cancelDisplayTask(view);
view.setVisibility(View.GONE);
}
return;
}
final int length = Math.min(profileImageViews.length, statuses.length);
final boolean shouldDisplayImages = true;
profileImagesContainer.setVisibility(shouldDisplayImages ? View.VISIBLE : View.GONE);
if (!shouldDisplayImages) return;
for (int i = 0, j = profileImageViews.length; i < j; i++) {
final ImageView view = profileImageViews[i];
view.setImageDrawable(null);
if (i < length) {
view.setVisibility(View.VISIBLE);
imageLoader.displayProfileImage(view, statuses[i].profile_image_url);
} else {
imageLoader.cancelDisplayTask(view);
view.setVisibility(View.GONE);
}
}
if (statuses.length > profileImageViews.length) {
final Context context = adapter.getContext();
final int moreNumber = statuses.length - profileImageViews.length;
profileImageMoreNumber.setVisibility(View.VISIBLE);
profileImageMoreNumber.setText(context.getString(R.string.and_more, moreNumber));
} else {
profileImageMoreNumber.setVisibility(View.GONE);
}
}
}

View File

@ -29,10 +29,11 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.ShortTimeView;
import static org.mariotaku.twidere.util.Utils.getDisplayName;
import static org.mariotaku.twidere.util.UserColorNameUtils.getDisplayName;
import static org.mariotaku.twidere.util.Utils.getStatusTypeIconRes;
import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;
@ -124,14 +125,14 @@ public class StatusListViewHolder extends CardViewHolder {
}
public void setReplyTo(final long user_id, final String name, final String screen_name) {
final String display_name = getDisplayName(getContext(), user_id, name, screen_name, name_first, nickname_only,
final String display_name = UserColorNameUtils.getDisplayName(getContext(), user_id, name, screen_name, name_first, nickname_only,
false);
reply_retweet_status.setText(getString(R.string.in_reply_to_name, display_name));
reply_retweet_status.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_indicator_conversation, 0, 0, 0);
}
public void setRetweetedBy(final long count, final long user_id, final String name, final String screen_name) {
final String display_name = getDisplayName(getContext(), user_id, name, screen_name, name_first, nickname_only,
final String display_name = UserColorNameUtils.getDisplayName(getContext(), user_id, name, screen_name, name_first, nickname_only,
false);
reply_retweet_status.setText(count > 1 ? getString(R.string.retweeted_by_name_with_count, display_name, count - 1)
: getString(R.string.retweeted_by_name, display_name));

View File

@ -19,7 +19,7 @@ import org.mariotaku.twidere.model.ParcelableStatus.CursorIndices;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.UserColorNicknameUtils;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.CardMediaContainer;
import org.mariotaku.twidere.view.ShapedImageView;
@ -87,7 +87,10 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
}
public void setupViewOptions() {
final float textSize = adapter.getTextSize();
setTextSize(adapter.getTextSize());
}
public void setTextSize(final float textSize) {
nameView.setTextSize(textSize);
textView.setTextSize(textSize);
screenNameView.setTextSize(textSize * 0.85f);
@ -139,7 +142,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
screenNameView.setText("@" + status.user_screen_name);
timeView.setTime(status.timestamp);
final int userColor = UserColorNicknameUtils.getUserColor(context, status.user_id);
final int userColor = UserColorNameUtils.getUserColor(context, status.user_id);
profileImageView.setBorderColor(userColor);
profileImageView.setStyle(profileImageStyle);
@ -250,7 +253,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
screenNameView.setText("@" + user_screen_name);
timeView.setTime(timestamp);
final int userColor = UserColorNicknameUtils.getUserColor(context, user_id);
final int userColor = UserColorNameUtils.getUserColor(context, user_id);
profileImageView.setBorderColor(userColor);
profileImageView.setStyle(adapter.getProfileImageStyle());

View File

@ -5,62 +5,67 @@ import java.util.Date;
public interface Activity extends TwitterResponse, Comparable<Activity>, Serializable {
public Action getAction();
public Action getAction();
public Date getCreatedAt();
public Date getCreatedAt();
public long getMaxPosition();
public long getMaxPosition();
public long getMinPosition();
public long getMinPosition();
public User[] getSources();
public User[] getSources();
public int getSourcesSize();
public int getSourcesSize();
public int getTargetObjectsSize();
public int getTargetObjectsSize();
public Status[] getTargetObjectStatuses();
public Status[] getTargetObjectStatuses();
public UserList[] getTargetObjectUserLists();
public UserList[] getTargetObjectUserLists();
public int getTargetsSize();
public int getTargetsSize();
public Status[] getTargetStatuses();
public Status[] getTargetStatuses();
public UserList[] getTargetUserLists();
public UserList[] getTargetUserLists();
public User[] getTargetUsers();
public User[] getTargetUsers();
public static enum Action implements Serializable {
FAVORITE(0x1), FOLLOW(0x2), MENTION(0x3), REPLY(0x4), RETWEET(0x5), LIST_MEMBER_ADDED(0x06), LIST_CREATED(0x07);
public static enum Action implements Serializable {
FAVORITE(0x1), FOLLOW(0x2), MENTION(0x3), REPLY(0x4), RETWEET(0x5), LIST_MEMBER_ADDED(0x06),
LIST_CREATED(0x07), FAVORITED_RETWEET(0x08), RETWEETED_RETWEET(0x09);
public final static int ACTION_FAVORITE = 0x01;
public final static int ACTION_FOLLOW = 0x02;
public final static int ACTION_MENTION = 0x03;
public final static int ACTION_REPLY = 0x04;
public final static int ACTION_RETWEET = 0x05;
public final static int ACTION_LIST_MEMBER_ADDED = 0x06;
public final static int ACTION_LIST_CREATED = 0x07;
public final static int ACTION_FAVORITE = 0x01;
public final static int ACTION_FOLLOW = 0x02;
public final static int ACTION_MENTION = 0x03;
public final static int ACTION_REPLY = 0x04;
public final static int ACTION_RETWEET = 0x05;
public final static int ACTION_LIST_MEMBER_ADDED = 0x06;
public final static int ACTION_LIST_CREATED = 0x07;
public final static int ACTION_FAVORITED_RETWEET = 0x08;
public final static int ACTION_RETWEETED_RETWEET = 0x09;
private final int actionId;
private final int actionId;
private Action(final int action) {
actionId = action;
}
private Action(final int action) {
actionId = action;
}
public int getActionId() {
return actionId;
}
public int getActionId() {
return actionId;
}
public static Action fromString(final String string) {
if ("favorite".equalsIgnoreCase(string)) return FAVORITE;
if ("follow".equalsIgnoreCase(string)) return FOLLOW;
if ("mention".equalsIgnoreCase(string)) return MENTION;
if ("reply".equalsIgnoreCase(string)) return REPLY;
if ("retweet".equalsIgnoreCase(string)) return RETWEET;
if ("list_member_added".equalsIgnoreCase(string)) return LIST_MEMBER_ADDED;
if ("list_created".equalsIgnoreCase(string)) return LIST_CREATED;
throw new IllegalArgumentException("Unknown action " + string);
}
}
public static Action fromString(final String string) {
if ("favorite".equalsIgnoreCase(string)) return FAVORITE;
if ("follow".equalsIgnoreCase(string)) return FOLLOW;
if ("mention".equalsIgnoreCase(string)) return MENTION;
if ("reply".equalsIgnoreCase(string)) return REPLY;
if ("retweet".equalsIgnoreCase(string)) return RETWEET;
if ("list_member_added".equalsIgnoreCase(string)) return LIST_MEMBER_ADDED;
if ("list_created".equalsIgnoreCase(string)) return LIST_CREATED;
if ("favorited_retweet".equalsIgnoreCase(string)) return FAVORITED_RETWEET;
if ("retweeted_retweet".equalsIgnoreCase(string)) return RETWEETED_RETWEET;
throw new IllegalArgumentException("Unknown action " + string);
}
}
}

View File

@ -83,6 +83,8 @@
android:layout_height="@dimen/icon_size_profile_type"
android:layout_alignBottom="@id/profile_image"
android:layout_alignRight="@id/profile_image"
android:layout_marginBottom="-8dp"
android:layout_marginRight="-8dp"
android:scaleType="fitCenter"/>
<LinearLayout
@ -109,20 +111,20 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
tools:text="User"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
android:textStyle="bold"
tools:text="User"/>
<TextView
android:id="@+id/screen_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="\@user"
android:layout_marginLeft="@dimen/element_spacing_small"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"/>
android:textSize="10sp"
tools:text="\@user"/>
</LinearLayout>
<org.mariotaku.twidere.view.ShortTimeView
@ -170,11 +172,11 @@
android:layout_below="@id/media_preview_container"
android:layout_marginBottom="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_normal"
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam faucibus quis purus ac malesuada. Duis id vulputate magna, a eleifend amet."
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
android:textColor="?android:attr/textColorPrimary"
tools:text="@string/sample_status_text"/>
<HorizontalScrollView
android:id="@+id/action_buttons"

View File

@ -22,6 +22,7 @@
android:id="@+id/item_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
@ -101,6 +102,7 @@
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
@ -110,6 +112,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_small"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"/>
@ -140,7 +143,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
android:textColor="?android:attr/textColorPrimary"
tools:text="@string/sample_status_text"/>
</LinearLayout>

View File

@ -23,8 +23,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="@+id/card"
@ -170,11 +169,10 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="true"/>
<FrameLayout
<org.mariotaku.twidere.view.TwitterCardContainer
android:id="@+id/twitter_card"
android:layout_width="match_parent"
android:minHeight="200dp"
android:layout_height="wrap_content"></FrameLayout>
android:layout_height="wrap_content"/>
<RelativeLayout
android:id="@+id/location_container"

View File

@ -134,6 +134,7 @@
android:padding="@dimen/element_spacing_small"
android:singleLine="true"
android:text="@string/description"
android:visibility="gone"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorPrimary"
@ -164,6 +165,7 @@
android:padding="@dimen/element_spacing_small"
android:singleLine="true"
android:text="@string/location"
android:visibility="gone"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorPrimary"
@ -193,6 +195,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/element_spacing_small"
android:visibility="gone"
android:singleLine="true"
android:text="@string/url"
android:textAllCaps="true"
@ -227,6 +230,7 @@
android:padding="@dimen/element_spacing_small"
android:singleLine="true"
android:text="@string/created_at"
android:visibility="gone"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorPrimary"

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ 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 <http://www.gnu.org/licenses/>.
-->
<RelativeLayout
android:id="@+id/item_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:orientation="horizontal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_normal">
<ImageView
android:id="@+id/activity_type"
android:layout_width="@dimen/element_spacing_large"
android:layout_height="@dimen/element_spacing_large"
android:layout_alignRight="@+id/profile_image"
android:layout_alignTop="@+id/profile_images_container"
android:scaleType="centerInside"
tools:src="@drawable/ic_indicator_retweet"/>
<LinearLayout
android:id="@+id/profile_images_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/profile_image"
android:gravity="center_vertical"
android:orientation="horizontal">
<org.mariotaku.twidere.view.ShapedImageView
android:id="@+id/activity_profile_image_0"
style="?profileImageStyle"
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"
tools:src="@drawable/ic_profile_image_default"/>
<org.mariotaku.twidere.view.ShapedImageView
android:id="@+id/activity_profile_image_1"
style="?profileImageStyle"
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"
tools:src="@drawable/ic_profile_image_default"/>
<org.mariotaku.twidere.view.ShapedImageView
android:id="@+id/activity_profile_image_2"
style="?profileImageStyle"
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"
tools:src="@drawable/ic_profile_image_default"/>
<org.mariotaku.twidere.view.ShapedImageView
android:id="@+id/activity_profile_image_3"
style="?profileImageStyle"
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"
tools:src="@drawable/ic_profile_image_default"/>
<org.mariotaku.twidere.view.ShapedImageView
android:id="@+id/activity_profile_image_4"
style="?profileImageStyle"
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"
tools:src="@drawable/ic_profile_image_default"/>
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/activity_profile_image_more_number"
android:layout_width="0dp"
android:minHeight="@dimen/profile_image_size_activity_small"
android:minWidth="@dimen/profile_image_size_activity_small"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:layout_weight="1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
tools:text="11"/>
</LinearLayout>
<Space
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:layout_alignWithParentIfMissing="true"
android:layout_below="@+id/profile_images_container"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_images_container"
android:layout_below="@+id/profile_images_container"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:singleLine="false"
tools:text="Uucky and 15 others favorited your tweet."/>
<TextView
android:id="@+id/summary"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_images_container"
android:layout_below="@+id/title"
android:singleLine="false"
tools:text="@string/sample_status_text"/>
</RelativeLayout>

View File

@ -140,12 +140,10 @@
<string-array name="values_media_preview_style">
<item>crop</item>
<item>scale</item>
<item>none</item>
</string-array>
<string-array name="entries_media_preview_style">
<item>@string/crop</item>
<item>@string/scale</item>
<item>@string/none</item>
</string-array>
<string-array name="entries_image_sources">
<item>@string/from_camera</item>

View File

@ -13,5 +13,6 @@
<string name="font_family_thin" translatable="false">Thin</string>
<string name="easter_egg_triggered_message" translatable="false">不二对你的膝盖发动了会心一击!</string>
<string name="uucky_footer_text">- Luna meae es -</string>
<string name="sample_status_text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam faucibus quis purus ac malesuada. Duis id vulputate magna, a eleifend amet.</string>
</resources>