1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-01-30 16:35:00 +01:00

improved search ui

fixed notification light/vibrate/ringtone option
improved refresh indicator in statuses timeline
fixed crashes when open drafts
fixed annoying loading indicator always visible on screen
This commit is contained in:
Mariotaku Lee 2015-04-01 21:42:07 +08:00
parent 9f2abf6cd9
commit dd729d2d5c
18 changed files with 295 additions and 103 deletions

View File

@ -33,7 +33,7 @@ import static org.mariotaku.twidere.annotation.Preference.Type.STRING;
public interface Constants extends TwidereConstants { public interface Constants extends TwidereConstants {
String DATABASES_NAME = "twidere.sqlite"; String DATABASES_NAME = "twidere.sqlite";
int DATABASES_VERSION = 89; int DATABASES_VERSION = 90;
int MENU_GROUP_STATUS_EXTENSION = 10; int MENU_GROUP_STATUS_EXTENSION = 10;
int MENU_GROUP_COMPOSE_EXTENSION = 11; int MENU_GROUP_COMPOSE_EXTENSION = 11;

View File

@ -75,7 +75,8 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
private final boolean mDisplayMediaPreview; private final boolean mDisplayMediaPreview;
private final boolean mNameFirst; private final boolean mNameFirst;
private final boolean mDisplayProfileImage; private final boolean mDisplayProfileImage;
private boolean mLoadMoreIndicatorEnabled; private boolean mLoadMoreSupported;
private boolean mLoadMoreIndicatorVisible;
private ActivityAdapterListener mActivityAdapterListener; private ActivityAdapterListener mActivityAdapterListener;
protected AbsActivitiesAdapter(final Context context, boolean compact) { protected AbsActivitiesAdapter(final Context context, boolean compact) {
@ -140,10 +141,6 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
return mTextSize; return mTextSize;
} }
public boolean hasLoadMoreIndicator() {
return mLoadMoreIndicatorEnabled;
}
public boolean isNameFirst() { public boolean isNameFirst() {
return mNameFirst; return mNameFirst;
} }
@ -248,7 +245,7 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
} }
public final int getItemCount() { public final int getItemCount() {
return getActivityCount() + (mLoadMoreIndicatorEnabled ? 1 : 0); return getActivityCount() + (mLoadMoreIndicatorVisible ? 1 : 0);
} }
@Override @Override
@ -313,12 +310,33 @@ public abstract class AbsActivitiesAdapter<Data> extends Adapter<ViewHolder> imp
mActivityAdapterListener = listener; mActivityAdapterListener = listener;
} }
public void setLoadMoreIndicatorEnabled(boolean enabled) { @Override
if (mLoadMoreIndicatorEnabled == enabled) return; public boolean isLoadMoreIndicatorVisible() {
mLoadMoreIndicatorEnabled = enabled; return mLoadMoreIndicatorVisible;
}
@Override
public boolean isLoadMoreSupported() {
return mLoadMoreSupported;
}
@Override
public void setLoadMoreSupported(boolean supported) {
mLoadMoreSupported = supported;
if (!supported) {
mLoadMoreIndicatorVisible = false;
}
notifyDataSetChanged(); notifyDataSetChanged();
} }
@Override
public void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged();
}
protected abstract void bindTitleSummaryViewHolder(ActivityTitleSummaryViewHolder holder, int position); protected abstract void bindTitleSummaryViewHolder(ActivityTitleSummaryViewHolder holder, int position);
protected abstract int getActivityAction(int position); protected abstract int getActivityAction(int position);

View File

