improved activity gap
This commit is contained in:
parent
f153aea3ad
commit
1d42bca508
|
@ -8,7 +8,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
|
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
|
||||||
classpath 'com.android.tools.build:gradle:2.0.0-beta7'
|
classpath 'com.android.tools.build:gradle:2.0.0-rc1'
|
||||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
||||||
classpath('fr.avianey.androidsvgdrawable:gradle-plugin:3.0.0') {
|
classpath('fr.avianey.androidsvgdrawable:gradle-plugin:3.0.0') {
|
||||||
// should be excluded to avoid conflict
|
// should be excluded to avoid conflict
|
||||||
|
|
|
@ -119,7 +119,7 @@ dependencies {
|
||||||
compile 'com.android.support:preference-v14:23.2.1'
|
compile 'com.android.support:preference-v14:23.2.1'
|
||||||
compile 'com.twitter:twitter-text:1.13.0'
|
compile 'com.twitter:twitter-text:1.13.0'
|
||||||
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||||
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.4.1'
|
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.5.0'
|
||||||
compile 'com.squareup:otto:1.3.8'
|
compile 'com.squareup:otto:1.3.8'
|
||||||
compile 'dnsjava:dnsjava:2.1.7'
|
compile 'dnsjava:dnsjava:2.1.7'
|
||||||
compile 'com.commonsware.cwac:merge:1.1.1'
|
compile 'com.commonsware.cwac:merge:1.1.1'
|
||||||
|
@ -183,4 +183,4 @@ task svgToMipmap(type: SvgDrawableTask) {
|
||||||
outputFormat = 'PNG'
|
outputFormat = 'PNG'
|
||||||
|
|
||||||
outputType = 'mipmap'
|
outputType = 'mipmap'
|
||||||
}
|
}
|
||||||
|
|
|
@ -511,8 +511,8 @@ public abstract class AbsActivitiesFragment extends AbsContentListRecyclerViewFr
|
||||||
final LinearLayoutManager layoutManager = getLayoutManager();
|
final LinearLayoutManager layoutManager = getLayoutManager();
|
||||||
adapter.setListener(this);
|
adapter.setListener(this);
|
||||||
registerForContextMenu(recyclerView);
|
registerForContextMenu(recyclerView);
|
||||||
mNavigationHelper = new RecyclerViewNavigationHelper(recyclerView, layoutManager,
|
mNavigationHelper = new RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter,
|
||||||
adapter, this);
|
this);
|
||||||
mPauseOnScrollListener = new PauseRecyclerViewOnScrollListener(adapter.getMediaLoader().getImageLoader(), false, true);
|
mPauseOnScrollListener = new PauseRecyclerViewOnScrollListener(adapter.getMediaLoader().getImageLoader(), false, true);
|
||||||
|
|
||||||
final Bundle loaderArgs = new Bundle(getArguments());
|
final Bundle loaderArgs = new Bundle(getArguments());
|
||||||
|
@ -521,6 +521,27 @@ public abstract class AbsActivitiesFragment extends AbsContentListRecyclerViewFr
|
||||||
showProgress();
|
showProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReachingEnd() {
|
||||||
|
final LinearLayoutManager lm = getLayoutManager();
|
||||||
|
final ParcelableActivitiesAdapter adapter = getAdapter();
|
||||||
|
int lastPosition = lm.findLastCompletelyVisibleItemPosition();
|
||||||
|
final int itemCount = adapter.getItemCount();
|
||||||
|
int finalPos = itemCount - 1;
|
||||||
|
for (int i = lastPosition + 1; i < itemCount; i++) {
|
||||||
|
if (adapter.getItemViewType(i) != ParcelableActivitiesAdapter.ITEM_VIEW_TYPE_EMPTY) {
|
||||||
|
finalPos = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return finalPos >= itemCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReachingStart() {
|
||||||
|
return super.isReachingStart();
|
||||||
|
}
|
||||||
|
|
||||||
protected Object createMessageBusCallback() {
|
protected Object createMessageBusCallback() {
|
||||||
return new StatusesBusCallback();
|
return new StatusesBusCallback();
|
||||||
}
|
}
|
||||||
|
@ -578,11 +599,7 @@ public abstract class AbsActivitiesFragment extends AbsContentListRecyclerViewFr
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupRecyclerView(Context context, boolean compact) {
|
protected void setupRecyclerView(Context context, final boolean compact) {
|
||||||
if (compact) {
|
|
||||||
super.setupRecyclerView(context, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final RecyclerView recyclerView = getRecyclerView();
|
final RecyclerView recyclerView = getRecyclerView();
|
||||||
final ParcelableActivitiesAdapter adapter = getAdapter();
|
final ParcelableActivitiesAdapter adapter = getAdapter();
|
||||||
// Dividers are drawn on bottom of view
|
// Dividers are drawn on bottom of view
|
||||||
|
@ -595,7 +612,9 @@ public abstract class AbsActivitiesFragment extends AbsContentListRecyclerViewFr
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final int itemViewType = adapter.getItemViewType(childPos);
|
final int itemViewType = adapter.getItemViewType(childPos);
|
||||||
// Draw only if current item and next item is TITLE_SUMMARY
|
if (compact) {
|
||||||
|
return itemViewType != ParcelableActivitiesAdapter.ITEM_VIEW_TYPE_EMPTY;
|
||||||
|
}
|
||||||
if (shouldUseDividerFor(itemViewType)) {
|
if (shouldUseDividerFor(itemViewType)) {
|
||||||
if (shouldUseDividerFor(adapter.getItemViewType(childPos + 1))) {
|
if (shouldUseDividerFor(adapter.getItemViewType(childPos + 1))) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -43,7 +43,6 @@ import org.mariotaku.twidere.activity.HomeActivity;
|
||||||
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter;
|
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter;
|
||||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
|
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
|
||||||
import org.mariotaku.twidere.loader.ExtendedObjectCursorLoader;
|
import org.mariotaku.twidere.loader.ExtendedObjectCursorLoader;
|
||||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
|
||||||
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.ParcelableStatus;
|
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||||
|
@ -55,7 +54,6 @@ import org.mariotaku.twidere.model.message.GetActivitiesTaskEvent;
|
||||||
import org.mariotaku.twidere.model.message.StatusDestroyedEvent;
|
import org.mariotaku.twidere.model.message.StatusDestroyedEvent;
|
||||||
import org.mariotaku.twidere.model.message.StatusListChangedEvent;
|
import org.mariotaku.twidere.model.message.StatusListChangedEvent;
|
||||||
import org.mariotaku.twidere.model.message.StatusRetweetedEvent;
|
import org.mariotaku.twidere.model.message.StatusRetweetedEvent;
|
||||||
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
|
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
|
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
|
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
|
||||||
|
@ -123,7 +121,7 @@ public abstract class CursorActivitiesFragment extends AbsActivitiesFragment {
|
||||||
adapter.setShowAccountsColor(accountKeys.length > 1);
|
adapter.setShowAccountsColor(accountKeys.length > 1);
|
||||||
final String[] projection = Activities.COLUMNS;
|
final String[] projection = Activities.COLUMNS;
|
||||||
return new CursorActivitiesLoader(context, uri, projection, selection, expression.whereArgs,
|
return new CursorActivitiesLoader(context, uri, projection, selection, expression.whereArgs,
|
||||||
sortOrder, fromUser, accountKeys);
|
sortOrder, fromUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -393,19 +391,17 @@ public abstract class CursorActivitiesFragment extends AbsActivitiesFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CursorActivitiesLoader extends ExtendedObjectCursorLoader<ParcelableActivity> {
|
public static class CursorActivitiesLoader extends ExtendedObjectCursorLoader<ParcelableActivity> {
|
||||||
private final UserKey[] mAccountKeys;
|
|
||||||
|
|
||||||
public CursorActivitiesLoader(Context context, Uri uri, String[] projection,
|
public CursorActivitiesLoader(Context context, Uri uri, String[] projection,
|
||||||
String selection, String[] selectionArgs, String sortOrder,
|
String selection, String[] selectionArgs,
|
||||||
boolean fromUser, UserKey[] accountKeys) {
|
String sortOrder, boolean fromUser) {
|
||||||
super(context, ParcelableActivityCursorIndices.class, uri, projection, selection, selectionArgs, sortOrder, fromUser);
|
super(context, ParcelableActivityCursorIndices.class, uri, projection, selection,
|
||||||
mAccountKeys = accountKeys;
|
selectionArgs, sortOrder, fromUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ObjectCursor<ParcelableActivity> createObjectCursor(Cursor cursor, ObjectCursor.CursorIndices<ParcelableActivity> indices) {
|
protected ObjectCursor<ParcelableActivity> createObjectCursor(Cursor cursor, ObjectCursor.CursorIndices<ParcelableActivity> indices) {
|
||||||
final String[] filteredUserIds = DataStoreUtils.getFilteredUserIds(getContext());
|
final String[] filteredUserIds = DataStoreUtils.getFilteredUserIds(getContext());
|
||||||
final ParcelableAccount[] accounts = ParcelableAccountUtils.getAccounts(getContext(), mAccountKeys);
|
|
||||||
return new ActivityCursor(cursor, indices, filteredUserIds);
|
return new ActivityCursor(cursor, indices, filteredUserIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
|
||||||
if (param.shouldAbort()) return null;
|
if (param.shouldAbort()) return null;
|
||||||
final UserKey[] accountIds = param.getAccountKeys();
|
final UserKey[] accountIds = param.getAccountKeys();
|
||||||
final String[] maxIds = param.getMaxIds();
|
final String[] maxIds = param.getMaxIds();
|
||||||
|
final long[] maxSortIds = param.getMaxSortIds();
|
||||||
final String[] sinceIds = param.getSinceIds();
|
final String[] sinceIds = param.getSinceIds();
|
||||||
final ContentResolver cr = context.getContentResolver();
|
final ContentResolver cr = context.getContentResolver();
|
||||||
final int loadItemLimit = preferences.getInt(KEY_LOAD_ITEM_LIMIT);
|
final int loadItemLimit = preferences.getInt(KEY_LOAD_ITEM_LIMIT);
|
||||||
|
@ -88,8 +89,12 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
|
||||||
final Paging paging = new Paging();
|
final Paging paging = new Paging();
|
||||||
paging.count(loadItemLimit);
|
paging.count(loadItemLimit);
|
||||||
String maxId = null;
|
String maxId = null;
|
||||||
|
long maxSortId = -1;
|
||||||
if (maxIds != null) {
|
if (maxIds != null) {
|
||||||
maxId = maxIds[i];
|
maxId = maxIds[i];
|
||||||
|
if (maxSortIds != null) {
|
||||||
|
maxSortId = maxSortIds[i];
|
||||||
|
}
|
||||||
if (maxId != null) {
|
if (maxId != null) {
|
||||||
paging.maxId(maxId);
|
paging.maxId(maxId);
|
||||||
}
|
}
|
||||||
|
@ -139,23 +144,44 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
|
||||||
long[] deleteBound = new long[2];
|
long[] deleteBound = new long[2];
|
||||||
Arrays.fill(deleteBound, -1);
|
Arrays.fill(deleteBound, -1);
|
||||||
List<ContentValues> valuesList = new ArrayList<>();
|
List<ContentValues> valuesList = new ArrayList<>();
|
||||||
for (Activity activity : activities) {
|
int minIdx = -1;
|
||||||
final ParcelableActivity parcelableActivity = ParcelableActivityUtils.fromActivity(activity,
|
long minPositionKey = -1;
|
||||||
credentials.account_key, false);
|
if (!activities.isEmpty()) {
|
||||||
if (deleteBound[0] < 0) {
|
final long firstSortId = activities.get(0).getCreatedAt().getTime();
|
||||||
deleteBound[0] = parcelableActivity.min_sort_position;
|
final long lastSortId = activities.get(activities.size() - 1).getCreatedAt().getTime();
|
||||||
} else {
|
// Get id diff of first and last item
|
||||||
deleteBound[0] = Math.min(deleteBound[0], parcelableActivity.min_sort_position);
|
final long sortDiff = firstSortId - lastSortId;
|
||||||
|
for (int i = 0, j = activities.size(); i < j; i++) {
|
||||||
|
Activity item = activities.get(i);
|
||||||
|
final ParcelableActivity activity = ParcelableActivityUtils.fromActivity(item,
|
||||||
|
credentials.account_key, false);
|
||||||
|
activity.position_key = GetStatusesTask.getPositionKey(activity.timestamp,
|
||||||
|
activity.timestamp, lastSortId, sortDiff, i, j);
|
||||||
|
if (deleteBound[0] < 0) {
|
||||||
|
deleteBound[0] = activity.min_sort_position;
|
||||||
|
} else {
|
||||||
|
deleteBound[0] = Math.min(deleteBound[0], activity.min_sort_position);
|
||||||
|
}
|
||||||
|
if (deleteBound[1] < 0) {
|
||||||
|
deleteBound[1] = activity.max_sort_position;
|
||||||
|
} else {
|
||||||
|
deleteBound[1] = Math.max(deleteBound[1], activity.max_sort_position);
|
||||||
|
}
|
||||||
|
if (minIdx == -1 || item.compareTo(activities.get(minIdx)) < 0) {
|
||||||
|
minIdx = i;
|
||||||
|
minPositionKey = activity.position_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.inserted_date = System.currentTimeMillis();
|
||||||
|
final ContentValues values = ContentValuesCreator.createActivity(activity,
|
||||||
|
credentials, userColorNameManager);
|
||||||
|
valuesList.add(values);
|
||||||
}
|
}
|
||||||
if (deleteBound[1] < 0) {
|
}
|
||||||
deleteBound[1] = parcelableActivity.max_sort_position;
|
int olderCount = -1;
|
||||||
} else {
|
if (minPositionKey > 0) {
|
||||||
deleteBound[1] = Math.max(deleteBound[1], parcelableActivity.max_sort_position);
|
olderCount = DataStoreUtils.getActivitiesCount(context, getContentUri(), minPositionKey,
|
||||||
}
|
Activities.POSITION_KEY, false, credentials.account_key);
|
||||||
parcelableActivity.inserted_date = System.currentTimeMillis();
|
|
||||||
final ContentValues values = ContentValuesCreator.createActivity(parcelableActivity,
|
|
||||||
credentials, userColorNameManager);
|
|
||||||
valuesList.add(values);
|
|
||||||
}
|
}
|
||||||
final Uri writeUri = UriUtils.appendQueryParameters(getContentUri(), QUERY_PARAM_NOTIFY,
|
final Uri writeUri = UriUtils.appendQueryParameters(getContentUri(), QUERY_PARAM_NOTIFY,
|
||||||
notify);
|
notify);
|
||||||
|
@ -169,7 +195,7 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
|
||||||
String.valueOf(deleteBound[1])};
|
String.valueOf(deleteBound[1])};
|
||||||
int rowsDeleted = cr.delete(writeUri, where.getSQL(), whereArgs);
|
int rowsDeleted = cr.delete(writeUri, where.getSQL(), whereArgs);
|
||||||
// Why loadItemLimit / 2? because it will not acting strange in most cases
|
// Why loadItemLimit / 2? because it will not acting strange in most cases
|
||||||
boolean insertGap = valuesList.size() >= loadItemLimit && !noItemsBefore
|
boolean insertGap = valuesList.size() >= loadItemLimit && !noItemsBefore && olderCount > 0
|
||||||
&& rowsDeleted <= 0 && activities.size() > loadItemLimit / 2;
|
&& rowsDeleted <= 0 && activities.size() > loadItemLimit / 2;
|
||||||
if (insertGap && !valuesList.isEmpty()) {
|
if (insertGap && !valuesList.isEmpty()) {
|
||||||
valuesList.get(valuesList.size() - 1).put(Activities.IS_GAP, true);
|
valuesList.get(valuesList.size() - 1).put(Activities.IS_GAP, true);
|
||||||
|
|
|
@ -193,7 +193,7 @@ public abstract class GetStatusesTask extends AbstractTask<RefreshTaskParam,
|
||||||
final long firstSortId = statuses.get(0).getSortId();
|
final long firstSortId = statuses.get(0).getSortId();
|
||||||
final long lastSortId = statuses.get(statuses.size() - 1).getSortId();
|
final long lastSortId = statuses.get(statuses.size() - 1).getSortId();
|
||||||
// Get id diff of first and last item
|
// Get id diff of first and last item
|
||||||
long sortDiff = firstSortId - lastSortId;
|
final long sortDiff = firstSortId - lastSortId;
|
||||||
|
|
||||||
for (int i = 0, j = statuses.size(); i < j; i++) {
|
for (int i = 0, j = statuses.size(); i < j; i++) {
|
||||||
final Status item = statuses.get(i);
|
final Status item = statuses.get(i);
|
||||||
|
|
|
@ -486,6 +486,25 @@ public class DataStoreUtils implements Constants {
|
||||||
return queryCount(context, uri, selection.getSQL(), whereArgs);
|
return queryCount(context, uri, selection.getSQL(), whereArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getActivitiesCount(final Context context, final Uri uri, final long compare,
|
||||||
|
String compareColumn, boolean greaterThan, UserKey... accountKeys) {
|
||||||
|
if (context == null) return 0;
|
||||||
|
if (accountKeys == null) {
|
||||||
|
accountKeys = getActivatedAccountKeys(context);
|
||||||
|
}
|
||||||
|
final Expression selection = Expression.and(
|
||||||
|
Expression.inArgs(new Column(Activities.ACCOUNT_KEY), accountKeys.length),
|
||||||
|
greaterThan ? Expression.greaterThanArgs(compareColumn) : Expression.lesserThanArgs(compareColumn),
|
||||||
|
buildActivityFilterWhereClause(getTableNameByUri(uri), null)
|
||||||
|
);
|
||||||
|
final String[] whereArgs = new String[accountKeys.length + 1];
|
||||||
|
for (int i = 0; i < accountKeys.length; i++) {
|
||||||
|
whereArgs[i] = accountKeys[i].toString();
|
||||||
|
}
|
||||||
|
whereArgs[accountKeys.length] = String.valueOf(compare);
|
||||||
|
return queryCount(context, uri, selection.getSQL(), whereArgs);
|
||||||
|
}
|
||||||
|
|
||||||
public static int getActivitiesCount(@NonNull final Context context, final Uri uri,
|
public static int getActivitiesCount(@NonNull final Context context, final Uri uri,
|
||||||
final Expression extraWhere, final String[] extraWhereArgs,
|
final Expression extraWhere, final String[] extraWhereArgs,
|
||||||
final long since, String sinceColumn, boolean followingOnly,
|
final long since, String sinceColumn, boolean followingOnly,
|
||||||
|
|
|
@ -741,6 +741,7 @@ public final class Utils implements Constants {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LINK_ID_ITEMS: {
|
case LINK_ID_ITEMS: {
|
||||||
|
isAccountIdRequired = false;
|
||||||
fragment = new ItemsListFragment();
|
fragment = new ItemsListFragment();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue