improved activities divider
improved status conversation view
This commit is contained in:
parent
76547896ba
commit
4a4defaa5d
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue