migrating users list to RecyclerView

This commit is contained in:
Mariotaku Lee 2015-04-16 20:48:24 +08:00
parent 162ac1af42
commit eb82d1eee7
39 changed files with 1276 additions and 1061 deletions

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.util.Pair;
import android.support.v7.widget.CardView;
@ -40,7 +41,7 @@ import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
@ -69,7 +70,7 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
private final Context mContext;
private final LayoutInflater mInflater;
private final MediaLoaderWrapper mImageLoader;
private final ImageLoadingHandler mLoadingHandler;
private final MediaLoadingHandler mLoadingHandler;
private final AsyncTwitterWrapper mTwitterWrapper;
private final int mCardBackgroundColor;
private final int mTextSize;
@ -90,7 +91,7 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context);
mInflater = LayoutInflater.from(context);
mImageLoader = app.getMediaLoaderWrapper();
mLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
mLoadingHandler = new MediaLoadingHandler(R.id.media_preview_progress);
mTwitterWrapper = app.getTwitterWrapper();
final SharedPreferencesWrapper preferences = SharedPreferencesWrapper.getInstance(context,
SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
@ -115,7 +116,7 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
public abstract void setData(Data data);
@Override
public MediaLoaderWrapper getImageLoader() {
public MediaLoaderWrapper getMediaLoader() {
return mImageLoader;
}
@ -125,7 +126,7 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
}
@Override
public ImageLoadingHandler getImageLoadingHandler() {
public MediaLoadingHandler getMediaLoadingHandler() {
return mLoadingHandler;
}
@ -139,6 +140,7 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
return mMediaPreviewStyle;
}
@NonNull
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return mTwitterWrapper;
@ -187,7 +189,6 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
return mNameFirst;
}
@Override
public boolean isProfileImageEnabled() {
return mDisplayProfileImage;
}
@ -304,6 +305,11 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
}
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
return false;
}
@Override
public int getItemViewType(int position) {
if (position == getActivityCount()) {

View File

@ -2,10 +2,10 @@ package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.util.Pair;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
@ -19,8 +19,8 @@ import org.mariotaku.twidere.fragment.support.UserFragment;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.StatusAdapterLinkClickHandler;
import org.mariotaku.twidere.util.ThemeUtils;
@ -36,17 +36,15 @@ import org.mariotaku.twidere.view.holder.StatusViewHolder;
/**
* Created by mariotaku on 14/11/19.
*/
public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implements Constants,
public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewHolder> implements Constants,
IStatusesAdapter<D> {
public static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 0;
public static final int ITEM_VIEW_TYPE_GAP = 1;
public static final int ITEM_VIEW_TYPE_STATUS = 2;
private final Context mContext;
private final LayoutInflater mInflater;
private final MediaLoaderWrapper mImageLoader;
private final ImageLoadingHandler mLoadingHandler;
private final MediaLoaderWrapper mMediaLoader;
private final MediaLoadingHandler mLoadingHandler;
private final AsyncTwitterWrapper mTwitterWrapper;
private final TwidereLinkify mLinkify;
@ -68,8 +66,6 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
private final boolean mSensitiveContentEnabled;
private final boolean mHideCardActions;
private boolean mLoadMoreSupported;
private boolean mLoadMoreIndicatorVisible;
private boolean mShowInReplyTo;
private boolean mShowAccountsColor;
@ -78,8 +74,8 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
final TwidereApplication app = TwidereApplication.getInstance(context);
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context);
mInflater = LayoutInflater.from(context);
mImageLoader = app.getMediaLoaderWrapper();
mLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
mMediaLoader = app.getMediaLoaderWrapper();
mLoadingHandler = new MediaLoadingHandler(R.id.media_preview_progress);
mTwitterWrapper = app.getTwitterWrapper();
final SharedPreferencesWrapper preferences = SharedPreferencesWrapper.getInstance(context,
SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
@ -107,8 +103,8 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
}
@Override
public final MediaLoaderWrapper getImageLoader() {
return mImageLoader;
public final MediaLoaderWrapper getMediaLoader() {
return mMediaLoader;
}
@Override
@ -117,7 +113,7 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
}
@Override
public final ImageLoadingHandler getImageLoadingHandler() {
public final MediaLoadingHandler getMediaLoadingHandler() {
return mLoadingHandler;
}
@ -131,6 +127,7 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
return mMediaPreviewStyle;
}
@NonNull
@Override
public final AsyncTwitterWrapper getTwitterWrapper() {
return mTwitterWrapper;
@ -141,32 +138,6 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
return mTextSize;
}
@Override
public boolean isLoadMoreIndicatorVisible() {
return mLoadMoreIndicatorVisible;
}
@Override
public boolean isLoadMoreSupported() {
return mLoadMoreSupported;
}
@Override
public void setLoadMoreSupported(boolean supported) {
mLoadMoreSupported = supported;
if (!supported) {
mLoadMoreIndicatorVisible = false;
}
notifyDataSetChanged();
}
@Override
public void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged();
}
@Override
public TwidereLinkify getTwidereLinkify() {
return mLinkify;
@ -203,18 +174,21 @@ 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 boolean onStatusLongClick(StatusViewHolder holder, int position) {
return mStatusAdapterListener != null && mStatusAdapterListener.onStatusLongClick(holder, position);
}
@Override
public final void onStatusClick(StatusViewHolder holder, int position) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onStatusClick(holder, position);
}
@Override
public void onMediaClick(StatusViewHolder holder, final ParcelableMedia media, int position) {
if (mStatusAdapterListener != null) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onMediaClick(holder, media, position);
}
}
@Override
public void onUserProfileClick(final StatusViewHolder holder, final int position) {
@ -300,29 +274,26 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
@Override
public final int getItemCount() {
return getStatusesCount() + (mLoadMoreIndicatorVisible ? 1 : 0);
return getStatusesCount() + (isLoadMoreIndicatorVisible() ? 1 : 0);
}
@Override
public final void onGapClick(ViewHolder holder, int position) {
if (mStatusAdapterListener != null) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onGapClick((GapViewHolder) holder, position);
}
}
@Override
public void onItemActionClick(ViewHolder holder, int id, int position) {
if (mStatusAdapterListener != null) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onStatusActionClick((StatusViewHolder) holder, id, position);
}
}
@Override
public void onItemMenuClick(ViewHolder holder, View menuView, int position) {
if (mStatusAdapterListener != null) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onStatusMenuClick((StatusViewHolder) holder, menuView, position);
}
}
public void setListener(StatusAdapterListener listener) {
mStatusAdapterListener = listener;
@ -345,6 +316,8 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
void onStatusClick(StatusViewHolder holder, int position);
boolean onStatusLongClick(StatusViewHolder holder, int position);
void onStatusMenuClick(StatusViewHolder holder, View menuView, int position);
}

View File

@ -0,0 +1,161 @@
/*
* 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.annotation.NonNull;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
import org.mariotaku.twidere.view.holder.UserViewHolder;
public abstract class AbsUsersAdapter<D> extends LoadMoreSupportAdapter<ViewHolder> implements Constants,
IUsersAdapter<D> {
public static final int ITEM_VIEW_TYPE_USER = 2;
private final Context mContext;
private final LayoutInflater mInflater;
private final MediaLoaderWrapper mMediaLoader;
private final int mCardBackgroundColor;
private final boolean mCompactCards;
private final int mProfileImageStyle;
private final int mTextSize;
private final AsyncTwitterWrapper mTwitterWrapper;
private final boolean mDisplayProfileImage;
public AbsUsersAdapter(final Context context, final boolean compact) {
final TwidereApplication app = TwidereApplication.getInstance(context);
mContext = context;
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context);
mInflater = LayoutInflater.from(context);
mMediaLoader = app.getMediaLoaderWrapper();
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));
mDisplayProfileImage = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true);
mCompactCards = compact;
}
@Override
public Context getContext() {
return mContext;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;
}
@Override
public float getTextSize() {
return mTextSize;
}
@NonNull
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return mTwitterWrapper;
}
@Override
public boolean isProfileImageEnabled() {
return mDisplayProfileImage;
}
public abstract D getData();
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ITEM_VIEW_TYPE_USER: {
final View view;
if (mCompactCards) {
view = mInflater.inflate(R.layout.card_item_user_compact, parent, false);
// final View itemContent = view.findViewById(R.id.item_content);
// itemContent.setBackgroundColor(mCardBackgroundColor);
} else {
view = mInflater.inflate(R.layout.card_item_user, parent, false);
// final CardView cardView = (CardView) view.findViewById(R.id.card);
// cardView.setCardBackgroundColor(mCardBackgroundColor);
}
final UserViewHolder holder = new UserViewHolder(this, view);
// holder.setOnClickListeners();
// holder.setupViewOptions();
return holder;
}
case ITEM_VIEW_TYPE_LOAD_INDICATOR: {
final View view = mInflater.inflate(R.layout.card_item_load_indicator, parent, false);
return new LoadIndicatorViewHolder(view);
}
}
throw new IllegalStateException("Unknown view type " + viewType);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case ITEM_VIEW_TYPE_USER: {
bindStatus(((UserViewHolder) holder), position);
break;
}
}
}
public boolean isUser(int position) {
return position < getUsersCount();
}
@Override
public int getItemViewType(int position) {
if (position == getUsersCount()) {
return ITEM_VIEW_TYPE_LOAD_INDICATOR;
}
return ITEM_VIEW_TYPE_USER;
}
@Override
public boolean shouldShowAccountsColor() {
return false;
}
@Override
public MediaLoaderWrapper getMediaLoader() {
return mMediaLoader;
}
protected abstract void bindStatus(UserViewHolder holder, int position);
}

View File

@ -34,7 +34,7 @@ import org.mariotaku.twidere.model.DraftItem;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableMediaUpdate;
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.TwidereArrayUtils;
@ -46,7 +46,7 @@ import static org.mariotaku.twidere.util.Utils.getAccountColors;
public class DraftsAdapter extends SimpleCursorAdapter implements Constants {
private final MediaLoaderWrapper mImageLoader;
private final ImageLoadingHandler mImageLoadingHandler;
private final MediaLoadingHandler mMediaLoadingHandler;
private final int mMediaPreviewStyle;
private float mTextSize;
@ -55,7 +55,7 @@ public class DraftsAdapter extends SimpleCursorAdapter implements Constants {
public DraftsAdapter(final Context context) {
super(context, R.layout.list_item_draft, null, new String[0], new int[0], 0);
mImageLoader = TwidereApplication.getInstance(context).getMediaLoaderWrapper();
mImageLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
mMediaLoadingHandler = new MediaLoadingHandler(R.id.media_preview_progress);
final SharedPreferencesWrapper preferences = SharedPreferencesWrapper.getInstance(context,
SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mMediaPreviewStyle = Utils.getMediaPreviewStyle(preferences.getString(KEY_MEDIA_PREVIEW_STYLE, null));
@ -74,7 +74,7 @@ public class DraftsAdapter extends SimpleCursorAdapter implements Constants {
if (actionType == Drafts.ACTION_UPDATE_STATUS) {
final ParcelableMedia[] media = ParcelableMedia.fromMediaUpdates(mediaUpdates);
holder.media_preview_container.setVisibility(View.VISIBLE);
holder.media_preview_container.displayMedia(media, mImageLoader, -1L, null, mImageLoadingHandler);
holder.media_preview_container.displayMedia(media, mImageLoader, -1L, null, mMediaLoadingHandler);
} else {
holder.media_preview_container.setVisibility(View.GONE);
}

View File

@ -0,0 +1,62 @@
/*
* 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.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter;
/**
* Created by mariotaku on 15/4/16.
*/
public abstract class LoadMoreSupportAdapter<VH extends ViewHolder> extends Adapter<VH>
implements ILoadMoreSupportAdapter {
private boolean mLoadMoreSupported;
private boolean mLoadMoreIndicatorVisible;
@Override
public final boolean isLoadMoreIndicatorVisible() {
return mLoadMoreIndicatorVisible;
}
@Override
public final void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged();
}
@Override
public final boolean isLoadMoreSupported() {
return mLoadMoreSupported;
}
@Override
public final void setLoadMoreSupported(boolean supported) {
mLoadMoreSupported = supported;
if (!supported) {
mLoadMoreIndicatorVisible = false;
}
notifyDataSetChanged();
}
}