@ -33,11 +33,11 @@ import org.mariotaku.twidere.view.holder.StatusViewHolder;
*/ */
public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implements Constants, public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implements Constants,
IStatusesAdapter<D> { IStatusesAdapter<D> {
public static final int ITEM_VIEW_TYPE_STATUS = 0; public static final int ITEM_VIEW_TYPE_STATUS = 0;
public static final int ITEM_VIEW_TYPE_GAP = 1; public static final int ITEM_VIEW_TYPE_GAP = 1;
public static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 2; public static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 2;
private final Context mContext; private final Context mContext;
private final LayoutInflater mInflater; private final LayoutInflater mInflater;
private final MediaLoaderWrapper mImageLoader; private final MediaLoaderWrapper mImageLoader;
@ -46,11 +46,15 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
private final int mCardBackgroundColor; private final int mCardBackgroundColor;
private final int mTextSize; private final int mTextSize;
private final int mProfileImageStyle, mMediaPreviewStyle; private final int mProfileImageStyle, mMediaPreviewStyle;
private final boolean mCompactCards; private final boolean mCompactCards;
private final boolean mNameFirst; private final boolean mNameFirst;
private final boolean mDisplayMediaPreview; private final boolean mDisplayMediaPreview;
private final boolean mDisplayProfileImage; private final boolean mDisplayProfileImage;
private boolean mLoadMoreIndicatorEnabled;
private boolean mLoadMoreSupported;
private boolean mLoadMoreIndicatorVisible;
private StatusAdapterListener mStatusAdapterListener; private StatusAdapterListener mStatusAdapterListener;
private boolean mShowInReplyTo; private boolean mShowInReplyTo;
private boolean mShowAccountsColor; private boolean mShowAccountsColor;
@ -120,14 +124,28 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
} }
@Override @Override
public boolean hasLoadMoreIndicator() { public boolean isLoadMoreIndicatorVisible() {
return mLoadMoreIndicatorEnabled; return mLoadMoreIndicatorVisible;
} }
@Override @Override
public void setLoadMoreIndicatorEnabled(boolean enabled) { public boolean isLoadMoreSupported() {
if (mLoadMoreIndicatorEnabled == enabled) return; return mLoadMoreSupported;
mLoadMoreIndicatorEnabled = enabled; }
@Override
public void setLoadMoreSupported(boolean supported) {
mLoadMoreSupported = supported;
if (!supported) {
mLoadMoreIndicatorVisible = false;
}
notifyDataSetChanged();
}
@Override
public void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged(); notifyDataSetChanged();
} }
@ -136,14 +154,44 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
return mDisplayMediaPreview; return mDisplayMediaPreview;
} }
@Override
public boolean isNameFirst() {
return mNameFirst;
}
@Override @Override
public boolean isProfileImageEnabled() { public boolean isProfileImageEnabled() {
return mDisplayProfileImage; return mDisplayProfileImage;
} }
@Override @Override
public boolean isNameFirst() { public final void onStatusClick(StatusViewHolder holder, int position) {
return mNameFirst; if (mStatusAdapterListener != null) {
mStatusAdapterListener.onStatusClick(holder, position);
}
}
@Override
public void onMediaClick(StatusViewHolder holder, ParcelableMedia media, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onMediaClick(holder, media, position);
}
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
final Context context = getContext();
final ParcelableStatus status = getStatus(position);
final View profileImageView = holder.getProfileImageView();
final View profileTypeView = holder.getProfileTypeView();
if (context instanceof FragmentActivity) {
final Bundle options = Utils.makeSceneTransitionOption((FragmentActivity) context,
new Pair<>(profileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE),
new Pair<>(profileTypeView, UserFragment.TRANSITION_NAME_PROFILE_TYPE));
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, options);
} else {
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, null);
}
} }
public boolean isShowInReplyTo() { public boolean isShowInReplyTo() {
@ -213,7 +261,7 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
@Override @Override
public final int getItemCount() { public final int getItemCount() {
return getStatusesCount() + (mLoadMoreIndicatorEnabled ? 1 : 0); return getStatusesCount() + (mLoadMoreIndicatorVisible ? 1 : 0);
} }
@Override @Override
@ -237,37 +285,6 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
} }
} }
@Override
public final void onStatusClick(StatusViewHolder holder, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onStatusClick(holder, position);
}
}
@Override
public void onMediaClick(StatusViewHolder holder, ParcelableMedia media, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onMediaClick(holder, media, position);
}
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
final Context context = getContext();
final ParcelableStatus status = getStatus(position);
final View profileImageView = holder.getProfileImageView();
final View profileTypeView = holder.getProfileTypeView();
if (context instanceof FragmentActivity) {
final Bundle options = Utils.makeSceneTransitionOption((FragmentActivity) context,
new Pair<>(profileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE),
new Pair<>(profileTypeView, UserFragment.TRANSITION_NAME_PROFILE_TYPE));
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, options);
} else {
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name, null);
}
}
public void setListener(StatusAdapterListener listener) { public void setListener(StatusAdapterListener listener) {
mStatusAdapterListener = listener; mStatusAdapterListener = listener;
} }

View File

