improved activities divider

improved status conversation view
This commit is contained in:
Mariotaku Lee 2016-01-02 23:10:53 +08:00
parent 76547896ba
commit 4a4defaa5d
8 changed files with 160 additions and 263 deletions

View File

@ -25,6 +25,7 @@ import android.support.v4.app.FragmentActivity;
import android.support.v4.util.Pair; import android.support.v4.util.Pair;
import android.support.v4.widget.Space; import android.support.v4.widget.Space;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -54,6 +55,8 @@ import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapter; import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapter;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder; import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
import java.util.Random;
/** /**
* Created by mariotaku on 15/1/3. * Created by mariotaku on 15/1/3.
*/ */
@ -77,6 +80,7 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
private long[] mFilteredUserIds; private long[] mFilteredUserIds;
private boolean mFollowingOnly; private boolean mFollowingOnly;
private Random mRandom = new Random();
protected AbsActivitiesAdapter(final Context context, boolean compact) { protected AbsActivitiesAdapter(final Context context, boolean compact) {
super(context); super(context);
@ -224,8 +228,7 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
return new StubViewHolder(view); return new StubViewHolder(view);
} }
case ITEM_VIEW_TYPE_EMPTY: { case ITEM_VIEW_TYPE_EMPTY: {
final View view = new Space(getContext()); return new EmptyViewHolder(new Space(getContext()));
return new EmptyViewHolder(view);
} }
} }
throw new UnsupportedOperationException("Unsupported viewType " + viewType); throw new UnsupportedOperationException("Unsupported viewType " + viewType);

View File