View File

@ -28,7 +28,7 @@ import android.widget.ImageView;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import java.util.Collection;
@ -37,7 +37,7 @@ public class MediaPreviewAdapter extends ArrayAdapter<String> implements Constan
private final MediaLoaderWrapper mImageLoader;
private final SharedPreferences mPreferences;
private final ImageLoadingHandler mImageLoadingHandler;
private final MediaLoadingHandler mMediaLoadingHandler;
private boolean mIsPossiblySensitive;
@ -45,7 +45,7 @@ public class MediaPreviewAdapter extends ArrayAdapter<String> implements Constan
super(context, R.layout.gallery_item_image_preview);
mImageLoader = ((TwidereApplication) context.getApplicationContext()).getMediaLoaderWrapper();
mPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mImageLoadingHandler = new ImageLoadingHandler();
mMediaLoadingHandler = new MediaLoadingHandler();
}
public void addAll(final Collection<String> data, final boolean is_possibly_sensitive) {
@ -63,9 +63,9 @@ public class MediaPreviewAdapter extends ArrayAdapter<String> implements Constan
view.findViewById(R.id.media_preview_progress).setVisibility(View.GONE);
image_view.setBackgroundResource(R.drawable.image_preview_nsfw);
mImageLoader.cancelDisplayTask(image_view);
} else if (!link.equals(mImageLoadingHandler.getLoadingUri(image_view))) {
} else if (!link.equals(mMediaLoadingHandler.getLoadingUri(image_view))) {
image_view.setBackgroundResource(0);
mImageLoader.displayPreviewImage(image_view, link, mImageLoadingHandler);
mImageLoader.displayPreviewImage(image_view, link, mMediaLoadingHandler);
}
return view;
}

View File

@ -36,7 +36,7 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.model.ParcelableDirectMessage.CursorIndices;
import org.mariotaku.twidere.util.DirectMessageOnLinkClickHandler;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.ThemeUtils;
@ -61,7 +61,7 @@ public class MessageConversationAdapter extends Adapter<ViewHolder>
private final LayoutInflater mInflater;
private final MediaLoaderWrapper mImageLoader;
private final MultiSelectManager mMultiSelectManager;
private final ImageLoadingHandler mImageLoadingHandler;
private final MediaLoadingHandler mMediaLoadingHandler;
private Cursor mCursor;
private CursorIndices mIndices;
@ -74,7 +74,7 @@ public class MessageConversationAdapter extends Adapter<ViewHolder>
mLinkify = new TwidereLinkify(new DirectMessageOnLinkClickHandler(context, null));
mMultiSelectManager = app.getMultiSelectManager();
mImageLoader = app.getMediaLoaderWrapper();
mImageLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
mMediaLoadingHandler = new MediaLoadingHandler(R.id.media_preview_progress);
mIncomingMessageColor = ThemeUtils.getUserAccentColor(context);
mOutgoingMessageColor = ThemeUtils.getCardBackgroundColor(context);
}

View File