@ -67,7 +67,7 @@ public class CursorStatusesAdapter extends AbsStatusesAdapter<Cursor> {
@Override @Override
public ParcelableStatus getStatus(int position) { public ParcelableStatus getStatus(int position) {
if (hasLoadMoreIndicator() && position == getStatusesCount() - 1) return null; if (isLoadMoreIndicatorVisible() && position == getStatusesCount() - 1) return null;
final Cursor c = mCursor; final Cursor c = mCursor;
if (c != null && c.moveToPosition(position)) { if (c != null && c.moveToPosition(position)) {
return new ParcelableStatus(c, mIndices); return new ParcelableStatus(c, mIndices);

View File

@ -63,7 +63,8 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
private final int mMediaPreviewStyle; private final int mMediaPreviewStyle;
private final ReadStateManager mReadStateManager; private final ReadStateManager mReadStateManager;
private final OnSharedPreferenceChangeListener mReadStateChangeListener; private final OnSharedPreferenceChangeListener mReadStateChangeListener;
private boolean mLoadMoreIndicatorEnabled; private boolean mLoadMoreSupported;
private boolean mLoadMoreIndicatorVisible;
private Cursor mCursor; private Cursor mCursor;
private MessageEntriesAdapterListener mListener; private MessageEntriesAdapterListener mListener;
private StringLongPair[] mPositionPairs; private StringLongPair[] mPositionPairs;
@ -133,10 +134,6 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
return mTextSize; return mTextSize;
} }
@Override
public boolean hasLoadMoreIndicator() {
return mLoadMoreIndicatorEnabled;
}
@Override @Override
public void onReadStateChanged() { public void onReadStateChanged() {
@ -144,12 +141,32 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
} }
@Override @Override
public void setLoadMoreIndicatorEnabled(boolean enabled) { public boolean isLoadMoreIndicatorVisible() {
if (mLoadMoreIndicatorEnabled == enabled) return; return mLoadMoreIndicatorVisible;
mLoadMoreIndicatorEnabled = enabled; }
@Override
public boolean isLoadMoreSupported() {
return mLoadMoreSupported;
}
@Override
public void setLoadMoreSupported(boolean supported) {
mLoadMoreSupported = supported;
if (!supported) {
mLoadMoreIndicatorVisible = false;
}
notifyDataSetChanged(); notifyDataSetChanged();
} }
@Override
public void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged();
}
@Override @Override
public boolean isGapItem(int position) { public boolean isGapItem(int position) {
return false; return false;
@ -228,7 +245,7 @@ public class MessageEntriesAdapter extends Adapter<ViewHolder> implements Consta
@Override @Override
public final int getItemCount() { public final int getItemCount() {
return getMessagesCount() + (mLoadMoreIndicatorEnabled ? 1 : 0); return getMessagesCount() + (mLoadMoreIndicatorVisible ? 1 : 0);
} }
@Override @Override

View File

@ -47,7 +47,11 @@ public interface IContentCardAdapter extends IGapSupportedAdapter, ContentCardCl
float getTextSize(); float getTextSize();
boolean hasLoadMoreIndicator(); boolean isLoadMoreIndicatorVisible();
void setLoadMoreIndicatorEnabled(boolean enabled); boolean isLoadMoreSupported();
void setLoadMoreSupported(boolean supported);
void setLoadMoreIndicatorVisible(boolean enabled);
} }

View File

@ -86,7 +86,7 @@ public abstract class AbsActivitiesFragment<Data> extends BaseSupportFragment im
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (isRefreshing()) return; if (isRefreshing()) return;
if (mAdapter.hasLoadMoreIndicator() && mScrollState != RecyclerView.SCROLL_STATE_IDLE if (mAdapter.isLoadMoreIndicatorVisible() && mScrollState != RecyclerView.SCROLL_STATE_IDLE
&& layoutManager.findLastVisibleItemPosition() == mAdapter.getItemCount() - 1) { && layoutManager.findLastVisibleItemPosition() == mAdapter.getItemCount() - 1) {
onLoadMoreStatuses(); onLoadMoreStatuses();
} }
@ -171,7 +171,7 @@ public abstract class AbsActivitiesFragment<Data> extends BaseSupportFragment im
mSwipeRefreshLayout.setOnRefreshListener(this); mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeColors(ThemeUtils.getUserAccentColor(context)); mSwipeRefreshLayout.setColorSchemeColors(ThemeUtils.getUserAccentColor(context));
mAdapter = onCreateAdapter(context, compact); mAdapter = onCreateAdapter(context, compact);
mAdapter.setLoadMoreIndicatorEnabled(true); mAdapter.setLoadMoreIndicatorVisible(true);
mAdapter.setListener(this); mAdapter.setListener(this);
final LinearLayoutManager layoutManager = new FixedLinearLayoutManager(context); final LinearLayoutManager layoutManager = new FixedLinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL); layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

View File

@ -150,7 +150,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
public void setRefreshing(boolean refreshing) { public void setRefreshing(boolean refreshing) {
if (refreshing == mSwipeRefreshLayout.isRefreshing()) return; if (refreshing == mSwipeRefreshLayout.isRefreshing()) return;
// if (!refreshing) updateRefreshProgressOffset(); // if (!refreshing) updateRefreshProgressOffset();
mSwipeRefreshLayout.setRefreshing(refreshing); mSwipeRefreshLayout.setRefreshing(refreshing && !mAdapter.isLoadMoreIndicatorVisible());
} }
@Override @Override
@ -209,6 +209,16 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
setListShown(false); setListShown(false);
} }
@Override
public void onLoadMoreContents() {
setLoadMoreIndicatorVisible(true);
setRefreshEnabled(false);
}
public void setLoadMoreIndicatorVisible(boolean visible) {
mAdapter.setLoadMoreIndicatorVisible(visible);
}
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
@ -272,7 +282,6 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
@Override @Override
public final void onLoadFinished(Loader<Data> loader, Data data) { public final void onLoadFinished(Loader<Data> loader, Data data) {
setRefreshing(false);
final SharedPreferences preferences = getSharedPreferences(); final SharedPreferences preferences = getSharedPreferences();
final boolean rememberPosition = preferences.getBoolean(KEY_REMEMBER_POSITION, false); final boolean rememberPosition = preferences.getBoolean(KEY_REMEMBER_POSITION, false);
final boolean readFromBottom = preferences.getBoolean(KEY_READ_FROM_BOTTOM, false); final boolean readFromBottom = preferences.getBoolean(KEY_READ_FROM_BOTTOM, false);
@ -300,7 +309,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
} }
mAdapter.setData(data); mAdapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) { if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
mAdapter.setLoadMoreIndicatorEnabled(hasMoreData(data)); mAdapter.setLoadMoreSupported(hasMoreData(data));
int pos = -1; int pos = -1;
for (int i = 0, j = mAdapter.getItemCount(); i < j; i++) { for (int i = 0, j = mAdapter.getItemCount(); i < j; i++) {
if (lastReadId != -1 && lastReadId == mAdapter.getStatusId(i)) { if (lastReadId != -1 && lastReadId == mAdapter.getStatusId(i)) {
@ -316,6 +325,13 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
((IExtendedLoader) loader).setFromUser(false); ((IExtendedLoader) loader).setFromUser(false);
} }
setListShown(true); setListShown(true);
onLoadingFinished();
}
protected abstract void onLoadingFinished();
public void setRefreshEnabled(boolean enabled) {
mSwipeRefreshLayout.setEnabled(enabled);
} }
@Override @Override

View File

@ -59,6 +59,11 @@ import static org.mariotaku.twidere.util.Utils.shouldEnableFiltersForRTs;
*/ */
public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor> { public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor> {
@Override
protected void onLoadingFinished() {
}
private ContentObserver mContentObserver; private ContentObserver mContentObserver;
public abstract Uri getContentUri(); public abstract Uri getContentUri();
@ -95,6 +100,10 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor>
public void notifyGetStatusesTaskChanged(GetStatusesTaskEvent event) { public void notifyGetStatusesTaskChanged(GetStatusesTaskEvent event) {
if (!event.uri.equals(getContentUri())) return; if (!event.uri.equals(getContentUri())) return;
setRefreshing(event.running); setRefreshing(event.running);
if (!event.running) {
setLoadMoreIndicatorVisible(false);
setRefreshEnabled(true);
}
} }
@Subscribe @Subscribe
@ -175,6 +184,7 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor>
@Override @Override
public void onLoadMoreContents() { public void onLoadMoreContents() {
super.onLoadMoreContents();
AsyncTaskUtils.executeTask(new AsyncTask<Void, Void, long[][]>() { AsyncTaskUtils.executeTask(new AsyncTask<Void, Void, long[][]>() {
@Override @Override

View File

@ -64,6 +64,7 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface; import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages; import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Inbox;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses; import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import org.mariotaku.twidere.util.AsyncTaskUtils; import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.AsyncTwitterWrapper;
@ -73,6 +74,7 @@ import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver; import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver;
import org.mariotaku.twidere.util.message.GetMessagesTaskEvent;
import org.mariotaku.twidere.util.message.TaskStateChangedEvent; import org.mariotaku.twidere.util.message.TaskStateChangedEvent;
import java.util.Collections; import java.util.Collections;
@ -152,13 +154,6 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
super.onDetach(); super.onDetach();
} }
@Subscribe
public void notifyTaskStateChanged(TaskStateChangedEvent event) {
updateRefreshState();
}
@Override @Override
public void onEntryClick(int position, DirectMessageEntry entry) { public void onEntryClick(int position, DirectMessageEntry entry) {
Utils.openMessageConversation(getActivity(), entry.account_id, entry.conversation_id); Utils.openMessageConversation(getActivity(), entry.account_id, entry.conversation_id);
@ -219,7 +214,9 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
if (getActivity() == null) return; if (getActivity() == null) return;
mFirstVisibleItem = -1; mFirstVisibleItem = -1;
mAdapter.setCursor(cursor); mAdapter.setCursor(cursor);
mAdapter.setLoadMoreIndicatorEnabled(cursor != null && cursor.getCount() > 0); mAdapter.setLoadMoreIndicatorVisible(false);
mAdapter.setLoadMoreSupported(cursor != null && cursor.getCount() > 0);
mSwipeRefreshLayout.setEnabled(true);
// mAdapter.setShowAccountColor(getActivatedAccountIds(getActivity()).length > 1); // mAdapter.setShowAccountColor(getActivatedAccountIds(getActivity()).length > 1);
setListShown(true); setListShown(true);
} }
@ -274,9 +271,19 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus(); final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
bus.register(this); bus.register(this);
mAdapter.updateReadState(); mAdapter.updateReadState();
updateRefreshState();
} }
@Subscribe
public void onGetMessagesTaskChanged(GetMessagesTaskEvent event) {
if (event.uri.equals(Inbox.CONTENT_URI) && !event.running) {
setRefreshing(false);
mAdapter.setLoadMoreIndicatorVisible(false);
mSwipeRefreshLayout.setEnabled(true);
}
}
@Override @Override
public void onStop() { public void onStop() {
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus(); final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
@ -330,12 +337,13 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
} }
public void setRefreshing(boolean refreshing) { public void setRefreshing(boolean refreshing) {
if (refreshing == mSwipeRefreshLayout.isRefreshing()) return; if (mAdapter == null || refreshing == mSwipeRefreshLayout.isRefreshing()) return;
mSwipeRefreshLayout.setRefreshing(refreshing); mSwipeRefreshLayout.setRefreshing(refreshing && !mAdapter.isLoadMoreIndicatorVisible());
} }
public boolean isRefreshing() { public boolean isRefreshing() {
return mSwipeRefreshLayout.isRefreshing(); if (mSwipeRefreshLayout == null || mAdapter == null) return false;
return mSwipeRefreshLayout.isRefreshing() || mAdapter.isLoadMoreIndicatorVisible();
} }
private void addReadPosition(final int firstVisibleItem) { private void addReadPosition(final int firstVisibleItem) {
@ -359,6 +367,8 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
// //
private void loadMoreMessages() { private void loadMoreMessages() {
if (isRefreshing()) return; if (isRefreshing()) return;
mAdapter.setLoadMoreIndicatorVisible(true);
mSwipeRefreshLayout.setEnabled(false);
AsyncTaskUtils.executeTask(new AsyncTask<Void, Void, long[][]>() { AsyncTaskUtils.executeTask(new AsyncTask<Void, Void, long[][]>() {
@Override @Override

View File

@ -112,8 +112,17 @@ public abstract class ParcelableStatusesFragment extends AbsStatusesFragment<Lis
return new ParcelableStatusesAdapter(context, compact); return new ParcelableStatusesAdapter(context, compact);
} }
@Override
protected void onLoadingFinished() {
setRefreshEnabled(true);
setRefreshing(false);
setLoadMoreIndicatorVisible(false);
}
@Override @Override
public void onLoadMoreContents() { public void onLoadMoreContents() {
super.onLoadMoreContents();
final IStatusesAdapter<List<ParcelableStatus>> adapter = getAdapter(); final IStatusesAdapter<List<ParcelableStatus>> adapter = getAdapter();
final long[] maxIds = new long[]{adapter.getStatus(adapter.getStatusesCount() - 1).id}; final long[] maxIds = new long[]{adapter.getStatus(adapter.getStatusesCount() - 1).id};
getStatuses(null, maxIds, null); getStatuses(null, maxIds, null);

View File

@ -483,6 +483,9 @@ public class StatusFragment extends BaseSupportFragment
private final boolean mDisplayMediaPreview; private final boolean mDisplayMediaPreview;
private final boolean mDisplayProfileImage; private final boolean mDisplayProfileImage;
private boolean mLoadMoreSupported;
private boolean mLoadMoreIndicatorVisible;
private ParcelableStatus mStatus; private ParcelableStatus mStatus;
private ParcelableCredentials mStatusAccount; private ParcelableCredentials mStatusAccount;
private List<ParcelableStatus> mConversation, mReplies; private List<ParcelableStatus> mConversation, mReplies;
@ -641,14 +644,31 @@ public class StatusFragment extends BaseSupportFragment
return mTextSize; return mTextSize;
} }
@Override @Override
public boolean hasLoadMoreIndicator() { public boolean isLoadMoreIndicatorVisible() {
return false; return mLoadMoreIndicatorVisible;
} }
@Override @Override
public void setLoadMoreIndicatorEnabled(boolean enabled) { public boolean isLoadMoreSupported() {
return mLoadMoreSupported;
}
@Override
public void setLoadMoreSupported(boolean supported) {
mLoadMoreSupported = supported;
if (!supported) {
mLoadMoreIndicatorVisible = false;
}
notifyDataSetChanged();
}
@Override
public void setLoadMoreIndicatorVisible(boolean enabled) {
if (mLoadMoreIndicatorVisible == enabled) return;
mLoadMoreIndicatorVisible = enabled && mLoadMoreSupported;
notifyDataSetChanged();
} }
public ParcelableStatus getStatus() { public ParcelableStatus getStatus() {

View File

@ -70,6 +70,7 @@ import org.mariotaku.twidere.util.content.ContentResolverUtils;
import org.mariotaku.twidere.util.message.FavoriteCreatedEvent; import org.mariotaku.twidere.util.message.FavoriteCreatedEvent;
import org.mariotaku.twidere.util.message.FavoriteDestroyedEvent; import org.mariotaku.twidere.util.message.FavoriteDestroyedEvent;
import org.mariotaku.twidere.util.message.FriendshipUpdatedEvent; import org.mariotaku.twidere.util.message.FriendshipUpdatedEvent;
import org.mariotaku.twidere.util.message.GetMessagesTaskEvent;
import org.mariotaku.twidere.util.message.GetStatusesTaskEvent; import org.mariotaku.twidere.util.message.GetStatusesTaskEvent;
import org.mariotaku.twidere.util.message.ProfileUpdatedEvent; import org.mariotaku.twidere.util.message.ProfileUpdatedEvent;
import org.mariotaku.twidere.util.message.StatusDestroyedEvent; import org.mariotaku.twidere.util.message.StatusDestroyedEvent;
@ -1817,10 +1818,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
} }
// Delete all rows conflicting before new data inserted. // Delete all rows conflicting before new data inserted.
final Expression deleteWhere = Expression.and(Expression.equals(DirectMessages.ACCOUNT_ID, accountId), // final Expression deleteWhere = Expression.and(Expression.equals(DirectMessages.ACCOUNT_ID, accountId),
Expression.in(new Column(DirectMessages.MESSAGE_ID), new RawItemArray(messageIds))); // Expression.in(new Column(DirectMessages.MESSAGE_ID), new RawItemArray(messageIds)));
final Uri deleteUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, false); // final Uri deleteUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, false);
mResolver.delete(deleteUri, deleteWhere.getSQL(), null); // mResolver.delete(deleteUri, deleteWhere.getSQL(), null);
// Insert previously fetched items. // Insert previously fetched items.
final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify); final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
@ -1834,9 +1837,18 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return since_ids != null && since_ids.length == account_ids.length; return since_ids != null && since_ids.length == account_ids.length;
} }
@Override
protected void onPreExecute() {
super.onPreExecute();
final Bus bus = TwidereApplication.getInstance(getContext()).getMessageBus();
bus.post(new GetMessagesTaskEvent(getDatabaseUri(), true));
}
@Override @Override
protected void onPostExecute(final List<MessageListResponse> result) { protected void onPostExecute(final List<MessageListResponse> result) {
super.onPostExecute(result); super.onPostExecute(result);
final Bus bus = TwidereApplication.getInstance(getContext()).getMessageBus();
bus.post(new GetMessagesTaskEvent(getDatabaseUri(), false));
for (final TwitterListResponse<DirectMessage> response : result) { for (final TwitterListResponse<DirectMessage> response : result) {
if (response.list == null) { if (response.list == null) {
mMessagesManager.showErrorMessage(R.string.action_refreshing_direct_messages, mMessagesManager.showErrorMessage(R.string.action_refreshing_direct_messages,

View File

@ -54,7 +54,8 @@ public class ContentListScrollListener extends OnScrollListener {
} }
final IContentCardAdapter adapter = mContentListSupport.getAdapter(); final IContentCardAdapter adapter = mContentListSupport.getAdapter();
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!mContentListSupport.isRefreshing() && adapter.hasLoadMoreIndicator() && mScrollState != RecyclerView.SCROLL_STATE_IDLE if (!mContentListSupport.isRefreshing() && adapter.isLoadMoreSupported()
&& !adapter.isLoadMoreIndicatorVisible() && mScrollState != RecyclerView.SCROLL_STATE_IDLE
&& layoutManager.findLastVisibleItemPosition() == adapter.getItemCount() - 1) { && layoutManager.findLastVisibleItemPosition() == adapter.getItemCount() - 1) {
mContentListSupport.onLoadMoreContents(); mContentListSupport.onLoadMoreContents();
} }

View File

@ -119,8 +119,14 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
} }
private void createTriggers(SQLiteDatabase db) { private void createTriggers(SQLiteDatabase db) {
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_statuses").getSQL());
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_mentions").getSQL());
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_received_messages").getSQL());
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_sent_messages").getSQL());
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_statuses", Statuses.TABLE_NAME).getSQL()); db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_statuses", Statuses.TABLE_NAME).getSQL());
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_mentions", Mentions.TABLE_NAME).getSQL()); db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_mentions", Mentions.TABLE_NAME).getSQL());
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_received_messages", DirectMessages.Inbox.TABLE_NAME).getSQL());
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_sent_messages", DirectMessages.Outbox.TABLE_NAME).getSQL());
} }
private SQLQuery createDeleteDuplicateStatusTrigger(String triggerName, String tableName) { private SQLQuery createDeleteDuplicateStatusTrigger(String triggerName, String tableName) {
@ -135,6 +141,18 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
} }
private SQLQuery createDeleteDuplicateMessageTrigger(String triggerName, String tableName) {
final Table table = new Table(tableName);
final SQLDeleteQuery deleteOld = SQLQueryBuilder.deleteFrom(table).where(Expression.and(
Expression.equals(new Column(DirectMessages.ACCOUNT_ID), new Column(Table.NEW, DirectMessages.ACCOUNT_ID)),
Expression.equals(new Column(DirectMessages.MESSAGE_ID), new Column(Table.NEW, DirectMessages.MESSAGE_ID))
)).build();
return SQLQueryBuilder.createTrigger(false, true, triggerName)
.type(Type.BEFORE).event(Event.INSERT).on(table).forEachRow(true)
.actions(deleteOld).build();
}
@Override @Override
public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
handleVersionChange(db, oldVersion, newVersion); handleVersionChange(db, oldVersion, newVersion);

View File

@ -0,0 +1,38 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util.message;
import android.net.Uri;
import android.support.annotation.NonNull;
/**
* Created by mariotaku on 14/12/10.
*/
public class GetMessagesTaskEvent {
@NonNull
public final Uri uri;
public final boolean running;
public GetMessagesTaskEvent(@NonNull Uri uri, boolean running) {
this.uri = uri;
this.running = running;
}
}

View File

@ -2,8 +2,8 @@
<resources> <resources>
<color name="nyan_background">#003366</color> <color name="nyan_background">#003366</color>
<color name="bg_color_light">#e5e5e5</color> <color name="background_color_window_light">#e3e3e3</color>
<color name="bg_color_dark">#101010</color> <color name="background_color_window_dark">#101010</color>
<color name="bg_refresh_progress_color_light">#f5f5f5</color> <color name="bg_refresh_progress_color_light">#f5f5f5</color>
<color name="bg_refresh_progress_color_dark">#333333</color> <color name="bg_refresh_progress_color_dark">#333333</color>
<color name="bg_color_transparent_dark">#ff000000</color> <color name="bg_color_transparent_dark">#ff000000</color>
@ -27,5 +27,7 @@
<color name="branding_color">@color/material_cyan</color> <color name="branding_color">@color/material_cyan</color>
<color name="bg_color_tab_pressed">#40808080</color> <color name="bg_color_tab_pressed">#40808080</color>
<color name="bg_color_media_viewer">#a0000000</color> <color name="bg_color_media_viewer">#a0000000</color>
<color name="background_color_card_item_dark">#1a1a1a</color>
<color name="background_color_card_item_light">#fafafa</color>
</resources> </resources>

View File

@ -30,7 +30,7 @@
<!-- Window attributes --> <!-- Window attributes -->
<!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>--> <!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>-->
<!--<item name="android:windowBackground">@color/bg_color_dark</item>--> <item name="android:windowBackground">@color/background_color_window_dark</item>
<!-- ActionBar styles --> <!-- ActionBar styles -->
<item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar.Solid <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar.Solid
@ -42,7 +42,7 @@
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item> <item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item> <item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item> <item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item> <item name="cardItemBackgroundColor">@color/background_color_card_item_dark</item>
<!-- Twidere specific styles --> <!-- Twidere specific styles -->
<item name="menuIconColor">@color/action_icon_light</item> <item name="menuIconColor">@color/action_icon_light</item>
@ -57,7 +57,7 @@
<!-- Window attributes --> <!-- Window attributes -->
<!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>--> <!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>-->
<!--<item name="android:windowBackground">@color/bg_color_light</item>--> <item name="android:windowBackground">@color/background_color_window_light</item>
<!-- ActionBar styles --> <!-- ActionBar styles -->
<!--<item name="android:actionBarStyle">@style/Widget.Twidere.ActionBar.Light.DarkActionBar</item>--> <!--<item name="android:actionBarStyle">@style/Widget.Twidere.ActionBar.Light.DarkActionBar</item>-->
@ -157,7 +157,7 @@
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item> <item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item> <item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item> <item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item> <item name="cardItemBackgroundColor">@color/background_color_card_item_dark</item>
<!-- Twidere specific styles --> <!-- Twidere specific styles -->
@ -174,7 +174,7 @@
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item> <item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.Light.ProfileImage</item> <item name="profileImageStyle">@style/Widget.Light.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item> <item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#f8f8f8</item> <item name="cardItemBackgroundColor">@color/background_color_card_item_light</item>
<!-- Twidere specific styles --> <!-- Twidere specific styles -->
@ -239,7 +239,7 @@
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item> <item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item> <item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item> <item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item> <item name="cardItemBackgroundColor">@color/background_color_card_item_dark</item>
<!-- Twidere specific styles --> <!-- Twidere specific styles -->
<item name="menuIconColor">@color/action_icon_light</item> <item name="menuIconColor">@color/action_icon_light</item>
@ -297,11 +297,11 @@
<style name="Theme.Twidere.Settings.Dark" parent="Theme.Base"> <style name="Theme.Twidere.Settings.Dark" parent="Theme.Base">
<!-- Colors --> <!-- Colors -->
<item name="android:colorBackgroundCacheHint">@color/bg_color_dark</item> <item name="android:colorBackgroundCacheHint">@color/background_color_window_dark</item>
<!-- Window attributes --> <!-- Window attributes -->
<!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>--> <!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>-->
<!--<item name="android:windowBackground">@color/bg_color_dark</item>--> <item name="android:windowBackground">@color/background_color_window_dark</item>
<!-- ActionBar styles --> <!-- ActionBar styles -->
<item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar.Solid <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar.Solid
@ -313,7 +313,7 @@
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item> <item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item> <item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item> <item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item> <item name="cardItemBackgroundColor">@color/background_color_card_item_dark</item>
<!-- Twidere specific styles --> <!-- Twidere specific styles -->
<item name="menuIconColor">@color/action_icon_light</item> <item name="menuIconColor">@color/action_icon_light</item>
@ -324,11 +324,11 @@
<style name="Theme.Twidere.Settings.Light" parent="Theme.Base.Light"> <style name="Theme.Twidere.Settings.Light" parent="Theme.Base.Light">
<!-- Colors --> <!-- Colors -->
<item name="android:colorBackgroundCacheHint">@color/bg_color_light</item> <item name="android:colorBackgroundCacheHint">@color/background_color_window_light</item>
<!-- Window attributes --> <!-- Window attributes -->
<!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>--> <!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>-->
<!--<item name="android:windowBackground">@color/bg_color_light</item>--> <item name="android:windowBackground">@color/background_color_window_light</item>
<!-- Custom view styles --> <!-- Custom view styles -->
@ -336,7 +336,7 @@
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item> <item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.Light.ProfileImage</item> <item name="profileImageStyle">@style/Widget.Light.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item> <item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#f8f8f8</item> <item name="cardItemBackgroundColor">@color/background_color_card_item_light</item>
<!-- Twidere specific styles --> <!-- Twidere specific styles -->
<item name="menuIconColor">@color/action_icon_dark</item> <item name="menuIconColor">@color/action_icon_dark</item>
@ -351,7 +351,7 @@
<!-- Window attributes --> <!-- Window attributes -->
<!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>--> <!--<item name="android:windowAnimationStyle">@style/Animation.Twidere.Activity</item>-->
<!--<item name="android:windowBackground">@color/bg_color_light</item>--> <item name="android:windowBackground">@color/background_color_window_light</item>
<!-- Custom view styles --> <!-- Custom view styles -->
@ -359,7 +359,7 @@
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item> <item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.Light.ProfileImage</item> <item name="profileImageStyle">@style/Widget.Light.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item> <item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#f8f8f8</item> <item name="cardItemBackgroundColor">@color/background_color_card_item_light</item>
<!-- Twidere specific styles --> <!-- Twidere specific styles -->
<item name="menuIconColor">@color/action_icon_dark</item> <item name="menuIconColor">@color/action_icon_dark</item>