@ -514,6 +514,7 @@ public abstract class AbsActivitiesFragment<Data> extends AbsContentListRecycler
} }
final RecyclerView recyclerView = getRecyclerView(); final RecyclerView recyclerView = getRecyclerView();
final AbsActivitiesAdapter<Data> adapter = getAdapter(); final AbsActivitiesAdapter<Data> adapter = getAdapter();
// Dividers are drawn on bottom of view
recyclerView.addItemDecoration(new DividerItemDecoration(context, getLayoutManager().getOrientation()) { recyclerView.addItemDecoration(new DividerItemDecoration(context, getLayoutManager().getOrientation()) {
@Override @Override
@ -521,7 +522,15 @@ public abstract class AbsActivitiesFragment<Data> extends AbsContentListRecycler
if (childPos == RecyclerView.NO_POSITION || childPos == adapter.getItemCount() - 1) { if (childPos == RecyclerView.NO_POSITION || childPos == adapter.getItemCount() - 1) {
return false; return false;
} }
if (shouldUseDividerFor(adapter.getItemViewType(childPos))) { final int itemViewType = adapter.getItemViewType(childPos);
if (itemViewType == AbsActivitiesAdapter.ITEM_VIEW_TYPE_EMPTY) {
//
if (childPos != 0 && shouldUseDividerFor(adapter.getItemViewType(childPos + 1))) {
return true;
}
return false;
}
if (shouldUseDividerFor(itemViewType)) {
if (shouldUseDividerFor(adapter.getItemViewType(childPos + 1))) { if (shouldUseDividerFor(adapter.getItemViewType(childPos + 1))) {
return true; return true;
} }

View File

@ -216,6 +216,7 @@ public abstract class CacheDownloadFragment extends BaseSupportFragment implemen
mData = data; mData = data;
hideProgress(); hideProgress();
displayDownloaded(data); displayDownloaded(data);
invalidateOptionsMenu();
} }
protected abstract void displayDownloaded(CacheDownloadLoader.Result data); protected abstract void displayDownloaded(CacheDownloadLoader.Result data);

View File

@ -95,9 +95,8 @@ import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.Status; import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.api.twitter.model.TranslationResult; import org.mariotaku.twidere.api.twitter.model.TranslationResult;
import org.mariotaku.twidere.constant.IntentConstants; import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.loader.support.ConversationLoader;
import org.mariotaku.twidere.loader.support.ParcelableStatusLoader; import org.mariotaku.twidere.loader.support.ParcelableStatusLoader;
import org.mariotaku.twidere.loader.support.StatusRepliesLoader;
import org.mariotaku.twidere.model.ListResponse;
import org.mariotaku.twidere.model.ParcelableActivity; import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableActivityCursorIndices; import org.mariotaku.twidere.model.ParcelableActivityCursorIndices;
import org.mariotaku.twidere.model.ParcelableActivityValuesCreator; import org.mariotaku.twidere.model.ParcelableActivityValuesCreator;
@ -164,7 +163,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
// Constants // Constants
private static final int LOADER_ID_DETAIL_STATUS = 1; private static final int LOADER_ID_DETAIL_STATUS = 1;
private static final int LOADER_ID_STATUS_REPLIES = 2; private static final int LOADER_ID_STATUS_CONVERSATIONS = 2;
private static final int LOADER_ID_STATUS_ACTIVITY = 3; private static final int LOADER_ID_STATUS_ACTIVITY = 3;
private static final int STATE_LOADED = 1; private static final int STATE_LOADED = 1;
private static final int STATE_LOADING = 2; private static final int STATE_LOADING = 2;
@ -182,21 +181,21 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
private StatusAdapter mStatusAdapter; private StatusAdapter mStatusAdapter;
private LinearLayoutManager mLayoutManager; private LinearLayoutManager mLayoutManager;
private LoadConversationTask mLoadConversationTask;
private LoadTranslationTask mLoadTranslationTask; private LoadTranslationTask mLoadTranslationTask;
private RecyclerViewNavigationHelper mNavigationHelper; private RecyclerViewNavigationHelper mNavigationHelper;
// Data fields // Data fields
private boolean mRepliesLoaderInitialized; private boolean mConversationLoaderInitialized;
private boolean mActivityLoaderInitialized; private boolean mActivityLoaderInitialized;
private ParcelableStatus mSelectedStatus; private ParcelableStatus mSelectedStatus;
private TweetEvent mStatusEvent; private TweetEvent mStatusEvent;
// Listeners // Listeners
private LoaderCallbacks<List<ParcelableStatus>> mRepliesLoaderCallback = new LoaderCallbacks<List<ParcelableStatus>>() { private LoaderCallbacks<List<ParcelableStatus>> mConversationsLoaderCallback = new LoaderCallbacks<List<ParcelableStatus>>() {
@Override @Override
public Loader<List<ParcelableStatus>> onCreateLoader(int id, Bundle args) { public Loader<List<ParcelableStatus>> onCreateLoader(int id, Bundle args) {
mStatusAdapter.setRepliesLoading(true); mStatusAdapter.setRepliesLoading(true);
mStatusAdapter.setConversationsLoading(true);
mStatusAdapter.updateItemDecoration(); mStatusAdapter.updateItemDecoration();
final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1); final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1);
final String screenName = args.getString(EXTRA_SCREEN_NAME); final String screenName = args.getString(EXTRA_SCREEN_NAME);
@ -204,9 +203,8 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
final long maxId = args.getLong(EXTRA_MAX_ID, -1); final long maxId = args.getLong(EXTRA_MAX_ID, -1);
final long sinceId = args.getLong(EXTRA_SINCE_ID, -1); final long sinceId = args.getLong(EXTRA_SINCE_ID, -1);
final boolean twitterOptimizedSearches = mPreferences.getBoolean(KEY_TWITTER_OPTIMIZED_SEARCHES); final boolean twitterOptimizedSearches = mPreferences.getBoolean(KEY_TWITTER_OPTIMIZED_SEARCHES);
final ConversationLoader loader = new ConversationLoader(getActivity(), accountId,
final StatusRepliesLoader loader = new StatusRepliesLoader(getActivity(), accountId, statusId, screenName, sinceId, maxId, null, true);
screenName, statusId, maxId, sinceId, null, null, 0, true, twitterOptimizedSearches);
loader.setComparator(ParcelableStatus.REVERSE_ID_COMPARATOR); loader.setComparator(ParcelableStatus.REVERSE_ID_COMPARATOR);
return loader; return loader;
} }
@ -214,7 +212,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
@Override @Override
public void onLoadFinished(Loader<List<ParcelableStatus>> loader, List<ParcelableStatus> data) { public void onLoadFinished(Loader<List<ParcelableStatus>> loader, List<ParcelableStatus> data) {
mStatusAdapter.updateItemDecoration(); mStatusAdapter.updateItemDecoration();
setReplies(data); setConversation(data);
final ParcelableCredentials account = mStatusAdapter.getStatusAccount(); final ParcelableCredentials account = mStatusAdapter.getStatusAccount();
if (Utils.hasOfficialAPIAccess(loader.getContext(), mPreferences, account)) { if (Utils.hasOfficialAPIAccess(loader.getContext(), mPreferences, account)) {
mStatusAdapter.setReplyError(null); mStatusAdapter.setReplyError(null);
@ -243,6 +241,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
} }
mStatusAdapter.setReplyError(error); mStatusAdapter.setReplyError(error);
} }
mStatusAdapter.setConversationsLoading(false);
mStatusAdapter.setRepliesLoading(false); mStatusAdapter.setRepliesLoading(false);
} }
@ -540,10 +539,8 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
final Bundle dataExtra = data.getExtras(); final Bundle dataExtra = data.getExtras();
final ParcelableCredentials credentials = dataExtra.getParcelable(EXTRA_ACCOUNT); final ParcelableCredentials credentials = dataExtra.getParcelable(EXTRA_ACCOUNT);
if (mStatusAdapter.setStatus(status, credentials)) { if (mStatusAdapter.setStatus(status, credentials)) {
mStatusAdapter.setConversation(null); mStatusAdapter.setData(null);
mStatusAdapter.setReplies(null);
loadConversation(status); loadConversation(status);
loadReplies(status);
loadActivity(status); loadActivity(status);
final int position = mStatusAdapter.getFirstPositionOfItem(StatusAdapter.ITEM_IDX_STATUS); final int position = mStatusAdapter.getFirstPositionOfItem(StatusAdapter.ITEM_IDX_STATUS);
@ -600,14 +597,10 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
private void setConversation(List<ParcelableStatus> data) { private void setConversation(List<ParcelableStatus> data) {
final Pair<Long, Integer> readPosition = saveReadPosition(); final Pair<Long, Integer> readPosition = saveReadPosition();
mStatusAdapter.setConversation(data); mStatusAdapter.setData(data);
restoreReadPosition(readPosition); restoreReadPosition(readPosition);
} }
private void addConversation(ParcelableStatus status, int position) {
mStatusAdapter.addConversation(status, position);
}
private StatusAdapter getAdapter() { private StatusAdapter getAdapter() {
return mStatusAdapter; return mStatusAdapter;
} }
@ -621,25 +614,17 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
} }
private void loadConversation(ParcelableStatus status) { private void loadConversation(ParcelableStatus status) {
if (AsyncTaskUtils.isTaskRunning(mLoadConversationTask)) {
mLoadConversationTask.cancel(true);
}
mLoadConversationTask = new LoadConversationTask(this);
AsyncTaskUtils.executeTask(mLoadConversationTask, status);
}
private void loadReplies(ParcelableStatus status) {
if (status == null) return; if (status == null) return;
final Bundle args = new Bundle(); final Bundle args = new Bundle();
args.putLong(EXTRA_ACCOUNT_ID, status.account_id); args.putLong(EXTRA_ACCOUNT_ID, status.account_id);
args.putLong(EXTRA_STATUS_ID, status.is_retweet ? status.retweet_id : status.id); args.putLong(EXTRA_STATUS_ID, status.is_retweet ? status.retweet_id : status.id);
args.putString(EXTRA_SCREEN_NAME, status.is_retweet ? status.retweeted_by_user_screen_name : status.user_screen_name); args.putString(EXTRA_SCREEN_NAME, status.is_retweet ? status.retweeted_by_user_screen_name : status.user_screen_name);
if (mRepliesLoaderInitialized) { if (mConversationLoaderInitialized) {
getLoaderManager().restartLoader(LOADER_ID_STATUS_REPLIES, args, mRepliesLoaderCallback); getLoaderManager().restartLoader(LOADER_ID_STATUS_CONVERSATIONS, args, mConversationsLoaderCallback);
return; return;
} }
getLoaderManager().initLoader(LOADER_ID_STATUS_REPLIES, args, mRepliesLoaderCallback); getLoaderManager().initLoader(LOADER_ID_STATUS_CONVERSATIONS, args, mConversationsLoaderCallback);
mRepliesLoaderInitialized = true; mConversationLoaderInitialized = true;
} }
@ -696,13 +681,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
mLayoutManager.scrollToPositionWithOffset(adapterPosition, position.second); mLayoutManager.scrollToPositionWithOffset(adapterPosition, position.second);
} }
private void setReplies(List<ParcelableStatus> data) {
final Pair<Long, Integer> readPosition = saveReadPosition();
mStatusAdapter.setReplies(data);
//TODO maintain read position
restoreReadPosition(readPosition);
}
private void setState(int state) { private void setState(int state) {
mStatusContent.setVisibility(state == STATE_LOADED ? View.VISIBLE : View.GONE); mStatusContent.setVisibility(state == STATE_LOADED ? View.VISIBLE : View.GONE);
mProgressContainer.setVisibility(state == STATE_LOADING ? View.VISIBLE : View.GONE); mProgressContainer.setVisibility(state == STATE_LOADING ? View.VISIBLE : View.GONE);
@ -749,6 +727,10 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
} }
} }
private void onUserClick(ParcelableUser user) {
Utils.openUserProfile(getContext(), user, null);
}
public static final class LoadSensitiveImageConfirmDialogFragment extends BaseSupportDialogFragment implements public static final class LoadSensitiveImageConfirmDialogFragment extends BaseSupportDialogFragment implements
DialogInterface.OnClickListener { DialogInterface.OnClickListener {
@ -827,90 +809,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
} }
} }
static class LoadConversationTask extends AsyncTask<ParcelableStatus, ParcelableStatus,
ListResponse<ParcelableStatus>> {
final Context context;
final StatusFragment fragment;
LoadConversationTask(final StatusFragment fragment) {
context = fragment.getActivity();
this.fragment = fragment;
}
@Override
protected ListResponse<ParcelableStatus> doInBackground(final ParcelableStatus... params) {
final ArrayList<ParcelableStatus> list = new ArrayList<>();
try {
ParcelableStatus status = params[0];
final long accountId = status.account_id;
if (Utils.isOfficialKeyAccount(context, accountId)) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(context, accountId, true);
while (status.in_reply_to_status_id > 0 && !isCancelled()) {
final ParcelableStatus cached = Utils.findStatusInDatabases(context, accountId, status.in_reply_to_status_id);
if (cached == null) break;
status = cached;
publishProgress(status);
list.add(0, status);
}
final Paging paging = new Paging();
final long id = status.is_retweet ? status.retweet_id : status.id;
paging.setMaxId(id);
final List<ParcelableStatus> conversations = new ArrayList<>();
for (org.mariotaku.twidere.api.twitter.model.Status item : twitter.showConversation(id, paging)) {
if (item.getId() < id) {
final ParcelableStatus conversation = new ParcelableStatus(item, accountId, false);
publishProgress(conversation);
conversations.add(conversation);
}
}
list.addAll(0, conversations);
} else {
while (status.in_reply_to_status_id > 0 && !isCancelled()) {
status = Utils.findStatus(context, accountId, status.in_reply_to_status_id);
publishProgress(status);
list.add(0, status);
}
}
} catch (final TwitterException e) {
return ListResponse.getListInstance(e);
}
return ListResponse.getListInstance(list);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
fragment.getAdapter().setConversationsLoading(true);
}
@Override
protected void onPostExecute(final ListResponse<ParcelableStatus> data) {
final StatusAdapter adapter = fragment.getAdapter();
if (data.hasData()) {
fragment.setConversation(data.getData());
} else if (data.hasException()) {
fragment.showConversationError(data.getException());
} else {
Utils.showErrorMessage(context, context.getString(R.string.action_getting_status), data.getException(), true);
}
adapter.setConversationsLoading(false);
}
@Override
protected void onProgressUpdate(ParcelableStatus... values) {
for (ParcelableStatus status : values) {
// fragment.addConversation(status, 0);
}
}
@Override
protected void onCancelled() {
}
}
private static class DetailStatusViewHolder extends ViewHolder implements OnClickListener, private static class DetailStatusViewHolder extends ViewHolder implements OnClickListener,
ActionMenuView.OnMenuItemClickListener { ActionMenuView.OnMenuItemClickListener {
@ -1374,6 +1272,10 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
return new ProfileImageViewHolder(this, mInflater.inflate(R.layout.adapter_item_status_interact_user, parent, false)); return new ProfileImageViewHolder(this, mInflater.inflate(R.layout.adapter_item_status_interact_user, parent, false));
} }
private void notifyItemClick(int position) {
mFragment.onUserClick(getItem(position));
}
static class ProfileImageViewHolder extends ViewHolder implements OnClickListener { static class ProfileImageViewHolder extends ViewHolder implements OnClickListener {
private final UserProfileImagesAdapter adapter; private final UserProfileImagesAdapter adapter;
@ -1396,10 +1298,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
adapter.notifyItemClick(getLayoutPosition()); adapter.notifyItemClick(getLayoutPosition());
} }
} }
private void notifyItemClick(int position) {
mFragment.onUserClick(getItem(position));
}
} }
private static class DetailStatusLinkClickHandler extends StatusLinkClickHandler { private static class DetailStatusLinkClickHandler extends StatusLinkClickHandler {
@ -1438,10 +1336,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
} }
} }
private void onUserClick(ParcelableUser user) {
Utils.openUserProfile(getContext(), user, null);
}
private static class SpaceViewHolder extends ViewHolder { private static class SpaceViewHolder extends ViewHolder {
public SpaceViewHolder(View itemView) { public SpaceViewHolder(View itemView) {
@ -1494,7 +1388,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
private TranslationResult mTranslationResult; private TranslationResult mTranslationResult;
private StatusActivity mStatusActivity; private StatusActivity mStatusActivity;
private ParcelableCredentials mStatusAccount; private ParcelableCredentials mStatusAccount;
private List<ParcelableStatus> mConversation, mReplies; private List<ParcelableStatus> mData;
private StatusAdapterListener mStatusAdapterListener; private StatusAdapterListener mStatusAdapterListener;
private RecyclerView mRecyclerView; private RecyclerView mRecyclerView;
private CharSequence mReplyError, mConversationError; private CharSequence mReplyError, mConversationError;
@ -1534,16 +1428,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
mTwidereLinkify = new TwidereLinkify(new StatusAdapterLinkClickHandler<>(this)); mTwidereLinkify = new TwidereLinkify(new StatusAdapterLinkClickHandler<>(this));
} }
public void addConversation(ParcelableStatus status, int position) {
if (mConversation == null) {
mConversation = new ArrayList<>();
}
mConversation.add(position, status);
mItemCounts[ITEM_IDX_CONVERSATION] = mConversation.size();
notifyDataSetChanged();
updateItemDecoration();
}
public int findPositionById(long itemId) { public int findPositionById(long itemId) {
for (int i = 0, j = getItemCount(); i < j; i++) { for (int i = 0, j = getItemCount(); i < j; i++) {
if (getItemId(i) == itemId) return i; if (getItemId(i) == itemId) return i;
@ -1582,18 +1466,12 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
@Override @Override
public ParcelableStatus getStatus(int position) { public ParcelableStatus getStatus(int position) {
final int itemStart = getItemTypeStart(position);
final int itemType = getItemType(position); final int itemType = getItemType(position);
return getStatusByItemType(position, itemStart, itemType);
}
private ParcelableStatus getStatusByItemType(int position, int itemStart, int itemType) {
switch (itemType) { switch (itemType) {
case ITEM_IDX_CONVERSATION: { case ITEM_IDX_CONVERSATION:
return mConversation != null ? mConversation.get(position - itemStart) : null;
}
case ITEM_IDX_REPLY: { case ITEM_IDX_REPLY: {
return mReplies != null ? mReplies.get(position - itemStart) : null; if (mData == null) return null;
return mData.get(position - getIndexStart(ITEM_IDX_CONVERSATION));
} }
case ITEM_IDX_STATUS: { case ITEM_IDX_STATUS: {
return mStatus; return mStatus;
@ -1602,6 +1480,11 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
return null; return null;
} }
public int getIndexStart(int index) {
if (index == 0) return 0;
return TwidereMathUtils.sum(mItemCounts, 0, index - 1);
}
@Override @Override
public long getStatusId(int position) { public long getStatusId(int position) {
final ParcelableStatus status = getStatus(position); final ParcelableStatus status = getStatus(position);
@ -1618,10 +1501,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
public ParcelableStatus findStatusById(long accountId, long statusId) { public ParcelableStatus findStatusById(long accountId, long statusId) {
if (mStatus != null && accountId == mStatus.account_id && statusId == mStatus.id) if (mStatus != null && accountId == mStatus.account_id && statusId == mStatus.id)
return mStatus; return mStatus;
for (ParcelableStatus status : Nullables.list(mConversation)) { for (ParcelableStatus status : Nullables.list(mData)) {
if (accountId == status.account_id && status.id == statusId) return status;
}
for (ParcelableStatus status : Nullables.list(mReplies)) {
if (accountId == status.account_id && status.id == statusId) return status; if (accountId == status.account_id && status.id == statusId) return status;
} }
return null; return null;
@ -1659,7 +1539,32 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
@Override @Override
public void setData(List<ParcelableStatus> data) { public void setData(List<ParcelableStatus> data) {
final ParcelableStatus status = mStatus;
if (status == null) return;
mData = data;
if (data == null) {
setCount(ITEM_IDX_CONVERSATION, 0);
setCount(ITEM_IDX_REPLY, 0);
} else {
int conversationCount = 0, replyCount = 0;
boolean containsStatus = false;
for (ParcelableStatus item : data) {
if (item.id < status.id) {
conversationCount++;
} else if (item.id > status.id) {
replyCount++;
} else {
containsStatus = true;
}
}
if (!containsStatus) {
throw new IllegalArgumentException("Conversation data must contains original status");
}
setCount(ITEM_IDX_CONVERSATION, conversationCount);
setCount(ITEM_IDX_REPLY, replyCount);
}
notifyDataSetChanged();
updateItemDecoration();
} }
@Override @Override
@ -1964,12 +1869,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
} }
} }
public void setConversation(List<ParcelableStatus> conversation) {
mConversation = conversation;
setCount(ITEM_IDX_CONVERSATION, conversation != null ? conversation.size() : 0);
updateItemDecoration();
}
private void setCount(int idx, int size) { private void setCount(int idx, int size) {
mItemCounts[idx] = size; mItemCounts[idx] = size;
notifyDataSetChanged(); notifyDataSetChanged();
@ -1991,12 +1890,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
updateItemDecoration(); updateItemDecoration();
} }
public void setReplies(List<ParcelableStatus> replies) {
mReplies = replies;
setCount(ITEM_IDX_REPLY, replies != null ? replies.size() : 0);
updateItemDecoration();
}
public boolean setStatus(final ParcelableStatus status, final ParcelableCredentials credentials) { public boolean setStatus(final ParcelableStatus status, final ParcelableCredentials credentials) {
final ParcelableStatus old = mStatus; final ParcelableStatus old = mStatus;
mStatus = status; mStatus = status;
@ -2010,7 +1903,8 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
if (mRecyclerView == null) return; if (mRecyclerView == null) return;
final DividerItemDecoration decoration = mFragment.getItemDecoration(); final DividerItemDecoration decoration = mFragment.getItemDecoration();
decoration.setDecorationStart(0); decoration.setDecorationStart(0);
if (mReplies == null) { // Is loading replies
if (mRepliesLoading) {
decoration.setDecorationEndOffset(2); decoration.setDecorationEndOffset(2);
} else { } else {
decoration.setDecorationEndOffset(1); decoration.setDecorationEndOffset(1);

View File

@ -24,7 +24,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import org.mariotaku.twidere.loader.support.StatusRepliesLoader; import org.mariotaku.twidere.loader.support.ConversationLoader;
import org.mariotaku.twidere.model.ParcelableStatus; import org.mariotaku.twidere.model.ParcelableStatus;
import java.util.List; import java.util.List;
@ -33,21 +33,21 @@ import edu.tsinghua.hotmobi.model.TimelineType;
public class StatusRepliesListFragment extends StatusesSearchFragment { public class StatusRepliesListFragment extends StatusesSearchFragment {
@Override // @Override
protected Loader<List<ParcelableStatus>> onCreateStatusesLoader(final Context context, // protected Loader<List<ParcelableStatus>> onCreateStatusesLoader(final Context context,
final Bundle args, // final Bundle args,
final boolean fromUser) { // final boolean fromUser) {
final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1); // final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1);
final String screenName = args.getString(EXTRA_SCREEN_NAME); // final String screenName = args.getString(EXTRA_SCREEN_NAME);
final long statusId = args.getLong(EXTRA_STATUS_ID, -1); // final long statusId = args.getLong(EXTRA_STATUS_ID, -1);
final long maxId = args.getLong(EXTRA_MAX_ID, -1); // final long maxId = args.getLong(EXTRA_MAX_ID, -1);
final long sinceId = args.getLong(EXTRA_SINCE_ID, -1); // final long sinceId = args.getLong(EXTRA_SINCE_ID, -1);
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1); // final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
final boolean twitterOptimizedSearches = mPreferences.getBoolean(KEY_TWITTER_OPTIMIZED_SEARCHES); // final boolean twitterOptimizedSearches = mPreferences.getBoolean(KEY_TWITTER_OPTIMIZED_SEARCHES);
return new StatusRepliesLoader(getActivity(), accountId, screenName, statusId, maxId, // return new ConversationLoader(getActivity(), accountId, statusId, screenName, sinceId, maxId,
sinceId, getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser, // getAdapterData(), tabPosition, fromUser
twitterOptimizedSearches); // );
} // }
@Override @Override
protected String[] getSavedStatusesFileArgs() { protected String[] getSavedStatusesFileArgs() {

View File

@ -0,0 +1,57 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader.support;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.model.ParcelableStatus;
import java.util.ArrayList;
import java.util.List;
public class ConversationLoader extends TwitterAPIStatusesLoader {
private final long mInReplyToStatusId;
public ConversationLoader(final Context context, final long accountId, final long statusId,
final String screenName, final long sinceId, final long maxId,
final List<ParcelableStatus> data, final boolean fromUser) {
super(context, accountId, sinceId, maxId, data, null, -1, fromUser);
mInReplyToStatusId = statusId;
}
@NonNull
@Override
public List<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
return twitter.showConversation(mInReplyToStatusId, paging);
}
@Override
protected boolean shouldFilterStatus(SQLiteDatabase database, ParcelableStatus status) {
return false;
}
}

View File

@ -1,74 +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.loader.support;
import android.content.Context;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.model.ParcelableStatus;
import java.util.ArrayList;
import java.util.List;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import static org.mariotaku.twidere.util.Utils.isOfficialTwitterInstance;
import static org.mariotaku.twidere.util.Utils.shouldForceUsingPrivateAPIs;
public class StatusRepliesLoader extends UserMentionsLoader {
private final long mInReplyToStatusId;
public StatusRepliesLoader(final Context context, final long accountId, final String screenName,
final long statusId, final long maxId, final long sinceId, final List<ParcelableStatus> data,
final String[] savedStatusesArgs, final int tabPosition, boolean fromUser,
boolean twitterOptimizedSearches) {
super(context, accountId, screenName, maxId, sinceId, data, savedStatusesArgs, tabPosition,
fromUser, false, twitterOptimizedSearches);
mInReplyToStatusId = statusId;
}
@NonNull
@Override
public List<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
final Context context = getContext();
final List<Status> result = new ArrayList<>();
if (shouldForceUsingPrivateAPIs(context) || isOfficialTwitterInstance(context, twitter)) {
final List<Status> statuses = twitter.showConversation(mInReplyToStatusId, paging);
for (final Status status : statuses) {
if (status.getId() > mInReplyToStatusId) {
result.add(status);
}
}
} else {
final List<Status> statuses = super.getStatuses(twitter, paging);
for (final Status status : statuses) {
if (status.getInReplyToStatusId() == mInReplyToStatusId) {
result.add(status);
}
}
}
return result;
}
}

View File

@ -19,6 +19,8 @@
package org.mariotaku.twidere.util; package org.mariotaku.twidere.util;
import android.support.annotation.NonNull;
public class TwidereMathUtils { public class TwidereMathUtils {
public static float clamp(final float num, final float bound1, final float bound2) { public static float clamp(final float num, final float bound1, final float bound2) {
final float max = Math.max(bound1, bound2), min = Math.min(bound1, bound2); final float max = Math.max(bound1, bound2), min = Math.min(bound1, bound2);
@ -61,10 +63,15 @@ public class TwidereMathUtils {
return sum; return sum;
} }
public static int sum(int[] ints) { public static int sum(@NonNull int[] array) {
return sum(array, 0, array.length - 1);
}
public static int sum(@NonNull int[] array, int start, int end) {
int sum = 0; int sum = 0;
for (int i : ints) { for (int i = start; i <= end; i++) {
sum += i; int num = array[i];
sum += num;
} }
return sum; return sum;
} }