@ -23,6 +23,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
@ -37,7 +38,6 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.StringLongPair;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.ReadStateManager;
@ -62,6 +62,8 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
private final int mMediaPreviewStyle;
private final ReadStateManager mReadStateManager;
private final OnSharedPreferenceChangeListener mReadStateChangeListener;
private final boolean mDisplayProfileImage;
private final AsyncTwitterWrapper mTwitterWrapper;
private boolean mLoadMoreSupported;
private boolean mLoadMoreIndicatorVisible;
private Cursor mCursor;
@ -74,10 +76,12 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
final TwidereApplication app = TwidereApplication.getInstance(context);
mMultiSelectManager = app.getMultiSelectManager();
mImageLoader = app.getMediaLoaderWrapper();
mTwitterWrapper = app.getTwitterWrapper();
final SharedPreferencesWrapper preferences = SharedPreferencesWrapper.getInstance(context,
SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mProfileImageStyle = Utils.getProfileImageStyle(preferences.getString(KEY_PROFILE_IMAGE_STYLE, null));
mMediaPreviewStyle = Utils.getMediaPreviewStyle(preferences.getString(KEY_MEDIA_PREVIEW_STYLE, null));
mDisplayProfileImage = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true);
mTextSize = preferences.getInt(KEY_TEXT_SIZE, context.getResources().getInteger(R.integer.default_text_size));
mReadStateManager = app.getReadStateManager();
mReadStateChangeListener = new OnSharedPreferenceChangeListener() {
@ -89,58 +93,39 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
};
}
public void onUserProfileClick(int position) {
mListener.onUserClick(position, getEntry(position));
}
public void updateReadState() {
mPositionPairs = mReadStateManager.getPositionPairs(TAB_TYPE_DIRECT_MESSAGES);
notifyDataSetChanged();
}
public DirectMessageEntry getEntry(final int position) {
final Cursor c = mCursor;
if (c == null || c.isClosed() || !c.moveToPosition(position)) return null;
return new DirectMessageEntry(c);
}
public MediaLoaderWrapper getImageLoader() {
return mImageLoader;
}
public Context getContext() {
return mContext;
}
@Override
public ImageLoadingHandler getImageLoadingHandler() {
return null;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;
}
@Override
public int getMediaPreviewStyle() {
return mMediaPreviewStyle;
}
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return null;
}
@Override
public float getTextSize() {
return mTextSize;
}
@NonNull
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return mTwitterWrapper;
}
@Override
public void onReadStateChanged() {
public boolean isProfileImageEnabled() {
return mDisplayProfileImage;
}
public DirectMessageEntry getEntry(final int position) {
final Cursor c = mCursor;
if (c == null || c.isClosed() || !c.moveToPosition(position)) return null;
return new DirectMessageEntry(c);
}
public MediaLoaderWrapper getMediaLoader() {
return mImageLoader;
}
@Override
@ -148,6 +133,13 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
return mLoadMoreIndicatorVisible;
}
@Override
public void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged();
}
@Override
public boolean isLoadMoreSupported() {
return mLoadMoreSupported;
@ -162,24 +154,6 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
notifyDataSetChanged();
}
@Override
public void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged();
}
@Override
public boolean isGapItem(int position) {
return false;
}
@Override
public void onGapClick(ViewHolder holder, int position) {
}
@Override
public void onClick(final View view) {
// if (mMultiSelectManager.isActive()) return;
@ -226,18 +200,6 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
}
}
private boolean isUnread(Cursor c) {
if (mPositionPairs == null) return true;
final long accountId = c.getLong(ConversationEntries.IDX_ACCOUNT_ID);
final long conversationId = c.getLong(ConversationEntries.IDX_CONVERSATION_ID);
final long messageId = c.getLong(ConversationEntries.IDX_MESSAGE_ID);
final String key = accountId + "-" + conversationId;
for (StringLongPair pair : mPositionPairs) {
if (key.equals(pair.getKey())) return messageId > pair.getValue();
}
return true;
}
@Override
public int getItemViewType(int position) {
if (position == getMessagesCount()) {
@ -251,21 +213,20 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
return getMessagesCount() + (mLoadMoreIndicatorVisible ? 1 : 0);
}
@Override
public void onItemActionClick(ViewHolder holder, int id, int position) {
}
@Override
public void onItemMenuClick(ViewHolder holder, View menuView, int position) {
}
public void onMessageClick(int position) {
if (mListener == null) return;
mListener.onEntryClick(position, getEntry(position));
}
@Override
public void onReadStateChanged() {
}
public void onUserProfileClick(int position) {
mListener.onUserClick(position, getEntry(position));
}
public void setCursor(Cursor cursor) {
mCursor = cursor;
mReadStateManager.unregisterOnSharedPreferenceChangeListener(mReadStateChangeListener);
@ -280,12 +241,29 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
mListener = listener;
}
public void updateReadState() {
mPositionPairs = mReadStateManager.getPositionPairs(TAB_TYPE_DIRECT_MESSAGES);
notifyDataSetChanged();
}
private int getMessagesCount() {
final Cursor c = mCursor;
if (c == null || c.isClosed()) return 0;
return c.getCount();
}
private boolean isUnread(Cursor c) {
if (mPositionPairs == null) return true;
final long accountId = c.getLong(ConversationEntries.IDX_ACCOUNT_ID);
final long conversationId = c.getLong(ConversationEntries.IDX_CONVERSATION_ID);
final long messageId = c.getLong(ConversationEntries.IDX_MESSAGE_ID);
final String key = accountId + "-" + conversationId;
for (StringLongPair pair : mPositionPairs) {
if (key.equals(pair.getKey())) return messageId > pair.getValue();
}
return true;
}
public interface MessageEntriesAdapterListener {
void onEntryClick(int position, DirectMessageEntry entry);

View File

@ -20,128 +20,57 @@
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.UserViewListHolder;
import org.mariotaku.twidere.view.holder.UserViewHolder;
import java.util.List;
import java.util.Locale;
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;
import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;
public class ParcelableUsersAdapter extends AbsUsersAdapter<List<ParcelableUser>> {
public class ParcelableUsersAdapter extends BaseArrayAdapter<ParcelableUser> implements IBaseCardAdapter {
private List<ParcelableUser> mData;
private final MediaLoaderWrapper mProfileImageLoader;
private final MultiSelectManager mMultiSelectManager;
private final Context mContext;
private final Locale mLocale;
public ParcelableUsersAdapter(final Context context) {
this(context, Utils.isCompactCards(context));
}
public ParcelableUsersAdapter(final Context context, final boolean compactCards) {
super(context, getItemResource(compactCards));
mContext = context;
mLocale = context.getResources().getConfiguration().locale;
final TwidereApplication app = TwidereApplication.getInstance(context);
mProfileImageLoader = app.getMediaLoaderWrapper();
mMultiSelectManager = app.getMultiSelectManager();
configBaseCardAdapter(context, this);
public ParcelableUsersAdapter(Context context, boolean compact) {
super(context, compact);
}
@Override
public long getItemId(final int position) {
return getItem(position) != null ? getItem(position).id : -1;
public List<ParcelableUser> getData() {
return mData;
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final View view = super.getView(position, convertView, parent);
final Object tag = view.getTag();
final UserViewListHolder holder;
if (tag instanceof UserViewListHolder) {
holder = (UserViewListHolder) tag;
} else {
holder = new UserViewListHolder(view);
// holder.content.setOnOverflowIconClickListener(this);
view.setTag(holder);
public void setData(List<ParcelableUser> data) {
mData = data;
notifyDataSetChanged();
}
holder.position = position;
final ParcelableUser user = getItem(position);
final boolean showAccountColor = isShowAccountColor();
holder.setAccountColorEnabled(showAccountColor);
if (showAccountColor) {
holder.setAccountColor(getAccountColor(mContext, user.account_id));
@Override
protected void bindStatus(UserViewHolder holder, int position) {
holder.displayUser(getUser(position));
}
holder.setUserColor(getUserColor(mContext, user.id));
holder.setTextSize(getTextSize());
final int userTypeRes = getUserTypeIconRes(user.is_verified, user.is_protected);
if (userTypeRes != 0) {
holder.profile_type.setImageResource(userTypeRes);
} else {
holder.profile_type.setImageDrawable(null);
}
holder.name.setText(getUserNickname(mContext, user.id, user.name));
holder.screen_name.setText("@" + user.screen_name);
holder.description.setVisibility(TextUtils.isEmpty(user.description_unescaped) ? View.GONE : View.VISIBLE);
holder.description.setText(user.description_unescaped);
holder.location.setVisibility(TextUtils.isEmpty(user.location) ? View.GONE : View.VISIBLE);
holder.location.setText(user.location);
holder.url.setVisibility(TextUtils.isEmpty(user.url_expanded) ? View.GONE : View.VISIBLE);
holder.url.setText(user.url_expanded);
holder.statuses_count.setText(getLocalizedNumber(mLocale, user.statuses_count));
holder.followers_count.setText(getLocalizedNumber(mLocale, user.followers_count));
holder.friends_count.setText(getLocalizedNumber(mLocale, user.friends_count));
holder.profile_image.setVisibility(isProfileImageDisplayed() ? View.VISIBLE : View.GONE);
if (isProfileImageDisplayed()) {
mProfileImageLoader.displayProfileImage(holder.profile_image, user.profile_image_url);
}
return view;
@Override
public int getItemCount() {
return getUsersCount() + (isLoadMoreIndicatorVisible() ? 1 : 0);
}
public void setData(final List<ParcelableUser> data) {
setData(data, false);
@Override
public ParcelableUser getUser(int position) {
if (position == getUsersCount()) return null;
return mData.get(position);
}
public void setData(final List<ParcelableUser> data, final boolean clear_old) {
if (clear_old) {
clear();
}
if (data == null) return;
for (final ParcelableUser user : data) {
if (clear_old || findItemPosition(user.id) < 0) {
add(user);
}
}
@Override
public long getUserId(int position) {
if (position == getUsersCount()) return -1;
return mData.get(position).id;
}
private static int getItemResource(final boolean compactCards) {
return compactCards ? R.layout.card_item_user_compact : R.layout.card_item_user;
@Override
public int getUsersCount() {
if (mData == null) return 0;
return mData.size();
}
}

View File

@ -20,11 +20,14 @@
package org.mariotaku.twidere.adapter.iface;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
/**
* Created by mariotaku on 14/11/18.
*/
public interface IActivitiesAdapter<Data> extends IContentCardAdapter {
public interface IActivitiesAdapter<Data> extends IContentCardAdapter, IGapSupportedAdapter {
ParcelableActivity getActivity(int position);
@ -32,4 +35,10 @@ public interface IActivitiesAdapter<Data> extends IContentCardAdapter {
void setData(Data data);
@PreviewStyle
int getMediaPreviewStyle();
MediaLoaderWrapper getMediaLoader();
MediaLoadingHandler getMediaLoadingHandler();
}

View File

@ -20,40 +20,29 @@
package org.mariotaku.twidere.adapter.iface;
import android.content.Context;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
import org.mariotaku.twidere.view.ShapedImageView.ShapeStyle;
/**
* Created by mariotaku on 15/1/3.
*/
public interface IContentCardAdapter extends IGapSupportedAdapter, ContentCardClickListener {
MediaLoaderWrapper getImageLoader();
public interface IContentCardAdapter extends ILoadMoreSupportAdapter {
Context getContext();
ImageLoadingHandler getImageLoadingHandler();
int getItemCount();
@ShapeStyle
int getProfileImageStyle();
@PreviewStyle
int getMediaPreviewStyle();
AsyncTwitterWrapper getTwitterWrapper();
float getTextSize();
boolean isLoadMoreIndicatorVisible();
@NonNull
AsyncTwitterWrapper getTwitterWrapper();
boolean isLoadMoreSupported();
boolean isProfileImageEnabled();
void setLoadMoreSupported(boolean supported);
void setLoadMoreIndicatorVisible(boolean enabled);
MediaLoaderWrapper getMediaLoader();
}

View File

@ -26,6 +26,8 @@ import android.support.v7.widget.RecyclerView.ViewHolder;
*/
public interface IGapSupportedAdapter {
int ITEM_VIEW_TYPE_GAP = 1;
boolean isGapItem(int position);
void onGapClick(ViewHolder holder, int position);

View File

@ -0,0 +1,35 @@
/*
* 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;
/**
* Created by mariotaku on 15/4/16.
*/
public interface ILoadMoreSupportAdapter {
int ITEM_VIEW_TYPE_LOAD_INDICATOR = 0;
boolean isLoadMoreIndicatorVisible();
void setLoadMoreIndicatorVisible(boolean enabled);
boolean isLoadMoreSupported();
void setLoadMoreSupported(boolean supported);
}

View File

@ -1,33 +1,42 @@
package org.mariotaku.twidere.adapter.iface;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
import org.mariotaku.twidere.view.holder.StatusViewHolder.StatusClickListener;
/**
* Created by mariotaku on 14/11/18.
*/
public interface IStatusesAdapter<Data> extends IContentCardAdapter, StatusClickListener {
public interface IStatusesAdapter<Data> extends IContentCardAdapter, StatusClickListener,
IGapSupportedAdapter, ContentCardClickListener {
int getLinkHighlightingStyle();
@PreviewStyle
int getMediaPreviewStyle();
ParcelableStatus getStatus(int position);
int getStatusesCount();
long getStatusId(int position);
int getStatusesCount();
TwidereLinkify getTwidereLinkify();
boolean isMediaPreviewEnabled();
boolean isCardActionsHidden();
int getLinkHighlightingStyle();
boolean isMediaPreviewEnabled();
boolean isNameFirst();
boolean isSensitiveContentEnabled();
boolean isCardActionsHidden();
void setData(Data data);
boolean shouldShowAccountsColor();
MediaLoadingHandler getMediaLoadingHandler();
}

View File

@ -1,61 +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.adapter.iface;
import org.mariotaku.twidere.model.ParcelableStatus;
public interface IStatusesListAdapter<Data> extends IBaseCardAdapter, IStatusesAdapter<Data> {
public int findPositionByStatusId(final long statusId);
public long getAccountId(final int position);
public ParcelableStatus getLastStatus();
public long getLastStatusId();
public long getStatusId(final int position);
public boolean isLastItemFiltered();
public void setCardHighlightOption(String option);
public void setDisplayImagePreview(boolean display);
public void setDisplaySensitiveContents(boolean display);
public void setFavoritesHightlightDisabled(boolean disable);
public void setFiltersEnabled(boolean enabled);
public void setGapDisallowed(boolean disallowed);
public void setHighlightKeyword(String... keywords);
public void setIgnoredFilterFields(final boolean user, final boolean textPlain, final boolean textHtml,
final boolean source, final boolean retweetedById);
public void setImagePreviewScaleType(String scaleType);
public void setIndicateMyStatusDisabled(boolean disable);
public void setMentionsHightlightDisabled(boolean disable);
}

View File

@ -0,0 +1,43 @@
/*
* 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.ParcelableUser;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaLoadingHandler;
/**
* Created by mariotaku on 15/4/16.
*/
public interface IUsersAdapter<Data> extends IContentCardAdapter {
ParcelableUser getUser(int position);
long getUserId(int position);
int getUsersCount();
void setData(Data data);
boolean shouldShowAccountsColor();
MediaLoaderWrapper getMediaLoader();
}

View File

@ -0,0 +1,248 @@
/*
* 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.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.support.v7.widget.FixedLinearLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IControlBarActivity;
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarOffsetListener;
import org.mariotaku.twidere.activity.support.BaseActionBarActivity;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
import org.mariotaku.twidere.adapter.iface.IContentCardAdapter;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.util.ColorUtils;
import org.mariotaku.twidere.util.ContentListScrollListener;
import org.mariotaku.twidere.util.ContentListScrollListener.ContentListSupport;
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 15/4/16.
*/
public abstract class AbsContentListFragment<A extends IContentCardAdapter> extends BaseSupportFragment implements OnRefreshListener,
DrawerCallback, RefreshScrollTopInterface, ControlBarOffsetListener, ContentListSupport {
private Rect mSystemWindowsInsets = new Rect();
private int mControlBarOffsetPixels;
private LinearLayoutManager mLayoutManager;
private View mProgressContainer;
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private SimpleDrawerCallback mDrawerCallback;
private A mAdapter;
private ContentListScrollListener mScrollListener;
public boolean canScroll(float dy) {
return mDrawerCallback.canScroll(dy);
}
public void cancelTouch() {
mDrawerCallback.cancelTouch();
}
public void fling(float velocity) {
mDrawerCallback.fling(velocity);
}
public boolean isScrollContent(float x, float y) {
return mDrawerCallback.isScrollContent(x, y);
}
@Override
public void onControlBarOffsetChanged(IControlBarActivity activity, float offset) {
mControlBarOffsetPixels = Math.round(activity.getControlBarHeight() * (1 - offset));
updateRefreshProgressOffset();
}
@Override
public void onRefresh() {
triggerRefresh();
}
public void scrollBy(float dy) {
mDrawerCallback.scrollBy(dy);
}
@Override
public boolean scrollToStart() {
mLayoutManager.scrollToPositionWithOffset(0, 0);
mRecyclerView.stopScroll();
setControlVisible(true);
return true;
}
public void setControlVisible(boolean visible) {
final FragmentActivity activity = getActivity();
if (activity instanceof BaseActionBarActivity) {
((BaseActionBarActivity) activity).setControlBarVisibleAnimate(visible);
}
}
public boolean shouldLayoutHeaderBottom() {
return mDrawerCallback.shouldLayoutHeaderBottom();
}
public void topChanged(int offset) {
mDrawerCallback.topChanged(offset);
}
public A getAdapter() {
return mAdapter;
}
public abstract boolean isRefreshing();
public LinearLayoutManager getLayoutManager() {
return mLayoutManager;
}
public void setRefreshing(boolean refreshing) {
if (refreshing == mSwipeRefreshLayout.isRefreshing()) return;
// if (!refreshing) updateRefreshProgressOffset();
mSwipeRefreshLayout.setRefreshing(refreshing && !mAdapter.isLoadMoreIndicatorVisible());
}
public void onLoadMoreContents() {
setLoadMoreIndicatorVisible(true);
setRefreshEnabled(false);
}
public final RecyclerView getRecyclerView() {
return mRecyclerView;
}
public final ContentListScrollListener getScrollListener() {
return mScrollListener;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof IControlBarActivity) {
((IControlBarActivity) activity).registerControlBarOffsetListener(this);
}
}
@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);
mDrawerCallback = new SimpleDrawerCallback(mRecyclerView);
final View view = getView();
if (view == null) throw new AssertionError();
final Context context = view.getContext();
final boolean compact = Utils.isCompactCards(context);
final int backgroundColor = ThemeUtils.getThemeBackgroundColor(context);
final int colorRes = ColorUtils.getContrastYIQ(backgroundColor,
R.color.bg_refresh_progress_color_light, R.color.bg_refresh_progress_color_dark);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeColors(ThemeUtils.getUserAccentColor(context));
mSwipeRefreshLayout.setProgressBackgroundColorSchemeResource(colorRes);
mAdapter = onCreateAdapter(context, compact);
mLayoutManager = new FixedLinearLayoutManager(context);
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(true);
if (compact) {
mRecyclerView.addItemDecoration(new DividerItemDecoration(context, mLayoutManager.getOrientation()));
}
mRecyclerView.setAdapter((RecyclerView.Adapter) mAdapter);
mScrollListener = new ContentListScrollListener(this);
mScrollListener.setTouchSlop(ViewConfiguration.get(context).getScaledTouchSlop());
mRecyclerView.setOnScrollListener(mScrollListener);
}
@Override
public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onBaseViewCreated(view, savedInstanceState);
mProgressContainer = view.findViewById(R.id.progress_container);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_layout);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
}
@Override
public void onDetach() {
final FragmentActivity activity = getActivity();
if (activity instanceof IControlBarActivity) {
((IControlBarActivity) activity).unregisterControlBarOffsetListener(this);
}
super.onDetach();
}
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
mRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
mProgressContainer.setPadding(insets.left, insets.top, insets.right, insets.bottom);
mSystemWindowsInsets.set(insets);
updateRefreshProgressOffset();
}
public void setLoadMoreIndicatorVisible(boolean visible) {
mAdapter.setLoadMoreIndicatorVisible(visible);
}
public void setRefreshEnabled(boolean enabled) {
mSwipeRefreshLayout.setEnabled(enabled);
}
@NonNull
protected abstract A onCreateAdapter(Context context, boolean compact);
protected final void setListShown(boolean shown) {
mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE);
}
protected void updateRefreshProgressOffset() {
if (mSystemWindowsInsets.top == 0 || mSwipeRefreshLayout == null || isRefreshing()) return;
final float density = getResources().getDisplayMetrics().density;
final int progressCircleDiameter = mSwipeRefreshLayout.getProgressCircleDiameter();
final int swipeStart = (mSystemWindowsInsets.top - mControlBarOffsetPixels) - progressCircleDiameter;
// 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET
final int swipeDistance = Math.round(64 * density);
mSwipeRefreshLayout.setProgressViewOffset(false, swipeStart, swipeStart + swipeDistance);
}
}

View File

@ -1,19 +1,14 @@
package org.mariotaku.twidere.fragment.support;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
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.FixedLinearLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.PopupMenu.OnMenuItemClickListener;
@ -21,40 +16,26 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IControlBarActivity;
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarOffsetListener;
import org.mariotaku.twidere.activity.support.BaseActionBarActivity;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter.StatusAdapterListener;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ColorUtils;
import org.mariotaku.twidere.util.ContentListScrollListener;
import org.mariotaku.twidere.util.ContentListScrollListener.ContentListSupport;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback;
import org.mariotaku.twidere.util.ReadStateManager;
import org.mariotaku.twidere.util.RecyclerViewUtils;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.message.StatusListChangedEvent;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
@ -66,27 +47,15 @@ import static org.mariotaku.twidere.util.Utils.setMenuForStatus;
/**
* Created by mariotaku on 14/11/5.
*/
public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment implements LoaderCallbacks<Data>,
OnRefreshListener, DrawerCallback, RefreshScrollTopInterface, StatusAdapterListener,
ControlBarOffsetListener, ContentListSupport, ShortcutCallback {
public abstract class AbsStatusesFragment<Data> extends AbsContentListFragment<AbsStatusesAdapter<Data>>
implements LoaderCallbacks<Data>, StatusAdapterListener, ShortcutCallback {
private final Object mStatusesBusCallback;
private AbsStatusesAdapter<Data> mAdapter;
private LinearLayoutManager mLayoutManager;
private SharedPreferences mPreferences;
private View mProgressContainer;
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private SimpleDrawerCallback mDrawerCallback;
private Rect mSystemWindowsInsets = new Rect();
private int mControlBarOffsetPixels;
private PopupMenu mPopupMenu;
private ReadStateManager mReadStateManager;
private KeyboardShortcutsHandler mKeyboardShortcutsHandler;
private ParcelableStatus mSelectedStatus;
private int mPositionBackup;
private OnMenuItemClickListener mOnStatusMenuItemClickListener = new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
@ -101,65 +70,23 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
getFragmentManager(), getTwitterWrapper(), status, item);
}
};
private int mPositionBackup;
protected AbsStatusesFragment() {
mStatusesBusCallback = createMessageBusCallback();
}
@Override
public boolean canScroll(float dy) {
return mDrawerCallback.canScroll(dy);
public SharedPreferences getSharedPreferences() {
if (mPreferences != null) return mPreferences;
return mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
@Override
public void cancelTouch() {
mDrawerCallback.cancelTouch();
}
public abstract int getStatuses(long[] accountIds, long[] maxIds, long[] sinceIds);
@Override
public void fling(float velocity) {
mDrawerCallback.fling(velocity);
}
@Override
public boolean isScrollContent(float x, float y) {
return mDrawerCallback.isScrollContent(x, y);
}
@Override
public boolean handleKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event) {
if (!KeyboardShortcutsHandler.isValidForHotkey(keyCode, event)) return false;
String action = mKeyboardShortcutsHandler.getKeyAction("navigation", keyCode, event);
final LinearLayoutManager layoutManager = mLayoutManager;
final RecyclerView recyclerView = mRecyclerView;
final View focusedChild = RecyclerViewUtils.findRecyclerViewChild(recyclerView, layoutManager.getFocusedChild());
final int position;
if (focusedChild != null) {
position = recyclerView.getChildLayoutPosition(focusedChild);
} else if (layoutManager.findFirstVisibleItemPosition() == 0) {
position = -1;
} else {
final int itemCount = mAdapter.getItemCount();
if (layoutManager.findLastVisibleItemPosition() == itemCount - 1) {
position = itemCount;
} else {
position = mPositionBackup;
}
}
mPositionBackup = position;
if (action != null) {
switch (action) {
case "navigation.previous": {
RecyclerViewUtils.focusNavigate(recyclerView, layoutManager, position, -1);
return true;
}
case "navigation.next": {
RecyclerViewUtils.focusNavigate(recyclerView, layoutManager, position, 1);
return true;
}
}
}
return false;
public final boolean scrollToStart() {
saveReadPosition();
return super.scrollToStart();
}
@Override
@ -170,7 +97,9 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
triggerRefresh();
return true;
}
final View focusedChild = RecyclerViewUtils.findRecyclerViewChild(mRecyclerView, mLayoutManager.getFocusedChild());
final RecyclerView mRecyclerView = getRecyclerView();
final LinearLayoutManager layoutManager = getLayoutManager();
final View focusedChild = RecyclerViewUtils.findRecyclerViewChild(mRecyclerView, layoutManager.getFocusedChild());
final int position;
if (focusedChild != null && focusedChild.getParent() == mRecyclerView) {
position = mRecyclerView.getChildLayoutPosition(focusedChild);
@ -178,7 +107,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
return false;
}
if (position == -1) return false;
final ParcelableStatus status = mAdapter.getStatus(position);
final ParcelableStatus status = getAdapter().getStatus(position);
if (status == null) return false;
if (action == null) {
action = mKeyboardShortcutsHandler.getKeyAction("status", keyCode, event);
@ -209,57 +138,39 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
}
@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 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 abstract boolean isRefreshing();
public AbsStatusesAdapter<Data> getAdapter() {
return mAdapter;
}
public void setControlVisible(boolean visible) {
final FragmentActivity activity = getActivity();
if (activity instanceof BaseActionBarActivity) {
((BaseActionBarActivity) activity).setControlBarVisibleAnimate(visible);
public boolean handleKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event) {
if (!KeyboardShortcutsHandler.isValidForHotkey(keyCode, event)) return false;
String action = mKeyboardShortcutsHandler.getKeyAction("navigation", keyCode, event);
final LinearLayoutManager layoutManager = getLayoutManager();
final RecyclerView recyclerView = getRecyclerView();
final View focusedChild = RecyclerViewUtils.findRecyclerViewChild(recyclerView, layoutManager.getFocusedChild());
final int position;
if (focusedChild != null) {
position = recyclerView.getChildLayoutPosition(focusedChild);
} else if (layoutManager.findFirstVisibleItemPosition() == 0) {
position = -1;
} else {
final int itemCount = getAdapter().getItemCount();
if (layoutManager.findLastVisibleItemPosition() == itemCount - 1) {
position = itemCount;
} else {
position = mPositionBackup;
}
}
public void setRefreshing(boolean refreshing) {
if (refreshing == mSwipeRefreshLayout.isRefreshing()) return;
// if (!refreshing) updateRefreshProgressOffset();
mSwipeRefreshLayout.setRefreshing(refreshing && !mAdapter.isLoadMoreIndicatorVisible());
mPositionBackup = position;
if (action != null) {
switch (action) {
case "navigation.previous": {
RecyclerViewUtils.focusNavigate(recyclerView, layoutManager, position, -1);
return true;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof IControlBarActivity) {
((IControlBarActivity) activity).registerControlBarOffsetListener(this);
case "navigation.next": {
RecyclerViewUtils.focusNavigate(recyclerView, layoutManager, position, 1);
return true;
}
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recycler_view, container, false);
}
return false;
}
@Override
@ -269,30 +180,8 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
final FragmentActivity activity = getActivity();
final TwidereApplication application = TwidereApplication.getInstance(activity);
mKeyboardShortcutsHandler = application.getKeyboardShortcutsHandler();
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));
final int backgroundColor = ThemeUtils.getThemeBackgroundColor(context);
final int colorRes = ColorUtils.getContrastYIQ(backgroundColor,
R.color.bg_refresh_progress_color_light, R.color.bg_refresh_progress_color_dark);
mSwipeRefreshLayout.setProgressBackgroundColorSchemeResource(colorRes);
mAdapter = onCreateAdapter(context, compact);
mLayoutManager = new FixedLinearLayoutManager(context);
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(true);
if (compact) {
mRecyclerView.addItemDecoration(new DividerItemDecoration(context, mLayoutManager.getOrientation()));
}
mRecyclerView.setAdapter(mAdapter);
final ContentListScrollListener scrollListener = new ContentListScrollListener(this);
scrollListener.setTouchSlop(ViewConfiguration.get(context).getScaledTouchSlop());
scrollListener.setOnScrollListener(new OnScrollListener() {
getAdapter().setListener(this);
getScrollListener().setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
@ -300,78 +189,13 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
}
}
});
mRecyclerView.setOnScrollListener(scrollListener);
mAdapter.setListener(this);
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
setListShown(false);
}
@Override
public void onLoadMoreContents() {
setLoadMoreIndicatorVisible(true);
setRefreshEnabled(false);
}
public void setLoadMoreIndicatorVisible(boolean visible) {
mAdapter.setLoadMoreIndicatorVisible(visible);
}
@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 onDestroyView() {
if (mPopupMenu != null) {
mPopupMenu.dismiss();
}
super.onDestroyView();
}
@Override
public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onBaseViewCreated(view, savedInstanceState);
mProgressContainer = view.findViewById(R.id.progress_container);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_layout);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
}
@Override
public void onDetach() {
final FragmentActivity activity = getActivity();
if (activity instanceof IControlBarActivity) {
((IControlBarActivity) activity).unregisterControlBarOffsetListener(this);
}
super.onDetach();
}
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
mRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
mProgressContainer.setPadding(insets.left, insets.top, insets.right, insets.bottom);
mSystemWindowsInsets.set(insets);
updateRefreshProgressOffset();
}
@Override
public void onControlBarOffsetChanged(IControlBarActivity activity, float offset) {
mControlBarOffsetPixels = Math.round(activity.getControlBarHeight() * (1 - offset));
updateRefreshProgressOffset();
}
@Override
public final Loader<Data> onCreateLoader(int id, Bundle args) {
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
@ -381,19 +205,21 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
@Override
public final void onLoadFinished(Loader<Data> loader, Data data) {
final AbsStatusesAdapter<Data> adapter = getAdapter();
final SharedPreferences preferences = getSharedPreferences();
final boolean rememberPosition = preferences.getBoolean(KEY_REMEMBER_POSITION, false);
final boolean readFromBottom = preferences.getBoolean(KEY_READ_FROM_BOTTOM, false);
final long lastReadId;
final int lastVisiblePos, lastVisibleTop;
final String tag = getCurrentReadPositionTag();
final LinearLayoutManager mLayoutManager = getLayoutManager();
if (readFromBottom) {
lastVisiblePos = mLayoutManager.findLastVisibleItemPosition();
} else {
lastVisiblePos = mLayoutManager.findFirstVisibleItemPosition();
}
if (lastVisiblePos != RecyclerView.NO_POSITION) {
lastReadId = mAdapter.getStatusId(lastVisiblePos);
lastReadId = adapter.getStatusId(lastVisiblePos);
final View positionView = mLayoutManager.findViewByPosition(lastVisiblePos);
lastVisibleTop = positionView != null ? positionView.getTop() : 0;
} else if (rememberPosition && tag != null) {
@ -403,18 +229,18 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
lastReadId = -1;
lastVisibleTop = 0;
}
mAdapter.setData(data);
adapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
mAdapter.setLoadMoreSupported(hasMoreData(data));
adapter.setLoadMoreSupported(hasMoreData(data));
setRefreshEnabled(true);
int pos = -1;
for (int i = 0, j = mAdapter.getItemCount(); i < j; i++) {
if (lastReadId != -1 && lastReadId == mAdapter.getStatusId(i)) {
for (int i = 0, j = adapter.getItemCount(); i < j; i++) {
if (lastReadId != -1 && lastReadId == adapter.getStatusId(i)) {
pos = i;
break;
}
}
if (pos != -1 && mAdapter.isStatus(pos) && (readFromBottom || lastVisiblePos != 0)) {
if (pos != -1 && adapter.isStatus(pos) && (readFromBottom || lastVisiblePos != 0)) {
mLayoutManager.scrollToPositionWithOffset(pos, lastVisibleTop);
}
}
@ -425,12 +251,6 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
onLoadingFinished();
}
protected abstract void onLoadingFinished();
public void setRefreshEnabled(boolean enabled) {
mSwipeRefreshLayout.setEnabled(enabled);
}
@Override
public void onLoaderReset(Loader<Data> loader) {
if (loader instanceof IExtendedLoader) {
@ -443,17 +263,37 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
@Override
public void onGapClick(GapViewHolder holder, int position) {
final ParcelableStatus status = mAdapter.getStatus(position);
final long sinceId = position + 1 < mAdapter.getStatusesCount() ? mAdapter.getStatus(position + 1).id : -1;
final AbsStatusesAdapter<Data> adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
final long sinceId = position + 1 < adapter.getStatusesCount() ? adapter.getStatus(position + 1).id : -1;
final long[] accountIds = {status.account_id};
final long[] maxIds = {status.id};
final long[] sinceIds = {sinceId};
getStatuses(accountIds, maxIds, sinceIds);
}
@Override
public void onMediaClick(StatusViewHolder holder, ParcelableMedia media, int position) {
final AbsStatusesAdapter<Data> adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
Utils.openMedia(getActivity(), status, media);
//spice
SpiceProfilingUtil.log(getActivity(),
status.id + ",Clicked," + status.account_id + "," + status.user_id + "," + status.text_plain.length()
+ "," + media.media_url + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + adapter.isMediaPreviewEnabled() + "," + status.timestamp);
SpiceProfilingUtil.profile(getActivity(), status.account_id,
status.id + ",Clicked," + status.account_id + "," + status.user_id + "," + status.text_plain.length()
+ "," + media.media_url + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + adapter.isMediaPreviewEnabled() + "," + status.timestamp);
//end
}
@Override
public void onStatusActionClick(StatusViewHolder holder, int id, int position) {
final ParcelableStatus status = mAdapter.getStatus(position);
final AbsStatusesAdapter<Data> adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
final FragmentActivity activity = getActivity();
switch (id) {
@ -483,7 +323,14 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
Utils.openStatus(getActivity(), mAdapter.getStatus(position), null);
final AbsStatusesAdapter<Data> adapter = getAdapter();
Utils.openStatus(getActivity(), adapter.getStatus(position), null);
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
//TODO handle long click event
return true;
}
@Override
@ -491,28 +338,38 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
if (mPopupMenu != null) {
mPopupMenu.dismiss();
}
final PopupMenu popupMenu = new PopupMenu(mAdapter.getContext(), menuView,
final AbsStatusesAdapter<Data> adapter = getAdapter();
final PopupMenu popupMenu = new PopupMenu(adapter.getContext(), menuView,
Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0);
popupMenu.setOnMenuItemClickListener(mOnStatusMenuItemClickListener);
popupMenu.inflate(R.menu.action_status);
final ParcelableStatus status = mAdapter.getStatus(position);
setMenuForStatus(mAdapter.getContext(), popupMenu.getMenu(), status);
final ParcelableStatus status = adapter.getStatus(position);
setMenuForStatus(adapter.getContext(), popupMenu.getMenu(), status);
popupMenu.show();
mPopupMenu = popupMenu;
mSelectedStatus = status;
}
@Override
public void onRefresh() {
triggerRefresh();
public void onStart() {
super.onStart();
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
bus.register(mStatusesBusCallback);
}
@Override
public boolean scrollToStart() {
saveReadPosition();
mLayoutManager.scrollToPositionWithOffset(0, 0);
setControlVisible(true);
return true;
public void onStop() {
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
bus.unregister(mStatusesBusCallback);
super.onStop();
}
@Override
public void onDestroyView() {
if (mPopupMenu != null) {
mPopupMenu.dismiss();
}
super.onDestroyView();
}
protected Object createMessageBusCallback() {
@ -522,11 +379,13 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
protected abstract long[] getAccountIds();
protected Data getAdapterData() {
return mAdapter.getData();
final AbsStatusesAdapter<Data> adapter = getAdapter();
return adapter.getData();
}
protected void setAdapterData(Data data) {
mAdapter.setData(data);
final AbsStatusesAdapter<Data> adapter = getAdapter();
adapter.setData(data);
}
protected String getReadPositionTag() {
@ -535,14 +394,16 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
protected abstract boolean hasMoreData(Data data);
protected abstract AbsStatusesAdapter<Data> onCreateAdapter(Context context, boolean compact);
protected abstract void onLoadingFinished();
protected void saveReadPosition() {
final String readPositionTag = getReadPositionTagWithAccounts();
if (readPositionTag == null) return;
final int position = mLayoutManager.findFirstVisibleItemPosition();
final LinearLayoutManager layoutManager = getLayoutManager();
final int position = layoutManager.findFirstVisibleItemPosition();
if (position == RecyclerView.NO_POSITION) return;
final ParcelableStatus status = mAdapter.getStatus(position);
final AbsStatusesAdapter<Data> adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
mReadStateManager.setPosition(readPositionTag, status.id);
mReadStateManager.setPosition(getCurrentReadPositionTag(), status.id, true);
@ -558,38 +419,6 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
return Utils.getReadPositionTagWithAccounts(getReadPositionTag(), getAccountIds());
}
private void setListShown(boolean shown) {
mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE);
}
@Override
public void onMediaClick(StatusViewHolder holder, ParcelableMedia media, int position) {
final ParcelableStatus status = mAdapter.getStatus(position);
if (status == null) return;
Utils.openMedia(getActivity(), status, media);
//spice
SpiceProfilingUtil.log(getActivity(),
status.id + ",Clicked," + status.account_id + "," + status.user_id + "," + status.text_plain.length()
+ "," + media.media_url + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + mAdapter.isMediaPreviewEnabled() + "," + status.timestamp);
SpiceProfilingUtil.profile(getActivity(), status.account_id,
status.id + ",Clicked," + status.account_id + "," + status.user_id + "," + status.text_plain.length()
+ "," + media.media_url + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + mAdapter.isMediaPreviewEnabled() + "," + status.timestamp);
//end
}
private void updateRefreshProgressOffset() {
if (mSystemWindowsInsets.top == 0 || mSwipeRefreshLayout == null || isRefreshing()) return;
final float density = getResources().getDisplayMetrics().density;
final int progressCircleDiameter = mSwipeRefreshLayout.getProgressCircleDiameter();
final int swipeStart = (mSystemWindowsInsets.top - mControlBarOffsetPixels) - progressCircleDiameter;
// 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET
final int swipeDistance = Math.round(64 * density);
mSwipeRefreshLayout.setProgressViewOffset(false, swipeStart, swipeStart + swipeDistance);
}
protected final class StatusesBusCallback {
protected StatusesBusCallback() {
@ -597,7 +426,8 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
@Subscribe
public void notifyStatusListChanged(StatusListChangedEvent event) {
mAdapter.notifyDataSetChanged();
final AbsStatusesAdapter<Data> adapter = getAdapter();
adapter.notifyDataSetChanged();
}
}

View File

@ -0,0 +1,110 @@
/*
* 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.annotation.Nullable;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import org.mariotaku.twidere.adapter.AbsUsersAdapter;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.model.ParcelableUser;
abstract class AbsUsersFragment<Data> extends AbsContentListFragment<AbsUsersAdapter<Data>> implements LoaderCallbacks<Data> {
public final Data getData() {
return getAdapter().getData();
}
@Override
public Loader<Data> onCreateLoader(int id, Bundle args) {
return newLoaderInstance(getActivity(), args);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
}
@Override
public final void onLoadFinished(Loader<Data> loader, Data data) {
final AbsUsersAdapter<Data> adapter = getAdapter();
final long lastReadId;
final int lastVisiblePos, lastVisibleTop;
final LinearLayoutManager layoutManager = getLayoutManager();
lastVisiblePos = layoutManager.findFirstVisibleItemPosition();
if (lastVisiblePos != RecyclerView.NO_POSITION) {
lastReadId = adapter.getUserId(lastVisiblePos);
final View positionView = layoutManager.findViewByPosition(lastVisiblePos);
lastVisibleTop = positionView != null ? positionView.getTop() : 0;
} else {
lastReadId = -1;
lastVisibleTop = 0;
}
adapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
adapter.setLoadMoreSupported(hasMoreData(data));
setRefreshEnabled(true);
int pos = -1;
for (int i = 0, j = adapter.getItemCount(); i < j; i++) {
if (lastReadId != -1 && lastReadId == adapter.getUserId(i)) {
pos = i;
break;
}
}
if (pos != -1 && adapter.isUser(pos) && (lastVisiblePos != 0)) {
layoutManager.scrollToPositionWithOffset(pos, lastVisibleTop);
}
}
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
setListShown(true);
onLoadingFinished(data);
}
protected abstract boolean hasMoreData(Data data);
@Override
public void onLoaderReset(Loader<Data> loader) {
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
}
protected ParcelableUser getSelectedUser() {
//TODO return selected
return null;
}
protected abstract Loader<Data> newLoaderInstance(Context context, Bundle args);
protected abstract void onLoadingFinished(Data data);
}

View File

@ -1,284 +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.fragment.support;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import org.mariotaku.twidere.adapter.ParcelableUsersAdapter;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter.MenuButtonClickListener;
import org.mariotaku.twidere.loader.support.DummyParcelableUsersLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList;
import java.util.Collections;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.clearListViewChoices;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
abstract class BaseUsersListFragment extends BasePullToRefreshListFragment implements
LoaderCallbacks<List<ParcelableUser>>, OnItemLongClickListener, OnMenuItemClickListener,
MultiSelectManager.Callback, MenuButtonClickListener {
private SharedPreferences mPreferences;
private MultiSelectManager mMultiSelectManager;
private ParcelableUsersAdapter mAdapter;
private ListView mListView;
private long mAccountId;
private final List<ParcelableUser> mData = Collections
.synchronizedList(new NoDuplicatesArrayList<ParcelableUser>());
private ParcelableUser mSelectedUser;
public long getAccountId() {
return mAccountId;
}
public final List<ParcelableUser> getData() {
return mData;
}
@Override
public ParcelableUsersAdapter getListAdapter() {
return mAdapter;
}
public SharedPreferences getSharedPreferences() {
return mPreferences;
}
public void loadMoreUsers() {
if (isRefreshing()) return;
final int count = mAdapter.getCount();
if (count - 1 > 0) {
final Bundle args = getArguments();
if (args != null) {
args.putLong(EXTRA_MAX_ID, mAdapter.getItem(count - 1).id);
}
if (!getLoaderManager().hasRunningLoaders()) {
getLoaderManager().restartLoader(0, args, this);
}
}
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mAdapter = new ParcelableUsersAdapter(getActivity());
mMultiSelectManager = getMultiSelectManager();
mListView = getListView();
mListView.setFastScrollEnabled(mPreferences.getBoolean(KEY_FAST_SCROLL_THUMB, false));
final Bundle args = getArguments() != null ? getArguments() : new Bundle();
final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1);
if (mAccountId != accountId) {
mAdapter.clear();
mData.clear();
}
mAccountId = accountId;
if (!mPreferences.getBoolean(KEY_COMPACT_CARDS, false)) {
mListView.setDivider(null);
}
mListView.setSelector(android.R.color.transparent);
mListView.setOnItemLongClickListener(this);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, getArguments(), this);
setListShown(false);
}
@Override
public Loader<List<ParcelableUser>> onCreateLoader(final int id, final Bundle args) {
setProgressBarIndeterminateVisibility(true);
final Loader<List<ParcelableUser>> loader = newLoaderInstance(getActivity(), args);
return loader != null ? loader : new DummyParcelableUsersLoader(getActivity());
}
@Override
public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position, final long id) {
final ParcelableUsersAdapter adapter = getListAdapter();
final int userPosition = adapter.findItemPosition(id);
if (userPosition < 0) return false;
final ParcelableUser user = adapter.getItem(userPosition);
setItemSelected(user, position, !mMultiSelectManager.isSelected(user));
return true;
}
@Override
public void onItemsCleared() {
clearListViewChoices(mListView);
}
@Override
public void onItemSelected(final Object item) {
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
@Override
public void onItemUnselected(final Object item) {
}
@Override
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
final ParcelableUsersAdapter adapter = getListAdapter();
final int userPosition = adapter.findItemPosition(id);
if (userPosition < 0) return;
final ParcelableUser user = adapter.getItem(userPosition);
if (mMultiSelectManager.isActive()) {
setItemSelected(user, position, !mMultiSelectManager.isSelected(user));
return;
}
openUserProfile(getActivity(), user, null);
}
@Override
public void onLoaderReset(final Loader<List<ParcelableUser>> loader) {
setProgressBarIndeterminateVisibility(false);
}
@Override
public void onLoadFinished(final Loader<List<ParcelableUser>> loader, final List<ParcelableUser> data) {
setProgressBarIndeterminateVisibility(false);
mAdapter.setData(data);
mAdapter.setShowAccountColor(shouldShowAccountColor());
setRefreshing(false);
setListShown(true);
}
@Override
public void onMenuButtonClick(final View button, final int position, final long id) {
final ParcelableUser user = mAdapter.getItem(position - mListView.getHeaderViewsCount());
if (user == null) return;
showMenu(button, user);
}
@Override
public boolean onMenuItemClick(final MenuItem item) {
if (mSelectedUser == null) return false;
switch (item.getItemId()) {
default: {
if (item.getIntent() != null) {
try {
startActivity(item.getIntent());
} catch (final ActivityNotFoundException e) {
Log.w(LOGTAG, e);
return false;
}
}
break;
}
}
return true;
}
@Override
public void onReachedBottom() {
loadMoreUsers();
}
@Override
public void onRefresh() {
if (isRefreshing()) return;
getLoaderManager().restartLoader(0, getArguments(), this);
}
@Override
public void onResume() {
super.onResume();
configBaseCardAdapter(getActivity(), mAdapter);
}
@Override
public void onStart() {
super.onStart();
mMultiSelectManager.registerCallback(this);
final int choiceMode = mListView.getChoiceMode();
if (mMultiSelectManager.isActive()) {
if (choiceMode != ListView.CHOICE_MODE_MULTIPLE) {
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
} else {
if (choiceMode != ListView.CHOICE_MODE_NONE) {
Utils.clearListViewChoices(mListView);
}
}
}
@Override
public void onStop() {
mMultiSelectManager.unregisterCallback(this);
super.onStop();
}
protected ParcelableUser getSelectedUser() {
return mSelectedUser;
}
protected int getUserMenuResource() {
return 0;
}
protected abstract Loader<List<ParcelableUser>> newLoaderInstance(Context context, Bundle args);
protected final void removeUsers(final long... userIds) {
if (userIds == null || userIds.length == 0) return;
for (final long userId : userIds) {
mData.remove(mAdapter.findItemPosition(userId));
}
mAdapter.setData(mData, true);
}
protected void setItemSelected(final ParcelableUser user, final int position, final boolean selected) {
if (selected) {
mMultiSelectManager.selectItem(user);
} else {
mMultiSelectManager.unselectItem(user);
}
mListView.setItemChecked(position, selected);
}
protected boolean shouldShowAccountColor() {
return getActivatedAccountIds(getActivity()).length > 1;
}
private void showMenu(final View view, final ParcelableUser user) {
mSelectedUser = user;
//TODO show menu
}
}

View File

@ -28,6 +28,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.content.Loader;
import com.squareup.otto.Subscribe;
@ -172,6 +173,7 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor>
return cursor != null && cursor.getCount() != 0;
}
@NonNull
@Override
protected CursorStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new CursorStatusesAdapter(context, compact);

View File

@ -28,7 +28,7 @@ import org.mariotaku.twidere.model.ParcelableUser;
import java.util.List;
public abstract class CursorSupportUsersListFragment extends BaseUsersListFragment {
public abstract class CursorSupportUsersListFragment extends ParcelableUsersFragment {
private long mNextCursor, mPrevCursor;
@ -58,15 +58,13 @@ public abstract class CursorSupportUsersListFragment extends BaseUsersListFragme
mPrevCursor = -1;
}
@Override
public void onLoadFinished(final Loader<List<ParcelableUser>> loader, final List<ParcelableUser> data) {
super.onLoadFinished(loader, data);
final BaseCursorSupportUsersLoader cursorLoader = (BaseCursorSupportUsersLoader) loader;
mNextCursor = cursorLoader.getNextCursor();
mPrevCursor = cursorLoader.getPrevCursor();
// TODO
// setEnabled(mNextCursor > 0 ? "from_end" : "disabled");
}
// @Override
// public void onLoadFinished(final Loader<List<ParcelableUser>> loader, final List<ParcelableUser> data) {
// super.onLoadFinished(loader, data);
// final BaseCursorSupportUsersLoader cursorLoader = (BaseCursorSupportUsersLoader) loader;
// mNextCursor = cursorLoader.getNextCursor();
// mPrevCursor = cursorLoader.getPrevCursor();
// }
@Override
public void onSaveInstanceState(final Bundle outState) {

View File

@ -21,12 +21,9 @@ package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.view.MenuItem;
import org.mariotaku.twidere.loader.support.IDsUsersLoader;
import org.mariotaku.twidere.loader.support.IncomingFriendshipsLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class IncomingFriendshipsFragment extends CursorSupportUsersListFragment {
@ -37,25 +34,4 @@ public class IncomingFriendshipsFragment extends CursorSupportUsersListFragment
return new IncomingFriendshipsLoader(context, accountId, getNextCursor(), getData());
}
@Override
public boolean onMenuItemClick(final MenuItem item) {
switch (item.getItemId()) {
case MENU_ACCEPT: {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
final ParcelableUser user = getSelectedUser();
if (twitter == null || user == null) return false;
twitter.acceptFriendshipAsync(user.account_id, user.id);
break;
}
case MENU_DENY: {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
final ParcelableUser user = getSelectedUser();
if (twitter == null || user == null) return false;
twitter.denyFriendshipAsync(user.account_id, user.id);
break;
}
}
return super.onMenuItemClick(item);
}
}

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.adapter.CursorStatusesAdapter;
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
@ -36,6 +37,7 @@ public class MentionsTimelineFragment extends CursorStatusesFragment {
return Mentions.CONTENT_URI;
}
@NonNull
@Override
protected CursorStatusesAdapter onCreateAdapter(Context context, boolean compact) {
final CursorStatusesAdapter adapter = super.onCreateAdapter(context, compact);

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.LoaderManager;
import com.squareup.otto.Bus;
@ -107,6 +108,7 @@ public abstract class ParcelableStatusesFragment extends AbsStatusesFragment<Lis
return new ParcelableStatusesBusCallback();
}
@NonNull
@Override
protected ParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableStatusesAdapter(context, compact);

View File

@ -0,0 +1,72 @@
/*
* 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.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.LoaderManager;
import org.mariotaku.twidere.adapter.ParcelableUsersAdapter;
import org.mariotaku.twidere.model.ParcelableUser;
import java.util.List;
public abstract class ParcelableUsersFragment extends AbsUsersFragment<List<ParcelableUser>> {
@Override
public boolean isRefreshing() {
final LoaderManager lm = getLoaderManager();
return lm.hasRunningLoaders();
}
@NonNull
@Override
protected final ParcelableUsersAdapter onCreateAdapter(Context context, boolean compact) {
return new ParcelableUsersAdapter(context, compact);
}
@Override
public boolean triggerRefresh() {
return false;
}
protected long getAccountId() {
final Bundle args = getArguments();
return args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
}
@Override
protected boolean hasMoreData(List<ParcelableUser> data) {
return data == null || data.isEmpty();
}
@Override
protected void onLoadingFinished(List<ParcelableUser> data) {
setRefreshEnabled(true);
setRefreshing(false);
setLoadMoreIndicatorVisible(false);
}
protected void removeUsers(long... ids) {
//TODO remove from adapter
}
}

View File

@ -21,17 +21,14 @@ package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.Loader;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import org.mariotaku.twidere.loader.support.UserSearchLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import java.util.List;
public class SearchUsersFragment extends BaseUsersListFragment {
public class SearchUsersFragment extends ParcelableUsersFragment {
private int mPage = 1;
@ -58,11 +55,10 @@ public class SearchUsersFragment extends BaseUsersListFragment {
}
@Override
public void onLoadFinished(final Loader<List<ParcelableUser>> loader, final List<ParcelableUser> data) {
public void onLoadingFinished(final List<ParcelableUser> data) {
if (data != null) {
mPage++;
}
super.onLoadFinished(loader, data);
}
@Override
@ -71,15 +67,4 @@ public class SearchUsersFragment extends BaseUsersListFragment {
super.onSaveInstanceState(outState);
}
@Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
super.onScrollStateChanged(view, scrollState);
if (scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
final Fragment parent = getParentFragment();
if (parent instanceof SearchFragment) {
((SearchFragment) parent).hideIndicator();
}
}
}
}

View File

@ -96,7 +96,7 @@ import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ClipboardUtils;
import org.mariotaku.twidere.util.CompareUtils;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MenuUtils;
@ -366,6 +366,11 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
openStatus(getActivity(), mStatusAdapter.getStatus(position), null);
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
return false;
}
@Override
public void onStatusMenuClick(StatusViewHolder holder, View menuView, int position) {
//TODO show status menu
@ -606,7 +611,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
final StatusFragment fragment = adapter.getFragment();
final Context context = adapter.getContext();
final Resources resources = context.getResources();
final MediaLoaderWrapper loader = adapter.getImageLoader();
final MediaLoaderWrapper loader = adapter.getMediaLoader();
final boolean nameFirst = adapter.isNameFirst();
linkClickHandler.setStatus(status);
@ -730,7 +735,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
mediaPreview.setVisibility(View.VISIBLE);
mediaPreviewLoad.setVisibility(View.GONE);
mediaPreview.displayMedia(status.media, loader, status.account_id,
adapter.getFragment(), adapter.getImageLoadingHandler());
adapter.getFragment(), adapter.getMediaLoadingHandler());
} else {
mediaPreviewContainer.setVisibility(View.VISIBLE);
mediaPreview.setVisibility(View.GONE);
@ -1021,7 +1026,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
private final StatusFragment mFragment;
private final LayoutInflater mInflater;
private final MediaLoaderWrapper mImageLoader;
private final ImageLoadingHandler mImageLoadingHandler;
private final MediaLoadingHandler mMediaLoadingHandler;
private final TwidereLinkify mTwidereLinkify;
private final boolean mNameFirst;
@ -1056,7 +1061,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
mContext = context;
mInflater = LayoutInflater.from(context);
mImageLoader = TwidereApplication.getInstance(context).getMediaLoaderWrapper();
mImageLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
mMediaLoadingHandler = new MediaLoadingHandler(R.id.media_preview_progress);
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context);
mNameFirst = preferences.getBoolean(KEY_NAME_FIRST, true);
mTextSize = preferences.getInt(KEY_TEXT_SIZE, res.getInteger(R.integer.default_text_size));
@ -1096,7 +1101,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
return mFragment;
}
public MediaLoaderWrapper getImageLoader() {
public MediaLoaderWrapper getMediaLoader() {
return mImageLoader;
}
@ -1105,8 +1110,8 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
@Override
public ImageLoadingHandler getImageLoadingHandler() {
return mImageLoadingHandler;
public MediaLoadingHandler getMediaLoadingHandler() {
return mMediaLoadingHandler;
}
@Override
@ -1119,6 +1124,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
return mMediaPreviewStyle;
}
@NonNull
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return mFragment.getTwitterWrapper();
@ -1266,6 +1272,11 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
return false;
}
@Override
public void onMediaClick(StatusViewHolder holder, ParcelableMedia media, int position) {
if (mStatusAdapterListener != null) {

View File

@ -25,13 +25,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.loader.support.CursorSupportUsersLoader;
import org.mariotaku.twidere.loader.support.UserListMembersLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.AsyncTaskUtils;
@ -41,7 +37,7 @@ import twitter4j.UserList;
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
public class UserListMembersFragment extends CursorSupportUsersListFragment implements OnMenuItemClickListener {
public class UserListMembersFragment extends CursorSupportUsersListFragment {
private ParcelableUserList mUserList;
@ -91,22 +87,6 @@ public class UserListMembersFragment extends CursorSupportUsersListFragment impl
}
}
@Override
public boolean onMenuItemClick(final MenuItem item) {
final ParcelableUser user = getSelectedUser();
if (user == null || mUserList == null) return false;
switch (item.getItemId()) {
case MENU_DELETE_FROM_LIST: {
DeleteUserListMembersDialogFragment.show(getFragmentManager(), mUserList, user);
break;
}
default: {
return super.onMenuItemClick(item);
}
}
return true;
}
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(EXTRA_USER_LIST, mUserList);
@ -126,11 +106,6 @@ public class UserListMembersFragment extends CursorSupportUsersListFragment impl
super.onStop();
}
@Override
protected int getUserMenuResource() {
return R.menu.action_user_list_member;
}
private class GetUserListTask extends AsyncTask<Object, Object, ParcelableUserList> {
private final long accountId, userId;

View File

@ -22,7 +22,7 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.loader.support.MediaTimelineLoader;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
@ -162,13 +162,13 @@ public class UserMediaTimelineFragment extends BaseSupportFragment
private final LayoutInflater mInflater;
private final MediaLoaderWrapper mImageLoader;
private final ImageLoadingHandler mLoadingHandler;
private final MediaLoadingHandler mLoadingHandler;
private List<ParcelableStatus> mData;
MediaTimelineAdapter(Context context) {
mInflater = LayoutInflater.from(context);
mImageLoader = TwidereApplication.getInstance(context).getMediaLoaderWrapper();
mLoadingHandler = new ImageLoadingHandler(R.id.media_image_progress);
mLoadingHandler = new MediaLoadingHandler(R.id.media_image_progress);
}
@Override
@ -208,7 +208,7 @@ public class UserMediaTimelineFragment extends BaseSupportFragment
mediaTextView = (TextView) itemView.findViewById(R.id.media_text);
}
public void setMedia(MediaLoaderWrapper loader, ImageLoadingHandler loadingHandler, ParcelableStatus status) {
public void setMedia(MediaLoaderWrapper loader, MediaLoadingHandler loadingHandler, ParcelableStatus status) {
final ParcelableMedia[] media = status.media;
if (media == null || media.length < 1) return;
final ParcelableMedia firstMedia = media[0];

View File

@ -28,7 +28,7 @@ import org.mariotaku.twidere.model.ParcelableUser;
import java.util.List;
public class UsersListFragment extends BaseUsersListFragment {
public class UsersListFragment extends ParcelableUsersFragment {
@Override
public Loader<List<ParcelableUser>> newLoaderInstance(final Context context, final Bundle args) {

View File

@ -2383,7 +2383,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count);
} else {
for (final ParcelableMedia spiceMedia : status.media) {
if (TypeMappingUtil.getMediaType(spiceMedia.type).equals("image")) {
if (spiceMedia.type == ParcelableMedia.TYPE_IMAGE) {
SpiceProfilingUtil.log(getContext(), status.id + ",RetweetM," + account_id + ","
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + spiceMedia.media_url + "," + TypeMappingUtil.getMediaType(spiceMedia.type) + "," + spiceMedia.width + "x" + spiceMedia.height);

View File

@ -94,12 +94,12 @@ public class MediaLoaderWrapper implements Constants {
mImageLoader.displayImage(uri, view, mImageDisplayOptions);
}
public void displayPreviewImage(final ImageView view, final String url, final ImageLoadingHandler loadingHandler) {
public void displayPreviewImage(final ImageView view, final String url, final MediaLoadingHandler loadingHandler) {
mImageLoader.displayImage(url, view, mImageDisplayOptions, loadingHandler, loadingHandler);
}
public void displayPreviewImageWithCredentials(final ImageView view, final String url, final long accountId,
final ImageLoadingHandler loadingHandler) {
final MediaLoadingHandler loadingHandler) {
final DisplayImageOptions.Builder b = new DisplayImageOptions.Builder();
b.cloneFrom(mImageDisplayOptions);
b.extraForDownloader(new AccountExtra(accountId));

View File

@ -39,16 +39,16 @@ import org.mariotaku.twidere.view.ForegroundImageView;
import java.util.HashMap;
import java.util.Map;
public class ImageLoadingHandler implements ImageLoadingListener, ImageLoadingProgressListener {
public class MediaLoadingHandler implements ImageLoadingListener, ImageLoadingProgressListener {
private final Map<View, String> mLoadingUris = new HashMap<>();
private final int[] mProgressBarIds;
public ImageLoadingHandler() {
public MediaLoadingHandler() {
this(R.id.media_preview_progress);
}
public ImageLoadingHandler(final int... progressBarIds) {
public MediaLoadingHandler(final int... progressBarIds) {
mProgressBarIds = progressBarIds;
}

View File

@ -35,7 +35,7 @@ import android.widget.TextView;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.Utils.OnMediaClickListener;
@ -92,7 +92,7 @@ public class CardMediaContainer extends ViewGroup implements Constants {
@NonNull final MediaLoaderWrapper loader,
final long accountId,
final OnMediaClickListener mediaClickListener,
final ImageLoadingHandler loadingHandler) {
final MediaLoadingHandler loadingHandler) {
if (mediaArray == null || mMediaPreviewStyle == VALUE_MEDIA_PREVIEW_STYLE_CODE_NONE) {
for (int i = 0, j = getChildCount(); i < j; i++) {
final View child = getChildAt(i);

View File

@ -156,7 +156,7 @@ public class ActivityTitleSummaryViewHolder extends ViewHolder {
}
private void displayUserProfileImages(final ParcelableUser[] statuses) {
final MediaLoaderWrapper imageLoader = adapter.getImageLoader();
final MediaLoaderWrapper imageLoader = adapter.getMediaLoader();
if (statuses == null) {
for (final ImageView view : profileImageViews) {
imageLoader.cancelDisplayTask(view);

View File

@ -67,7 +67,7 @@ public class MessageEntryViewHolder extends ViewHolder implements OnClickListene
public void displayMessage(Cursor cursor, boolean isUnread) {
final Context context = adapter.getContext();
final MediaLoaderWrapper loader = adapter.getImageLoader();
final MediaLoaderWrapper loader = adapter.getMediaLoader();
final long accountId = cursor.getLong(ConversationEntries.IDX_ACCOUNT_ID);
final long conversationId = cursor.getLong(ConversationEntries.IDX_CONVERSATION_ID);

View File

@ -5,13 +5,13 @@ import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.ImageView;
import android.widget.TextView;
@ -25,7 +25,7 @@ import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatus.CursorIndices;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.SimpleValueSerializer;
@ -53,8 +53,8 @@ import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;
* <p/>
* Created by mariotaku on 14/11/19.
*/
public class StatusViewHolder extends RecyclerView.ViewHolder implements Constants, OnClickListener,
OnMediaClickListener {
public class StatusViewHolder extends ViewHolder implements Constants, OnClickListener,
OnMediaClickListener, OnLongClickListener {
@NonNull
private final IStatusesAdapter<?> adapter;
@ -135,7 +135,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
public void displayStatus(@NonNull final ParcelableStatus status, @Nullable final TranslationResult translation,
final boolean displayInReplyTo, final boolean shouldDisplayExtraType) {
final MediaLoaderWrapper loader = adapter.getImageLoader();
final MediaLoaderWrapper loader = adapter.getMediaLoader();
final AsyncTwitterWrapper twitter = adapter.getTwitterWrapper();
final TwidereLinkify linkify = adapter.getTwidereLinkify();
final Context context = adapter.getContext();
@ -255,7 +255,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
if (hasMedia && (adapter.isSensitiveContentEnabled() || !status.is_possibly_sensitive)) {
mediaPreview.setVisibility(hasMedia ? View.VISIBLE : View.GONE);
mediaPreview.displayMedia(status.media, loader, status.account_id, this,
adapter.getImageLoadingHandler());
adapter.getMediaLoadingHandler());
} else {
mediaPreview.setVisibility(View.GONE);
}
@ -272,8 +272,9 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
textView.setMovementMethod(null);
}
final Locale locale = Locale.getDefault();
if (reply_count > 0) {
replyCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), reply_count));
replyCountView.setText(Utils.getLocalizedNumber(locale, reply_count));
} else {
replyCountView.setText(null);
}
@ -288,7 +289,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
retweet_count = status.retweet_count + (creatingRetweet ? 1 : 0);
}
if (retweet_count > 0) {
retweetCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), retweet_count));
retweetCountView.setText(Utils.getLocalizedNumber(locale, retweet_count));
} else {
retweetCountView.setText(null);
}
@ -301,7 +302,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
favorite_count = status.favorite_count + (creatingFavorite ? 1 : 0);
}
if (favorite_count > 0) {
favoriteCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), favorite_count));
favoriteCountView.setText(Utils.getLocalizedNumber(locale, favorite_count));
} else {
favoriteCountView.setText(null);
}
@ -315,7 +316,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
public void displayStatus(@NonNull Cursor cursor, @NonNull CursorIndices indices,
final boolean displayInReplyTo) {
final MediaLoaderWrapper loader = adapter.getImageLoader();
final MediaLoaderWrapper loader = adapter.getMediaLoader();
final AsyncTwitterWrapper twitter = adapter.getTwitterWrapper();
final TwidereLinkify linkify = adapter.getTwidereLinkify();
final Context context = adapter.getContext();
@ -459,7 +460,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
final boolean hasMedia = media != null && media.length > 0;
if (hasMedia && (adapter.isSensitiveContentEnabled() || !sensitive)) {
mediaPreview.setVisibility(hasMedia ? View.VISIBLE : View.GONE);
mediaPreview.displayMedia(media, loader, account_id, this, adapter.getImageLoadingHandler());
mediaPreview.displayMedia(media, loader, account_id, this, adapter.getMediaLoadingHandler());
} else {
mediaPreview.setVisibility(View.GONE);
}
@ -528,7 +529,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
@Override
public void onClick(View v) {
if (statusClickListener == null) return;
final int position = getAdapterPosition();
final int position = getLayoutPosition();
switch (v.getId()) {
case R.id.item_content: {
statusClickListener.onStatusClick(this, position);
@ -551,10 +552,22 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
}
}
@Override
public boolean onLongClick(View v) {
if (statusClickListener == null) return false;
final int position = getLayoutPosition();
switch (v.getId()) {
case R.id.item_content: {
return statusClickListener.onStatusLongClick(this, position);
}
}
return false;
}
@Override
public void onMediaClick(View view, ParcelableMedia media, long accountId) {
if (statusClickListener == null) return;
final int position = getAdapterPosition();
final int position = getLayoutPosition();
statusClickListener.onMediaClick(this, media, position);
}
@ -564,10 +577,10 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
public void setStatusClickListener(StatusClickListener listener) {
statusClickListener = listener;
itemView.findViewById(R.id.item_content).setOnClickListener(this);
((View) itemContent).setOnClickListener(this);
((View) itemContent).setOnLongClickListener(this);
itemMenu.setOnClickListener(this);
itemView.setOnClickListener(this);
profileImageView.setOnClickListener(this);
replyCountView.setOnClickListener(this);
retweetCountView.setOnClickListener(this);
@ -630,12 +643,12 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
public static interface StatusClickListener extends ContentCardClickListener {
boolean isProfileImageEnabled();
void onMediaClick(StatusViewHolder holder, ParcelableMedia media, int position);
void onStatusClick(StatusViewHolder holder, int position);
boolean onStatusLongClick(StatusViewHolder holder, int position);
void onUserProfileClick(StatusViewHolder holder, int position);
}
@ -644,7 +657,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
private final Context context;
private final SharedPreferencesWrapper preferences;
private final MediaLoaderWrapper loader;
private final ImageLoadingHandler handler;
private final MediaLoadingHandler handler;
private final AsyncTwitterWrapper twitter;
private final TwidereLinkify linkify;
private int profileImageStyle;
@ -662,14 +675,14 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
preferences = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final TwidereApplication app = TwidereApplication.getInstance(context);
loader = app.getMediaLoaderWrapper();
handler = new ImageLoadingHandler(R.id.media_preview_progress);
handler = new MediaLoadingHandler(R.id.media_preview_progress);
twitter = app.getTwitterWrapper();
linkify = new TwidereLinkify(null);
updateOptions();
}
@Override
public MediaLoaderWrapper getImageLoader() {
public MediaLoaderWrapper getMediaLoader() {
return loader;
}
@ -679,7 +692,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
}
@Override
public ImageLoadingHandler getImageLoadingHandler() {
public MediaLoadingHandler getMediaLoadingHandler() {
return handler;
}
@ -698,6 +711,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
return mediaPreviewStyle;
}
@NonNull
@Override
public AsyncTwitterWrapper getTwitterWrapper() {
return twitter;
@ -807,6 +821,11 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
return false;
}
@Override
public void onMediaClick(StatusViewHolder holder, ParcelableMedia media, int position) {

View File

@ -0,0 +1,134 @@
/*
* 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.graphics.Color;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IContentCardAdapter;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.view.iface.IColorLabelView;
import java.util.Locale;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserColor;
import static org.mariotaku.twidere.util.UserColorNameUtils.getUserNickname;
import static org.mariotaku.twidere.util.Utils.getLocalizedNumber;
import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;
public class UserViewHolder extends ViewHolder {
private final IContentCardAdapter adapter;
public final IColorLabelView content;
private final ImageView profileImageView, profileTypeView;
private final TextView name, screenName, description, location, url, statusesCount, followersCount,
friendsCount;
private boolean account_color_enabled;
public UserViewHolder(final IContentCardAdapter adapter, final View itemView) {
super(itemView);
this.adapter = adapter;
content = (IColorLabelView) itemView.findViewById(R.id.content);
profileImageView = (ImageView) itemView.findViewById(R.id.profile_image);
profileTypeView = (ImageView) itemView.findViewById(R.id.profile_type);
name = (TextView) itemView.findViewById(R.id.name);
screenName = (TextView) itemView.findViewById(R.id.screen_name);
description = (TextView) itemView.findViewById(R.id.description);
location = (TextView) itemView.findViewById(R.id.location);
url = (TextView) itemView.findViewById(R.id.url);
statusesCount = (TextView) itemView.findViewById(R.id.statuses_count);
followersCount = (TextView) itemView.findViewById(R.id.followers_count);
friendsCount = (TextView) itemView.findViewById(R.id.friends_count);
}
public void setAccountColor(final int color) {
content.drawEnd(account_color_enabled ? color : Color.TRANSPARENT);
}
public void setAccountColorEnabled(final boolean enabled) {
account_color_enabled = enabled;
if (!account_color_enabled) {
content.drawEnd(Color.TRANSPARENT);
}
}
public void setHighlightColor(final int color) {
content.drawBackground(color);
}
public void setTextSize(final float textSize) {
description.setTextSize(textSize);
name.setTextSize(textSize);
screenName.setTextSize(textSize * 0.75f);
location.setTextSize(textSize);
url.setTextSize(textSize);
statusesCount.setTextSize(textSize);
followersCount.setTextSize(textSize);
friendsCount.setTextSize(textSize);
}
public void displayUser(ParcelableUser user) {
final Context context = adapter.getContext();
final MediaLoaderWrapper loader = adapter.getMediaLoader();
setUserColor(getUserColor(context, user.id));
final int userTypeRes = getUserTypeIconRes(user.is_verified, user.is_protected);
if (userTypeRes != 0) {
profileTypeView.setImageResource(userTypeRes);
} else {
profileTypeView.setImageDrawable(null);
}
name.setText(getUserNickname(context, user.id, user.name));
screenName.setText("@" + user.screen_name);
description.setVisibility(TextUtils.isEmpty(user.description_unescaped) ? View.GONE : View.VISIBLE);
description.setText(user.description_unescaped);
location.setVisibility(TextUtils.isEmpty(user.location) ? View.GONE : View.VISIBLE);
location.setText(user.location);
url.setVisibility(TextUtils.isEmpty(user.url_expanded) ? View.GONE : View.VISIBLE);
url.setText(user.url_expanded);
final Locale locale = Locale.getDefault();
statusesCount.setText(getLocalizedNumber(locale, user.statuses_count));
followersCount.setText(getLocalizedNumber(locale, user.followers_count));
friendsCount.setText(getLocalizedNumber(locale, user.friends_count));
if (adapter.isProfileImageEnabled()) {
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, user.profile_image_url);
} else {
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
}
}
public void setUserColor(final int color) {
content.drawStart(color);
}
}