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

323 lines
12 KiB
Java

/*
* 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.fragment.support;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.Loader;
import com.desmond.asyncmanager.AsyncManager;
import com.desmond.asyncmanager.TaskRunnable;
import com.squareup.otto.Subscribe;
import org.mariotaku.library.objectcursor.ObjectCursor;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.adapter.AbsActivitiesAdapter;
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter;
import org.mariotaku.twidere.loader.support.ExtendedObjectCursorLoader;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.model.ParcelableActivityCursorIndices;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.message.AccountChangedEvent;
import org.mariotaku.twidere.util.message.FavoriteCreatedEvent;
import org.mariotaku.twidere.util.message.FavoriteDestroyedEvent;
import org.mariotaku.twidere.util.message.GetActivitiesTaskEvent;
import org.mariotaku.twidere.util.message.StatusDestroyedEvent;
import org.mariotaku.twidere.util.message.StatusListChangedEvent;
import org.mariotaku.twidere.util.message.StatusRetweetedEvent;
import java.util.List;
import static org.mariotaku.twidere.util.DataStoreUtils.getTableNameByUri;
/**
* Created by mariotaku on 14/12/3.
*/
public abstract class CursorActivitiesFragment extends AbsActivitiesFragment<List<ParcelableActivity>> {
@Override
protected void onLoadingFinished() {
final long[] accountIds = getAccountIds();
final AbsActivitiesAdapter<List<ParcelableActivity>> adapter = getAdapter();
if (adapter.getItemCount() > 0) {
showContent();
} else if (accountIds.length > 0) {
showContent();
showEmpty(R.drawable.ic_info_refresh, getString(R.string.swipe_down_to_refresh));
} else {
showError(R.drawable.ic_info_accounts, getString(R.string.no_account_selected));
}
}
private ContentObserver mContentObserver;
public abstract Uri getContentUri();
@Override
protected Loader<List<ParcelableActivity>> onCreateStatusesLoader(final Context context,
final Bundle args,
final boolean fromUser) {
final Uri uri = getContentUri();
final String table = getTableNameByUri(uri);
final String sortOrder = getSortOrder();
final long[] accountIds = getAccountIds();
final Expression accountWhere = Expression.in(new Column(Activities.ACCOUNT_ID), new RawItemArray(accountIds));
final Expression filterWhere = getFiltersWhere(table), where;
if (filterWhere != null) {
where = Expression.and(accountWhere, filterWhere);
} else {
where = accountWhere;
}
final String selection = processWhere(where).getSQL();
final AbsActivitiesAdapter<List<ParcelableActivity>> adapter = getAdapter();
adapter.setShowAccountsColor(accountIds.length > 1);
final String[] projection = Activities.COLUMNS;
return new CursorActivitiesLoader(context, uri, projection, selection, null, sortOrder,
fromUser);
}
@Override
protected Object createMessageBusCallback() {
return new CursorActivitiesBusCallback();
}
@Override
protected long[] getAccountIds() {
final Bundle args = getArguments();
if (args != null && args.getLong(EXTRA_ACCOUNT_ID) > 0) {
return new long[]{args.getLong(EXTRA_ACCOUNT_ID)};
}
final FragmentActivity activity = getActivity();
if (activity instanceof HomeActivity) {
return ((HomeActivity) activity).getActivatedAccountIds();
}
return DataStoreUtils.getActivatedAccountIds(getActivity());
}
@Override
public void onStart() {
super.onStart();
final ContentResolver cr = getContentResolver();
mContentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
reloadActivities();
}
};
cr.registerContentObserver(Accounts.CONTENT_URI, true, mContentObserver);
cr.registerContentObserver(Filters.CONTENT_URI, true, mContentObserver);
updateRefreshState();
reloadActivities();
}
protected void reloadActivities() {
if (getActivity() == null || isDetached()) return;
final Bundle args = new Bundle(), fragmentArgs = getArguments();
if (fragmentArgs != null) {
args.putAll(fragmentArgs);
args.putBoolean(EXTRA_FROM_USER, true);
}
getLoaderManager().restartLoader(0, args, this);
}
@Override
public void onStop() {
final ContentResolver cr = getContentResolver();
cr.unregisterContentObserver(mContentObserver);
super.onStop();
}
@Override
protected boolean hasMoreData(final List<ParcelableActivity> cursor) {
return cursor != null && cursor.size() != 0;
}
@NonNull
@Override
protected ParcelableActivitiesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableActivitiesAdapter(context, compact, false);
}
@Override
public void onLoaderReset(Loader<List<ParcelableActivity>> loader) {
getAdapter().setData(null);
}
@Override
public void onLoadMoreContents(boolean fromStart) {
if (fromStart) return;
//noinspection ConstantConditions
super.onLoadMoreContents(fromStart);
AsyncManager.runBackgroundTask(new TaskRunnable<Object, long[][], CursorActivitiesFragment>() {
@Override
public long[][] doLongOperation(Object o) throws InterruptedException {
final long[][] result = new long[3][];
result[0] = getAccountIds();
result[1] = getOldestActivityIds(result[0]);
return result;
}
@Override
public void callback(CursorActivitiesFragment fragment, long[][] result) {
fragment.getActivities(result[0], result[1], result[2]);
}
}.setResultHandler(this));
}
@Override
public boolean triggerRefresh() {
super.triggerRefresh();
AsyncManager.runBackgroundTask(new TaskRunnable<Object, long[][], CursorActivitiesFragment>() {
@Override
public long[][] doLongOperation(Object o) throws InterruptedException {
final long[][] result = new long[3][];
result[0] = getAccountIds();
result[2] = getNewestActivityIds(result[0]);
return result;
}
@Override
public void callback(CursorActivitiesFragment fragment, long[][] result) {
fragment.getActivities(result[0], result[1], result[2]);
}
}.setResultHandler(this));
return true;
}
protected Expression getFiltersWhere(String table) {
if (!isFilterEnabled()) return null;
return DataStoreUtils.buildActivityFilterWhereClause(table, null);
}
protected long[] getNewestActivityIds(long[] accountIds) {
return DataStoreUtils.getActivityMaxPositionsFromDatabase(getActivity(), getContentUri(), accountIds);
}
protected abstract int getNotificationType();
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
for (long accountId : getAccountIds()) {
mTwitterWrapper.clearNotificationAsync(getNotificationType(), accountId);
}
}
}
protected long[] getOldestActivityIds(long[] accountIds) {
return DataStoreUtils.getOldestActivityMinPositions(getActivity(), getContentUri(), accountIds);
}
protected abstract boolean isFilterEnabled();
protected Expression processWhere(final Expression where) {
return where;
}
protected abstract void updateRefreshState();
private String getSortOrder() {
return Activities.DEFAULT_SORT_ORDER;
}
protected class CursorActivitiesBusCallback {
@Subscribe
public void notifyGetStatusesTaskChanged(GetActivitiesTaskEvent event) {
if (!event.uri.equals(getContentUri())) return;
setRefreshing(event.running);
if (!event.running) {
setLoadMoreIndicatorVisible(false);
setRefreshEnabled(true);
}
}
@Subscribe
public void notifyFavoriteCreated(FavoriteCreatedEvent event) {
}
@Subscribe
public void notifyFavoriteDestroyed(FavoriteDestroyedEvent event) {
}
@Subscribe
public void notifyStatusDestroyed(StatusDestroyedEvent event) {
}
@Subscribe
public void notifyStatusListChanged(StatusListChangedEvent event) {
getAdapter().notifyDataSetChanged();
}
@Subscribe
public void notifyStatusRetweeted(StatusRetweetedEvent event) {
}
@Subscribe
public void notifyAccountChanged(AccountChangedEvent event) {
}
}
public static class CursorActivitiesLoader extends ExtendedObjectCursorLoader<ParcelableActivity> {
public CursorActivitiesLoader(Context context, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
boolean fromUser) {
super(context, ParcelableActivityCursorIndices.class, uri, projection, selection, selectionArgs, sortOrder, fromUser);
}
@Override
protected ObjectCursor<ParcelableActivity> createObjectCursor(Cursor cursor, ObjectCursor.CursorIndices<ParcelableActivity> indices) {
return new ActivityCursor(cursor, indices, DataStoreUtils.getFilteredUserIds(getContext()));
}
public static class ActivityCursor extends ObjectCursor<ParcelableActivity> {
private final long[] filteredUserIds;
public ActivityCursor(Cursor cursor, CursorIndices<ParcelableActivity> indies, long[] filteredUserIds) {
super(cursor, indies);
this.filteredUserIds = filteredUserIds;
}
public long[] getFilteredUserIds() {
return filteredUserIds;
}
}
}
}