Twidere-App-Android-Twitter.../twidere/src/main/java/org/mariotaku/twidere/fragment/AbsStatusesFragment.java

694 lines
30 KiB
Java
Raw Normal View History

2015-11-30 06:32:05 +01:00
/*
* 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/>.
*/
2016-03-18 17:04:03 +01:00
package org.mariotaku.twidere.fragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
2016-06-14 03:33:53 +02:00
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
2016-03-30 09:07:22 +02:00
import android.support.v4.app.FragmentManager;
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.support.v7.widget.RecyclerView.OnScrollListener;
2016-03-10 05:23:04 +01:00
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import com.squareup.otto.Subscribe;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.abstask.library.TaskStarter;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.R;
2016-03-09 17:12:09 +01:00
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
2016-06-14 03:33:53 +02:00
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
2016-02-03 20:27:43 +01:00
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
import org.mariotaku.twidere.annotation.ReadPositionTag;
2016-03-30 09:07:22 +02:00
import org.mariotaku.twidere.constant.IntentConstants;
2016-02-21 21:26:16 +01:00
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable;
2015-01-10 16:17:02 +01:00
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
2016-03-06 13:59:24 +01:00
import org.mariotaku.twidere.model.BaseRefreshTaskParam;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
2016-03-06 13:59:24 +01:00
import org.mariotaku.twidere.model.RefreshTaskParam;
2016-03-07 18:25:18 +01:00
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.StatusListChangedEvent;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
2015-11-10 09:03:03 +01:00
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MenuUtils;
import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
import org.mariotaku.twidere.util.RecyclerViewUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.imageloader.PauseRecyclerViewOnScrollListener;
import org.mariotaku.twidere.view.ExtendedRecyclerView;
import org.mariotaku.twidere.view.holder.GapViewHolder;
2016-03-21 01:34:20 +01:00
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
2015-08-30 13:31:15 +02:00
import java.util.TimeZone;
2015-08-16 04:50:56 +02:00
import edu.tsinghua.hotmobi.HotMobiLogger;
import edu.tsinghua.hotmobi.model.MediaEvent;
import edu.tsinghua.hotmobi.model.ScrollRecord;
import edu.tsinghua.hotmobi.model.TimelineType;
2015-03-04 09:02:32 +01:00
/**
* Created by mariotaku on 14/11/5.
*/
2016-03-09 17:12:09 +01:00
public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFragment<ParcelableStatusesAdapter>
2016-03-21 01:34:20 +01:00
implements LoaderCallbacks<List<ParcelableStatus>>, IStatusViewHolder.StatusClickListener, KeyboardShortcutCallback {
2015-01-14 09:47:51 +01:00
private final Object mStatusesBusCallback;
private final OnScrollListener mHotMobiScrollTracker = new OnScrollListener() {
public List<ScrollRecord> mRecords;
2016-03-10 05:23:04 +01:00
private String mFirstVisibleId;
2016-03-07 18:25:18 +01:00
private UserKey mFirstVisibleAccountId = null;
private int mFirstVisiblePosition = -1;
private int mScrollState;
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
final int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
2015-09-02 09:03:17 +02:00
if (firstVisiblePosition != mFirstVisiblePosition && firstVisiblePosition >= 0) {
//noinspection unchecked
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = (ParcelableStatusesAdapter) recyclerView.getAdapter();
final ParcelableStatus status = adapter.getStatus(firstVisiblePosition);
if (status != null) {
2016-03-10 05:23:04 +01:00
final String id = status.id;
2016-03-07 18:25:18 +01:00
final UserKey accountId = status.account_key;
2016-03-10 05:23:04 +01:00
if (!TextUtils.equals(id, mFirstVisibleId) || !accountId.equals(mFirstVisibleAccountId)) {
if (mRecords == null) mRecords = new ArrayList<>();
2015-08-30 13:31:15 +02:00
final long time = System.currentTimeMillis();
mRecords.add(ScrollRecord.create(id, accountId, time,
TimeZone.getDefault().getOffset(time), mScrollState));
}
mFirstVisibleId = id;
mFirstVisibleAccountId = accountId;
}
}
mFirstVisiblePosition = firstVisiblePosition;
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
mScrollState = newState;
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (mRecords != null) {
2016-03-06 13:59:24 +01:00
HotMobiLogger.getInstance(getActivity()).logList(mRecords, null, "scroll");
}
mRecords = null;
}
}
};
2015-09-02 09:03:17 +02:00
private final OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
final LinearLayoutManager layoutManager = getLayoutManager();
saveReadPosition(layoutManager.findFirstVisibleItemPosition());
}
}
};
private RecyclerViewNavigationHelper mNavigationHelper;
private OnScrollListener mPauseOnScrollListener;
private OnScrollListener mActiveHotMobiScrollTracker;
2015-01-10 16:17:02 +01:00
protected AbsStatusesFragment() {
mStatusesBusCallback = createMessageBusCallback();
}
2016-03-06 13:59:24 +01:00
public abstract boolean getStatuses(RefreshTaskParam param);
@Override
2015-10-07 16:09:00 +02:00
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState);
if (ACTION_NAVIGATION_REFRESH.equals(action)) {
triggerRefresh();
return true;
}
2015-09-07 04:07:03 +02:00
final RecyclerView recyclerView = getRecyclerView();
2015-04-16 14:48:24 +02:00
final LinearLayoutManager layoutManager = getLayoutManager();
2015-09-07 04:07:03 +02:00
if (recyclerView == null || layoutManager == null) return false;
2015-10-07 16:09:00 +02:00
final View focusedChild = RecyclerViewUtils.findRecyclerViewChild(recyclerView,
layoutManager.getFocusedChild());
int position = -1;
2015-09-07 04:07:03 +02:00
if (focusedChild != null && focusedChild.getParent() == recyclerView) {
position = recyclerView.getChildLayoutPosition(focusedChild);
}
2015-10-07 16:09:00 +02:00
if (position != -1) {
final ParcelableStatus status = getAdapter().getStatus(position);
if (status == null) return false;
if (keyCode == KeyEvent.KEYCODE_ENTER) {
2016-03-07 03:43:09 +01:00
IntentUtils.openStatus(getActivity(), status, null);
return true;
}
2015-10-07 16:09:00 +02:00
if (action == null) {
action = handler.getKeyAction(CONTEXT_TAG_STATUS, keyCode, event, metaState);
}
2015-10-07 16:09:00 +02:00
if (action == null) return false;
switch (action) {
case ACTION_STATUS_REPLY: {
final Intent intent = new Intent(INTENT_ACTION_REPLY);
intent.putExtra(EXTRA_STATUS, status);
startActivity(intent);
return true;
}
case ACTION_STATUS_RETWEET: {
RetweetQuoteDialogFragment.show(getFragmentManager(), status);
return true;
}
case ACTION_STATUS_FAVORITE: {
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (status.is_favorite) {
2016-03-07 06:05:08 +01:00
twitter.destroyFavoriteAsync(status.account_key, status.id);
2015-10-07 16:09:00 +02:00
} else {
2016-02-18 17:21:04 +01:00
final IStatusViewHolder holder = (IStatusViewHolder)
recyclerView.findViewHolderForLayoutPosition(position);
holder.playLikeAnimation(new DefaultOnLikedListener(twitter, status));
2015-10-07 16:09:00 +02:00
}
return true;
}
}
}
2015-10-07 16:09:00 +02:00
return mNavigationHelper.handleKeyboardShortcutSingle(handler, keyCode, event, metaState);
}
2015-08-16 04:50:56 +02:00
@Override
2015-10-07 16:09:00 +02:00
public boolean isKeyboardShortcutHandled(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState);
2015-08-16 04:50:56 +02:00
if (ACTION_NAVIGATION_REFRESH.equals(action)) {
return true;
}
if (action == null) {
2015-10-07 16:09:00 +02:00
action = handler.getKeyAction(CONTEXT_TAG_STATUS, keyCode, event, metaState);
2015-08-16 04:50:56 +02:00
}
if (action == null) return false;
switch (action) {
case ACTION_STATUS_REPLY:
case ACTION_STATUS_RETWEET:
case ACTION_STATUS_FAVORITE:
return true;
}
2015-10-07 16:09:00 +02:00
return mNavigationHelper.isKeyboardShortcutHandled(handler, keyCode, event, metaState);
2015-08-16 04:50:56 +02:00
}
@Override
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, final int keyCode, final int repeatCount,
2015-10-07 16:09:00 +02:00
@NonNull final KeyEvent event, int metaState) {
return mNavigationHelper.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState);
}
2015-03-12 10:43:28 +01:00
@Override
2016-03-09 17:12:09 +01:00
public final Loader<List<ParcelableStatus>> onCreateLoader(int id, Bundle args) {
2015-03-12 10:43:28 +01:00
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
args.remove(EXTRA_FROM_USER);
return onCreateStatusesLoader(getActivity(), args, fromUser);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
2016-03-03 14:06:12 +01:00
saveReadPosition();
}
}
2015-03-12 10:43:28 +01:00
@Override
2016-03-09 17:12:09 +01:00
public final void onLoadFinished(Loader<List<ParcelableStatus>> loader, List<ParcelableStatus> data) {
final ParcelableStatusesAdapter adapter = getAdapter();
2015-11-03 11:32:32 +01:00
final boolean rememberPosition = mPreferences.getBoolean(KEY_REMEMBER_POSITION, false);
final boolean readFromBottom = mPreferences.getBoolean(KEY_READ_FROM_BOTTOM, false);
long lastReadPositionKey;
2015-03-12 10:43:28 +01:00
final int lastVisiblePos, lastVisibleTop;
final String tag = getCurrentReadPositionTag();
2015-05-11 12:54:41 +02:00
final LinearLayoutManager layoutManager = getLayoutManager();
2015-03-12 10:43:28 +01:00
if (readFromBottom) {
2015-05-11 12:54:41 +02:00
lastVisiblePos = layoutManager.findLastVisibleItemPosition();
2015-03-12 10:43:28 +01:00
} else {
2015-05-11 12:54:41 +02:00
lastVisiblePos = layoutManager.findFirstVisibleItemPosition();
2015-03-12 10:43:28 +01:00
}
2015-09-02 09:03:17 +02:00
if (lastVisiblePos != RecyclerView.NO_POSITION && lastVisiblePos < adapter.getItemCount()) {
2016-02-10 03:04:15 +01:00
final int statusStartIndex = adapter.getStatusStartIndex();
final int statusEndIndex = statusStartIndex + adapter.getStatusCount();
2016-02-08 13:23:26 +01:00
final int lastItemIndex = Math.min(statusEndIndex, lastVisiblePos);
lastReadPositionKey = adapter.getStatusPositionKey(lastItemIndex);
2016-02-08 13:23:26 +01:00
final View positionView = layoutManager.findViewByPosition(lastItemIndex);
2015-04-08 11:47:34 +02:00
lastVisibleTop = positionView != null ? positionView.getTop() : 0;
} else if (rememberPosition && tag != null) {
lastReadPositionKey = mReadStateManager.getPosition(tag);
lastVisibleTop = 0;
2015-03-12 10:43:28 +01:00
} else {
lastReadPositionKey = -1;
2015-03-12 10:43:28 +01:00
lastVisibleTop = 0;
}
2015-04-16 14:48:24 +02:00
adapter.setData(data);
2016-02-10 03:04:15 +01:00
final int statusStartIndex = adapter.getStatusStartIndex();
2016-02-25 14:11:35 +01:00
// The last status is statusEndExclusiveIndex - 1
final int statusEndExclusiveIndex = statusStartIndex + adapter.getStatusCount();
2016-02-25 17:03:02 +01:00
if (statusEndExclusiveIndex >= 0 && rememberPosition && tag != null) {
final long lastPositionKey = adapter.getStatusPositionKey(statusEndExclusiveIndex - 1);
2016-02-25 14:11:35 +01:00
// Status corresponds to last read id was deleted, use last item id instead
if (lastPositionKey != -1 && lastReadPositionKey > 0 && lastReadPositionKey < lastPositionKey) {
lastReadPositionKey = lastPositionKey;
2016-02-25 14:11:35 +01:00
}
}
setRefreshEnabled(true);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
if (hasMoreData(data)) {
adapter.setLoadMoreSupportedPosition(IndicatorPosition.END);
onHasMoreDataChanged(true);
} else {
adapter.setLoadMoreSupportedPosition(IndicatorPosition.NONE);
onHasMoreDataChanged(false);
}
2015-03-12 10:43:28 +01:00
int pos = -1;
2016-02-25 14:11:35 +01:00
for (int i = statusStartIndex; i < statusEndExclusiveIndex; i++) {
// Assume statuses are descend sorted by id, so break at first status with id
// lesser equals than read position
if (lastReadPositionKey != -1 && adapter.getStatusPositionKey(i) <= lastReadPositionKey) {
2015-03-12 10:43:28 +01:00
pos = i;
break;
}
}
2015-04-16 14:48:24 +02:00
if (pos != -1 && adapter.isStatus(pos) && (readFromBottom || lastVisiblePos != 0)) {
2015-05-11 12:54:41 +02:00
if (layoutManager.getHeight() == 0) {
// RecyclerView has not currently laid out, ignore padding.
layoutManager.scrollToPositionWithOffset(pos, lastVisibleTop);
} else {
layoutManager.scrollToPositionWithOffset(pos, lastVisibleTop - layoutManager.getPaddingTop());
}
2015-03-12 10:43:28 +01:00
}
} else {
onHasMoreDataChanged(false);
2015-03-12 10:43:28 +01:00
}
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
2015-03-12 10:43:28 +01:00
}
2016-06-20 08:33:22 +02:00
onStatusesLoaded(loader, data);
}
2015-03-12 10:43:28 +01:00
@Override
2016-03-09 17:12:09 +01:00
public void onLoaderReset(Loader<List<ParcelableStatus>> loader) {
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
2015-03-12 10:43:28 +01:00
}
@Override
2015-01-10 16:17:02 +01:00
public void onGapClick(GapViewHolder holder, int position) {
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
2015-04-16 14:48:24 +02:00
final ParcelableStatus status = adapter.getStatus(position);
if (BuildConfig.DEBUG) {
Log.v(LOGTAG, "Load activity gap " + status);
}
if (status == null) return;
2016-03-07 18:25:18 +01:00
final UserKey[] accountIds = {status.account_key};
2016-03-10 05:23:04 +01:00
final String[] maxIds = {status.id};
2016-03-10 13:34:43 +01:00
final long[] maxSortIds = {status.sort_id};
getStatuses(new BaseRefreshTaskParam(accountIds, maxIds, null, maxSortIds, null));
}
2015-04-16 14:48:24 +02:00
@Override
public void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int statusPosition) {
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(statusPosition);
2016-04-19 14:32:12 +02:00
if (status == null || media == null) return;
2016-04-02 16:15:34 +02:00
IntentUtils.openMedia(getActivity(), status, media, null,
mPreferences.getBoolean(KEY_NEW_DOCUMENT_API));
2015-08-16 04:50:56 +02:00
// BEGIN HotMobi
2015-12-14 03:20:55 +01:00
final MediaEvent event = MediaEvent.create(getActivity(), status, media, getTimelineType(),
adapter.isMediaPreviewEnabled());
2016-03-07 06:05:08 +01:00
HotMobiLogger.getInstance(getActivity()).log(status.account_key, event);
2015-08-16 04:50:56 +02:00
// END HotMobi
2015-04-16 14:48:24 +02:00
}
@Override
2016-03-21 01:34:20 +01:00
public void onItemActionClick(RecyclerView.ViewHolder holder, int id, int position) {
2016-03-30 09:07:22 +02:00
final Context context = getContext();
if (context == null) return;
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
2015-04-16 14:48:24 +02:00
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
2016-03-30 09:07:22 +02:00
handleStatusActionClick(context, getFragmentManager(), mTwitterWrapper,
(StatusViewHolder) holder, status, id);
}
2016-06-14 03:33:53 +02:00
@Nullable
@Override
2016-06-21 08:43:11 +02:00
protected RecyclerView.ItemDecoration createItemDecoration(Context context, final RecyclerView recyclerView, final LinearLayoutManager layoutManager) {
final ParcelableStatusesAdapter adapter = getAdapter();
2016-06-14 03:33:53 +02:00
final DividerItemDecoration itemDecoration = new DividerItemDecoration(context,
((LinearLayoutManager) recyclerView.getLayoutManager()).getOrientation());
final Resources res = context.getResources();
2016-06-21 08:43:11 +02:00
if (adapter.isProfileImageEnabled()) {
2016-06-14 03:33:53 +02:00
final int decorPaddingLeft = res.getDimensionPixelSize(R.dimen.element_spacing_normal) * 2
+ res.getDimensionPixelSize(R.dimen.icon_size_status_profile_image);
2016-06-21 08:43:11 +02:00
itemDecoration.setPadding(new DividerItemDecoration.Padding() {
@Override
public boolean get(int position, Rect rect) {
final int itemViewType = adapter.getItemViewType(position);
boolean nextItemIsStatus = false;
if (position < adapter.getItemCount() - 1) {
nextItemIsStatus = adapter.getItemViewType(position + 1) == ParcelableStatusesAdapter.ITEM_VIEW_TYPE_STATUS;
}
if (nextItemIsStatus && itemViewType == ParcelableStatusesAdapter.ITEM_VIEW_TYPE_STATUS) {
rect.left = decorPaddingLeft;
} else {
rect.left = 0;
}
return true;
}
});
2016-06-14 03:33:53 +02:00
}
itemDecoration.setDecorationEndOffset(1);
return itemDecoration;
}
2016-03-30 09:07:22 +02:00
public static void handleStatusActionClick(Context context, FragmentManager fm,
AsyncTwitterWrapper twitter, StatusViewHolder holder,
ParcelableStatus status, int id) {
if (status == null) return;
switch (id) {
2016-03-03 12:53:02 +01:00
case R.id.reply: {
2016-03-30 09:07:22 +02:00
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_REPLY);
intent.setPackage(context.getPackageName());
intent.putExtra(IntentConstants.EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
2016-03-03 12:53:02 +01:00
case R.id.retweet: {
2016-03-30 09:07:22 +02:00
RetweetQuoteDialogFragment.show(fm, status);
break;
}
2016-03-03 12:53:02 +01:00
case R.id.favorite: {
if (twitter == null) return;
if (status.is_favorite) {
2016-03-07 06:05:08 +01:00
twitter.destroyFavoriteAsync(status.account_key, status.id);
} else {
2016-03-30 09:07:22 +02:00
holder.playLikeAnimation(new DefaultOnLikedListener(twitter,
2016-03-21 01:34:20 +01:00
status));
}
break;
}
}
}
2016-03-30 09:07:22 +02:00
protected void saveReadPosition() {
final LinearLayoutManager layoutManager = getLayoutManager();
if (layoutManager != null) {
saveReadPosition(layoutManager.findFirstVisibleItemPosition());
}
}
protected void onHasMoreDataChanged(boolean hasMoreData) {
}
@NonNull
@TimelineType
protected abstract String getTimelineType();
@Override
public void onStatusClick(IStatusViewHolder holder, int position) {
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
2016-03-07 03:43:09 +01:00
IntentUtils.openStatus(getActivity(), adapter.getStatus(position), null);
2015-04-16 14:48:24 +02:00
}
@Override
public boolean onStatusLongClick(IStatusViewHolder holder, int position) {
2015-04-16 14:48:24 +02:00
//TODO handle long click event
return true;
}
@Override
2016-03-21 01:34:20 +01:00
public void onItemMenuClick(RecyclerView.ViewHolder holder, View menuView, int position) {
2016-02-08 12:44:37 +01:00
if (getActivity() == null) return;
final LinearLayoutManager lm = getLayoutManager();
final View view = lm.findViewByPosition(position);
if (view == null) return;
getRecyclerView().showContextMenuForChild(view);
}
2015-04-16 22:29:36 +02:00
@Override
2016-03-21 01:34:20 +01:00
public void onUserProfileClick(IStatusViewHolder holder, int position) {
final ParcelableStatus status = getAdapter().getStatus(position);
final Intent intent = IntentUtils.userProfile(status.account_key, status.user_key,
status.user_screen_name, UserFragment.Referral.TIMELINE_STATUS,
status.extras.user_statusnet_profile_url);
IntentUtils.applyNewDocument(intent, mPreferences.getBoolean(KEY_NEW_DOCUMENT_API));
startActivity(intent);
2015-04-16 22:29:36 +02:00
}
2015-01-10 16:17:02 +01:00
@Override
2015-04-16 14:48:24 +02:00
public void onStart() {
super.onStart();
final RecyclerView recyclerView = getRecyclerView();
recyclerView.addOnScrollListener(mOnScrollListener);
recyclerView.addOnScrollListener(mPauseOnScrollListener);
final AbstractTask<Object, Boolean, RecyclerView> task = new AbstractTask<Object, Boolean, RecyclerView>() {
@Override
public Boolean doLongOperation(Object params) {
final Context context = getContext();
if (context == null) return false;
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE);
if (!prefs.getBoolean(KEY_USAGE_STATISTICS, false)) return false;
2016-03-06 13:59:24 +01:00
final File logFile = HotMobiLogger.getLogFile(context, null, "scroll");
return logFile.length() < 131072;
}
@Override
2016-03-24 14:50:13 +01:00
public void afterExecute(RecyclerView recyclerView, Boolean result) {
if (result) {
recyclerView.addOnScrollListener(mActiveHotMobiScrollTracker = mHotMobiScrollTracker);
}
}
};
task.setResultHandler(recyclerView);
TaskStarter.execute(task);
mBus.register(mStatusesBusCallback);
2015-01-10 16:17:02 +01:00
}
@Override
2015-04-16 14:48:24 +02:00
public void onStop() {
mBus.unregister(mStatusesBusCallback);
final RecyclerView recyclerView = getRecyclerView();
if (mActiveHotMobiScrollTracker != null) {
recyclerView.removeOnScrollListener(mActiveHotMobiScrollTracker);
}
mActiveHotMobiScrollTracker = null;
recyclerView.removeOnScrollListener(mPauseOnScrollListener);
recyclerView.removeOnScrollListener(mOnScrollListener);
2016-03-03 14:06:12 +01:00
if (getUserVisibleHint()) {
saveReadPosition();
}
2015-04-16 14:48:24 +02:00
super.onStop();
}
2016-01-27 16:08:00 +01:00
@Override
public void onDestroy() {
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
2016-03-21 01:34:20 +01:00
adapter.setStatusClickListener(null);
2016-01-27 16:08:00 +01:00
super.onDestroy();
}
2015-04-16 22:29:36 +02:00
@Override
public final boolean scrollToStart() {
final boolean result = super.scrollToStart();
if (result) {
2015-05-04 19:36:46 +02:00
saveReadPosition(0);
}
return result;
2015-04-16 22:29:36 +02:00
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mScrollListener.setReversed(mPreferences.getBoolean(KEY_READ_FROM_BOTTOM));
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
final RecyclerView recyclerView = getRecyclerView();
final LinearLayoutManager layoutManager = getLayoutManager();
2016-03-21 01:34:20 +01:00
adapter.setStatusClickListener(this);
registerForContextMenu(recyclerView);
2015-05-20 10:42:57 +02:00
mNavigationHelper = new RecyclerViewNavigationHelper(recyclerView, layoutManager,
adapter, this);
mPauseOnScrollListener = new PauseRecyclerViewOnScrollListener(adapter.getMediaLoader().getImageLoader(), false, true);
2015-04-16 22:29:36 +02:00
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
showProgress();
2015-04-16 22:29:36 +02:00
}
2015-01-10 16:17:02 +01:00
protected Object createMessageBusCallback() {
return new StatusesBusCallback();
}
@NonNull
2016-03-07 18:25:18 +01:00
protected abstract UserKey[] getAccountKeys();
2016-03-09 17:12:09 +01:00
protected List<ParcelableStatus> getAdapterData() {
final ParcelableStatusesAdapter adapter = getAdapter();
2015-04-16 14:48:24 +02:00
return adapter.getData();
}
2016-03-09 17:12:09 +01:00
protected void setAdapterData(List<ParcelableStatus> data) {
final ParcelableStatusesAdapter adapter = getAdapter();
2015-04-16 14:48:24 +02:00
adapter.setData(data);
}
@ReadPositionTag
@Nullable
protected String getReadPositionTag() {
return null;
}
2016-02-27 16:12:17 +01:00
@Nullable
protected String getReadPositionTagWithArguments() {
return getReadPositionTag();
}
2016-03-09 17:12:09 +01:00
protected abstract boolean hasMoreData(List<ParcelableStatus> data);
2016-03-09 17:12:09 +01:00
protected abstract Loader<List<ParcelableStatus>> onCreateStatusesLoader(final Context context, final Bundle args,
2016-03-10 13:34:43 +01:00
final boolean fromUser);
2015-04-16 22:29:36 +02:00
2016-06-20 08:33:22 +02:00
protected abstract void onStatusesLoaded(Loader<List<ParcelableStatus>> loader, List<ParcelableStatus> data);
2016-02-27 16:12:17 +01:00
protected final void saveReadPosition(int position) {
final String readPositionTag = getReadPositionTagWithAccounts();
if (readPositionTag == null) return;
if (position == RecyclerView.NO_POSITION) return;
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
2015-04-16 14:48:24 +02:00
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
final long positionKey = status.position_key > 0 ? status.position_key : status.timestamp;
mReadStateManager.setPosition(readPositionTag, positionKey);
final UserKey[] accountKeys = getAccountKeys();
if (accountKeys.length > 1) {
for (UserKey accountKey : accountKeys) {
final String tag = Utils.getReadPositionTagWithAccounts(getReadPositionTagWithArguments(),
accountKey);
mReadStateManager.setPosition(tag, positionKey);
}
2016-03-26 04:27:36 +01:00
}
mReadStateManager.setPosition(getCurrentReadPositionTag(), positionKey, true);
}
@NonNull
@Override
protected Rect getExtraContentPadding() {
final int paddingVertical = getResources().getDimensionPixelSize(R.dimen.element_spacing_small);
return new Rect(0, paddingVertical, 0, paddingVertical);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
2016-03-10 13:34:43 +01:00
if (!getUserVisibleHint() || menuInfo == null) return;
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
final MenuInflater inflater = new MenuInflater(getContext());
final ExtendedRecyclerView.ContextMenuInfo contextMenuInfo =
(ExtendedRecyclerView.ContextMenuInfo) menuInfo;
final ParcelableStatus status = adapter.getStatus(contextMenuInfo.getPosition());
inflater.inflate(R.menu.action_status, menu);
2016-03-22 05:46:05 +01:00
MenuUtils.setupForStatus(getContext(), mPreferences, menu, status,
mTwitterWrapper);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (!getUserVisibleHint()) return false;
final ExtendedRecyclerView.ContextMenuInfo contextMenuInfo =
(ExtendedRecyclerView.ContextMenuInfo) item.getMenuInfo();
final ParcelableStatus status = getAdapter().getStatus(contextMenuInfo.getPosition());
if (status == null) return false;
if (item.getItemId() == R.id.share) {
final Intent shareIntent = Utils.createStatusShareIntent(getActivity(), status);
final Intent chooser = Intent.createChooser(shareIntent, getString(R.string.share_status));
2016-03-11 16:39:37 +01:00
Utils.addCopyLinkIntent(getContext(), chooser, LinkCreator.getStatusWebLink(status));
startActivity(chooser);
return true;
}
2016-03-30 10:54:14 +02:00
return MenuUtils.handleStatusClick(getActivity(), this, getFragmentManager(),
mUserColorNameManager, mTwitterWrapper, status, item);
}
private String getCurrentReadPositionTag() {
final String tag = getReadPositionTagWithAccounts();
if (tag == null) return null;
return tag + "_current";
2015-03-12 10:43:28 +01:00
}
private String getReadPositionTagWithAccounts() {
2016-03-06 13:59:24 +01:00
return Utils.getReadPositionTagWithAccounts(getReadPositionTagWithArguments(), getAccountKeys());
}
2016-02-18 17:21:04 +01:00
public static final class DefaultOnLikedListener implements LikeAnimationDrawable.OnLikedListener {
private final ParcelableStatus mStatus;
private final AsyncTwitterWrapper mTwitter;
public DefaultOnLikedListener(final AsyncTwitterWrapper twitter, final ParcelableStatus status) {
mStatus = status;
mTwitter = twitter;
}
@Override
public boolean onLiked() {
2016-03-05 16:16:17 +01:00
final ParcelableStatus status = mStatus;
if (status.is_favorite) return false;
2016-03-07 06:05:08 +01:00
mTwitter.createFavoriteAsync(status.account_key, status.id);
2016-02-18 17:21:04 +01:00
return true;
}
}
protected final class StatusesBusCallback {
protected StatusesBusCallback() {
}
@Subscribe
public void notifyStatusListChanged(StatusListChangedEvent event) {
2016-03-09 17:12:09 +01:00
final ParcelableStatusesAdapter adapter = getAdapter();
2015-04-16 14:48:24 +02:00
adapter.notifyDataSetChanged();
}
}
}