mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-17 04:00:48 +01:00
improved drafts, now unsent tweet wont lost even killed by system
This commit is contained in:
parent
79e80bfaad
commit
793b6bf735
@ -179,6 +179,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
|
||||
public static final int VIRTUAL_TABLE_ID_UNREAD_COUNTS_BY_TYPE = 109;
|
||||
public static final int VIRTUAL_TABLE_ID_CACHED_USERS_WITH_RELATIONSHIP = 121;
|
||||
public static final int VIRTUAL_TABLE_ID_CACHED_USERS_WITH_SCORE = 122;
|
||||
public static final int VIRTUAL_TABLE_ID_DRAFTS_UNSENT = 131;
|
||||
|
||||
public static final int NOTIFICATION_ID_HOME_TIMELINE = 1;
|
||||
public static final int NOTIFICATION_ID_MENTIONS_TIMELINE = 2;
|
||||
|
@ -484,8 +484,10 @@ public interface TwidereDataStore {
|
||||
|
||||
public static final String TABLE_NAME = "drafts";
|
||||
public static final String CONTENT_PATH = TABLE_NAME;
|
||||
public static final String CONTENT_PATH_UNSENT = TABLE_NAME + "/unsent";
|
||||
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH);
|
||||
public static final Uri CONTENT_URI_UNSENT = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH_UNSENT);
|
||||
|
||||
/**
|
||||
* Status content.<br>
|
||||
|
@ -23,6 +23,8 @@ import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
@ -47,6 +49,8 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationCompat.Action;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
@ -92,6 +96,7 @@ import org.mariotaku.twidere.model.ParcelableStatusUpdate;
|
||||
import org.mariotaku.twidere.model.ParcelableUser;
|
||||
import org.mariotaku.twidere.preference.ServicePickerPreference;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||
import org.mariotaku.twidere.service.BackgroundOperationService;
|
||||
import org.mariotaku.twidere.task.TwidereAsyncTask;
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
import org.mariotaku.twidere.util.ContentValuesCreator;
|
||||
@ -511,7 +516,8 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
|
||||
builder.media(getMedia());
|
||||
}
|
||||
final ContentValues values = ContentValuesCreator.createStatusDraft(builder.build());
|
||||
mResolver.insert(Drafts.CONTENT_URI, values);
|
||||
final Uri draftUri = mResolver.insert(Drafts.CONTENT_URI, values);
|
||||
displayNewDraftNotification(text, draftUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -641,6 +647,25 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
|
||||
return Uri.fromFile(file);
|
||||
}
|
||||
|
||||
private void displayNewDraftNotification(String text, Uri draftUri) {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
|
||||
builder.setTicker(getString(R.string.draft_saved));
|
||||
builder.setContentTitle(getString(R.string.draft_saved));
|
||||
builder.setContentText(text);
|
||||
builder.setSmallIcon(R.drawable.ic_stat_info);
|
||||
builder.setAutoCancel(true);
|
||||
final Intent draftsIntent = new Intent(this, DraftsActivity.class);
|
||||
builder.setContentIntent(PendingIntent.getActivity(this, 0, draftsIntent, PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
final Intent serviceIntent = new Intent(this, BackgroundOperationService.class);
|
||||
serviceIntent.setAction(INTENT_ACTION_DISCARD_DRAFT);
|
||||
serviceIntent.setData(draftUri);
|
||||
final Action.Builder actionBuilder = new Action.Builder(R.drawable.ic_action_delete, getString(R.string.discard),
|
||||
PendingIntent.getService(this, 0, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
builder.addAction(actionBuilder.build());
|
||||
nm.notify(draftUri.toString(), NOTIFICATION_ID_DRAFTS, builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* The Location Manager manages location providers. This code searches for
|
||||
* the best provider of data (GPS, WiFi/cell phone tower lookup, some other
|
||||
@ -880,6 +905,13 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
|
||||
return true;
|
||||
}
|
||||
|
||||
private void saveAccountSelection() {
|
||||
if (!mShouldSaveAccounts) return;
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putString(KEY_COMPOSE_ACCOUNTS, TwidereArrayUtils.toString(mAccountsAdapter.getSelectedAccounts(), ',', false));
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private boolean setComposeTitle(final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (INTENT_ACTION_REPLY.equals(action)) {
|
||||
@ -977,13 +1009,6 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
|
||||
return true;
|
||||
}
|
||||
|
||||
private void saveAccountSelection() {
|
||||
if (!mShouldSaveAccounts) return;
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putString(KEY_COMPOSE_ACCOUNTS, TwidereArrayUtils.toString(mAccountsAdapter.getSelectedAccounts(), ',', false));
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private void updateMediaPreview() {
|
||||
final int count = mMediaPreviewAdapter.getCount();
|
||||
final Resources res = getResources();
|
||||
@ -1416,6 +1441,13 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
|
||||
return inflater.inflate(R.layout.dialog_scrollable_status, parent, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mStatusContainer = view.findViewById(R.id.status_container);
|
||||
mHolder = new StatusViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
@ -1441,13 +1473,6 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
|
||||
mStatusContainer.findViewById(R.id.reply_retweet_status).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mStatusContainer = view.findViewById(R.id.status_container);
|
||||
mHolder = new StatusViewHolder(view);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ package org.mariotaku.twidere.activity.support;
|
||||
import android.app.ActionBar;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@ -31,6 +32,7 @@ import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
@ -128,7 +130,7 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
||||
final Uri uri = Drafts.CONTENT_URI;
|
||||
final Uri uri = Drafts.CONTENT_URI_UNSENT;
|
||||
final String[] cols = Drafts.COLUMNS;
|
||||
final String orderBy = Drafts.TIMESTAMP + " DESC";
|
||||
return new CursorLoader(this, uri, cols, null, null, orderBy);
|
||||
@ -195,8 +197,6 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
|
||||
}
|
||||
mAdapter = new DraftsAdapter(this);
|
||||
mListView = (ListView) findViewById(android.R.id.list);
|
||||
mListView.setDivider(null);
|
||||
mListView.setSelector(android.R.color.transparent);
|
||||
mListView.setAdapter(mAdapter);
|
||||
mListView.setOnItemClickListener(this);
|
||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||
@ -281,6 +281,7 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final Context context = ThemeUtils.getDialogThemedContext(getActivity());
|
||||
@ -298,9 +299,11 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
|
||||
private static final String FRAGMENT_TAG_DELETING_DRAFTS = "deleting_drafts";
|
||||
private final FragmentActivity mActivity;
|
||||
private final long[] mIds;
|
||||
private final NotificationManager mNotificationManager;
|
||||
|
||||
private DeleteDraftsTask(final FragmentActivity activity, final long[] ids) {
|
||||
mActivity = activity;
|
||||
mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE);
|
||||
mIds = ids;
|
||||
}
|
||||
|
||||
@ -338,6 +341,10 @@ public class DraftsActivity extends BaseSupportActivity implements LoaderCallbac
|
||||
if (f instanceof DialogFragment) {
|
||||
((DialogFragment) f).dismiss();
|
||||
}
|
||||
for (long id : mIds) {
|
||||
final String tag = Uri.withAppendedPath(Drafts.CONTENT_URI, String.valueOf(id)).toString();
|
||||
mNotificationManager.cancel(tag, NOTIFICATION_ID_DRAFTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,7 +49,7 @@ public class DraftsAdapter extends SimpleCursorAdapter {
|
||||
private DraftItem.CursorIndices mIndices;
|
||||
|
||||
public DraftsAdapter(final Context context) {
|
||||
super(context, R.layout.card_item_draft, null, new String[0], new int[0], 0);
|
||||
super(context, R.layout.list_item_draft, null, new String[0], new int[0], 0);
|
||||
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
|
||||
mImageLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ import android.os.Looper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationCompat.Action;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
|
||||
@ -55,7 +54,9 @@ import com.squareup.otto.Bus;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.mariotaku.jsonserializer.JSONFileIO;
|
||||
import org.mariotaku.querybuilder.Columns.Column;
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
import org.mariotaku.querybuilder.RawItemArray;
|
||||
import org.mariotaku.querybuilder.query.SQLSelectQuery;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.R;
|
||||
@ -75,7 +76,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Preferences;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.UnreadCounts;
|
||||
import org.mariotaku.twidere.service.BackgroundOperationService;
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
import org.mariotaku.twidere.util.CustomTabUtils;
|
||||
import org.mariotaku.twidere.util.HtmlEscapeHelper;
|
||||
import org.mariotaku.twidere.util.ImagePreloader;
|
||||
@ -176,6 +177,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
return 0;
|
||||
}
|
||||
int result = 0;
|
||||
final long[] newIds = new long[valuesArray.length];
|
||||
if (table != null) {
|
||||
mDatabaseWrapper.beginTransaction();
|
||||
if (tableId == TABLE_ID_CACHED_USERS) {
|
||||
@ -183,9 +185,8 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
final Expression where = Expression.equals(CachedUsers.USER_ID,
|
||||
values.getAsLong(CachedUsers.USER_ID));
|
||||
mDatabaseWrapper.update(table, values, where.getSQL(), null);
|
||||
mDatabaseWrapper.insertWithOnConflict(table, null, values,
|
||||
SQLiteDatabase.CONFLICT_IGNORE);
|
||||
result++;
|
||||
newIds[result++] = mDatabaseWrapper.insertWithOnConflict(table, null,
|
||||
values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
} else if (tableId == TABLE_ID_SEARCH_HISTORY) {
|
||||
for (final ContentValues values : valuesArray) {
|
||||
@ -193,20 +194,17 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
final Expression where = Expression.equalsArgs(SearchHistory.QUERY);
|
||||
final String[] args = {values.getAsString(SearchHistory.QUERY)};
|
||||
mDatabaseWrapper.update(table, values, where.getSQL(), args);
|
||||
mDatabaseWrapper.insertWithOnConflict(table, null, values,
|
||||
SQLiteDatabase.CONFLICT_IGNORE);
|
||||
result++;
|
||||
newIds[result++] = mDatabaseWrapper.insertWithOnConflict(table, null,
|
||||
values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
} else if (shouldReplaceOnConflict(tableId)) {
|
||||
for (final ContentValues values : valuesArray) {
|
||||
mDatabaseWrapper.insertWithOnConflict(table, null, values,
|
||||
SQLiteDatabase.CONFLICT_REPLACE);
|
||||
result++;
|
||||
newIds[result++] = mDatabaseWrapper.insertWithOnConflict(table, null,
|
||||
values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
} else {
|
||||
for (final ContentValues values : valuesArray) {
|
||||
mDatabaseWrapper.insert(table, null, values);
|
||||
result++;
|
||||
newIds[result++] = mDatabaseWrapper.insert(table, null, values);
|
||||
}
|
||||
}
|
||||
mDatabaseWrapper.setTransactionSuccessful();
|
||||
@ -215,7 +213,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
if (result > 0) {
|
||||
onDatabaseUpdated(tableId, uri);
|
||||
}
|
||||
onNewItemsInserted(uri, tableId, valuesArray);
|
||||
onNewItemsInserted(uri, tableId, valuesArray, newIds);
|
||||
return result;
|
||||
} catch (final SQLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
@ -331,7 +329,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
rowId = mDatabaseWrapper.insert(table, null, values);
|
||||
}
|
||||
onDatabaseUpdated(tableId, uri);
|
||||
onNewItemsInserted(uri, tableId, values);
|
||||
onNewItemsInserted(uri, tableId, values, rowId);
|
||||
return Uri.withAppendedPath(uri, String.valueOf(rowId));
|
||||
} catch (final SQLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
@ -494,6 +492,22 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
setNotificationUri(c, CachedUsers.CONTENT_URI);
|
||||
return c;
|
||||
}
|
||||
case VIRTUAL_TABLE_ID_DRAFTS_UNSENT: {
|
||||
final TwidereApplication app = TwidereApplication.getInstance(getContext());
|
||||
final AsyncTwitterWrapper twitter = app.getTwitterWrapper();
|
||||
final RawItemArray sendingIds = new RawItemArray(twitter.getSendingDraftIds());
|
||||
final Expression where;
|
||||
if (selection != null) {
|
||||
where = Expression.and(new Expression(selection),
|
||||
Expression.notIn(new Column(Drafts._ID), sendingIds));
|
||||
} else {
|
||||
where = Expression.and(Expression.notIn(new Column(Drafts._ID), sendingIds));
|
||||
}
|
||||
final Cursor c = mDatabaseWrapper.query(Drafts.TABLE_NAME, projection,
|
||||
where.getSQL(), selectionArgs, null, null, sortOrder);
|
||||
setNotificationUri(c, getNotificationUri(tableId, uri));
|
||||
return c;
|
||||
}
|
||||
}
|
||||
if (table == null) return null;
|
||||
final Cursor c = mDatabaseWrapper.query(table, projection, selection, selectionArgs, null, null, sortOrder);
|
||||
@ -1174,7 +1188,13 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
notifyContentObserver(getNotificationUri(tableId, uri));
|
||||
}
|
||||
|
||||
private void onNewItemsInserted(final Uri uri, final int tableId, final ContentValues... valuesArray) {
|
||||
|
||||
private void onNewItemsInserted(final Uri uri, final int tableId, final ContentValues values, final long newId) {
|
||||
onNewItemsInserted(uri, tableId, new ContentValues[]{values}, new long[]{newId});
|
||||
|
||||
}
|
||||
|
||||
private void onNewItemsInserted(final Uri uri, final int tableId, final ContentValues[] valuesArray, final long[] newIds) {
|
||||
if (uri == null || valuesArray == null || valuesArray.length == 0) return;
|
||||
preloadImages(valuesArray);
|
||||
if (!uri.getBooleanQueryParameter(QUERY_PARAM_NOTIFY, true)) return;
|
||||
@ -1232,31 +1252,11 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
break;
|
||||
}
|
||||
case TABLE_ID_DRAFTS: {
|
||||
for (ContentValues values : valuesArray) {
|
||||
displayNewDraftNotification(values);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void displayNewDraftNotification(ContentValues values) {
|
||||
final Context context = getContext();
|
||||
final NotificationManager nm = getNotificationManager();
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
|
||||
builder.setTicker(context.getString(R.string.draft_saved));
|
||||
builder.setContentTitle(context.getString(R.string.draft_saved));
|
||||
builder.setContentText(values.getAsString(Drafts.TEXT));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_info);
|
||||
final Intent service = new Intent(context, BackgroundOperationService.class);
|
||||
service.setAction(INTENT_ACTION_DISCARD_DRAFT);
|
||||
final PendingIntent discardIntent = PendingIntent.getService(context, 0, service, 0);
|
||||
final Action.Builder actionBuilder = new Action.Builder(R.drawable.ic_action_delete,
|
||||
context.getString(R.string.discard), discardIntent);
|
||||
builder.addAction(actionBuilder.build());
|
||||
nm.notify(16, builder.build());
|
||||
}
|
||||
|
||||
private void preloadImages(final ContentValues... values) {
|
||||
if (values == null) return;
|
||||
for (final ContentValues v : values) {
|
||||
|
@ -41,6 +41,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.twitter.Extractor;
|
||||
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.activity.MainActivity;
|
||||
@ -60,12 +61,12 @@ import org.mariotaku.twidere.preference.ServicePickerPreference;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||
import org.mariotaku.twidere.util.TwidereArrayUtils;
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
import org.mariotaku.twidere.util.ContentValuesCreator;
|
||||
import org.mariotaku.twidere.util.ListUtils;
|
||||
import org.mariotaku.twidere.util.MediaUploaderInterface;
|
||||
import org.mariotaku.twidere.util.MessagesManager;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.StatusCodeMessageUtils;
|
||||
import org.mariotaku.twidere.util.StatusShortenerInterface;
|
||||
import org.mariotaku.twidere.util.TwidereValidator;
|
||||
@ -190,9 +191,21 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
handleUpdateStatusIntent(intent);
|
||||
} else if (INTENT_ACTION_SEND_DIRECT_MESSAGE.equals(action)) {
|
||||
handleSendDirectMessageIntent(intent);
|
||||
} else if (INTENT_ACTION_DISCARD_DRAFT.equals(action)) {
|
||||
handleDiscardDraftIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDiscardDraftIntent(Intent intent) {
|
||||
final Uri data = intent.getData();
|
||||
if (data == null) return;
|
||||
mNotificationManager.cancel(data.toString(), NOTIFICATION_ID_DRAFTS);
|
||||
final ContentResolver contentResolver = getContentResolver();
|
||||
final long id = ParseUtils.parseLong(data.getLastPathSegment(), -1);
|
||||
final Expression where = Expression.equals(Drafts._ID, id);
|
||||
contentResolver.delete(Drafts.CONTENT_URI, where.getSQL(), null);
|
||||
}
|
||||
|
||||
private Notification buildNotification(final String title, final String message, final int icon,
|
||||
final Intent content_intent, final Intent delete_intent) {
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
|
||||
@ -275,10 +288,22 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
for (final ParcelableStatusUpdate item : statuses) {
|
||||
mNotificationManager.notify(NOTIFICATION_ID_UPDATE_STATUS,
|
||||
updateUpdateStatusNotificaion(this, builder, 0, item));
|
||||
final ContentValues draftValues = ContentValuesCreator.createStatusDraft(item,
|
||||
ParcelableAccount.getAccountIds(item.accounts));
|
||||
final Uri draftUri = mResolver.insert(Drafts.CONTENT_URI, draftValues);
|
||||
final long draftId = ParseUtils.parseLong(draftUri.getLastPathSegment(), -1);
|
||||
mTwitter.addSendingDraftId(draftId);
|
||||
try {
|
||||
Thread.sleep(15000L);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
final List<SingleResponse<ParcelableStatus>> result = updateStatus(builder, item);
|
||||
boolean failed = false;
|
||||
Exception exception = null;
|
||||
final List<Long> failed_account_ids = ListUtils.fromArray(ParcelableAccount.getAccountIds(item.accounts));
|
||||
|
||||
final Expression where = Expression.equals(Drafts._ID, draftId);
|
||||
final List<Long> failedAccountIds = ListUtils.fromArray(ParcelableAccount.getAccountIds(item.accounts));
|
||||
|
||||
for (final SingleResponse<ParcelableStatus> response : result) {
|
||||
if (response.getData() == null) {
|
||||
@ -287,11 +312,10 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
exception = response.getException();
|
||||
}
|
||||
} else if (response.getData().account_id > 0) {
|
||||
failed_account_ids.remove(response.getData().account_id);
|
||||
failedAccountIds.remove(response.getData().account_id);
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
saveDrafts(item, failed_account_ids);
|
||||
showErrorMessage(R.string.action_updating_status, getString(R.string.no_account_selected), false);
|
||||
} else if (failed) {
|
||||
// If the status is a duplicate, there's no need to save it to
|
||||
@ -300,11 +324,15 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
&& ((TwitterException) exception).getErrorCode() == StatusCodeMessageUtils.STATUS_IS_DUPLICATE) {
|
||||
showErrorMessage(getString(R.string.status_is_duplicate), false);
|
||||
} else {
|
||||
saveDrafts(item, failed_account_ids);
|
||||
final ContentValues accountIdsValues = new ContentValues();
|
||||
accountIdsValues.put(Drafts.ACCOUNT_IDS, ListUtils.toString(failedAccountIds, ',', false));
|
||||
mResolver.update(Drafts.CONTENT_URI, accountIdsValues, where.getSQL(), null);
|
||||
showErrorMessage(R.string.action_updating_status, exception, true);
|
||||
displayTweetNotSendNotification();
|
||||
}
|
||||
} else {
|
||||
showOkMessage(R.string.status_updated, false);
|
||||
mResolver.delete(Drafts.CONTENT_URI, where.getSQL(), null);
|
||||
if (item.media != null) {
|
||||
for (final ParcelableMediaUpdate media : item.media) {
|
||||
final String path = getImagePathFromUri(this, Uri.parse(media.uri));
|
||||
@ -316,6 +344,7 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
}
|
||||
}
|
||||
}
|
||||
mTwitter.removeSendingDraftId(draftId);
|
||||
if (mPreferences.getBoolean(KEY_REFRESH_AFTER_TWEET, false)) {
|
||||
mTwitter.refreshAll();
|
||||
}
|
||||
@ -324,10 +353,7 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
mNotificationManager.cancel(NOTIFICATION_ID_UPDATE_STATUS);
|
||||
}
|
||||
|
||||
private void saveDrafts(final ParcelableStatusUpdate status, final List<Long> account_ids) {
|
||||
final ContentValues values = ContentValuesCreator.createStatusDraft(status,
|
||||
TwidereArrayUtils.fromList(account_ids));
|
||||
mResolver.insert(Drafts.CONTENT_URI, values);
|
||||
private void displayTweetNotSendNotification() {
|
||||
final String title = getString(R.string.status_not_updated);
|
||||
final String message = getString(R.string.status_not_updated_summary);
|
||||
final Intent intent = new Intent(INTENT_ACTION_DRAFTS);
|
||||
@ -396,6 +422,9 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
if (statusUpdate.accounts.length == 0) return Collections.emptyList();
|
||||
|
||||
try {
|
||||
if (true) {
|
||||
throw new UpdateStatusException("Test");
|
||||
}
|
||||
if (mUseUploader && mUploader == null) throw new UploaderNotFoundException(this);
|
||||
if (mUseShortener && mShortener == null) throw new ShortenerNotFoundException(this);
|
||||
|
||||
|
@ -53,6 +53,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
@ -76,6 +77,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import edu.ucdavis.earlybird.ProfilingUtil;
|
||||
import twitter4j.DirectMessage;
|
||||
@ -125,6 +127,8 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
private LongSparseMap<Long> mCreatingRetweetIds = new LongSparseMap<>();
|
||||
private LongSparseMap<Long> mDestroyingStatusIds = new LongSparseMap<>();
|
||||
|
||||
private CopyOnWriteArraySet<Long> mSendingDraftIds = new CopyOnWriteArraySet<>();
|
||||
|
||||
public AsyncTwitterWrapper(final Context context) {
|
||||
mContext = context;
|
||||
final TwidereApplication app = TwidereApplication.getInstance(context);
|
||||
@ -139,33 +143,26 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public void addSendingDraftId(long id) {
|
||||
mSendingDraftIds.add(id);
|
||||
mResolver.notifyChange(Drafts.CONTENT_URI_UNSENT, null);
|
||||
}
|
||||
|
||||
public int addUserListMembersAsync(final long accountId, final long listId, final ParcelableUser... users) {
|
||||
final AddUserListMembersTask task = new AddUserListMembersTask(accountId, listId, users);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
public int cancelRetweetAsync(long account_id, long status_id, long my_retweet_id) {
|
||||
if (my_retweet_id > 0)
|
||||
return destroyStatusAsync(account_id, my_retweet_id);
|
||||
else if (status_id > 0)
|
||||
return destroyStatusAsync(account_id, status_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
public AsyncTaskManager getTaskManager() {
|
||||
return mAsyncTaskManager;
|
||||
}
|
||||
|
||||
public boolean isCreatingFavorite(final long accountId, final long statusId) {
|
||||
return mCreatingFavoriteIds.has(accountId, statusId);
|
||||
}
|
||||
|
||||
public boolean isDestroyingFavorite(final long accountId, final long statusId) {
|
||||
return mDestroyingFavoriteIds.has(accountId, statusId);
|
||||
}
|
||||
|
||||
public boolean isCreatingRetweet(final long accountId, final long statusId) {
|
||||
return mCreatingRetweetIds.has(accountId, statusId);
|
||||
}
|
||||
|
||||
public boolean isDestroyingStatus(final long accountId, final long statusId) {
|
||||
return mDestroyingStatusIds.has(accountId, statusId);
|
||||
public int cancelRetweetAsync(@NonNull final ParcelableStatus status) {
|
||||
return cancelRetweetAsync(status.account_id, status.id, status.my_retweet_id);
|
||||
}
|
||||
|
||||
public void clearNotificationAsync(final int notificationType) {
|
||||
@ -187,11 +184,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int createMuteAsync(final long accountId, final long user_id) {
|
||||
final CreateMuteTask task = new CreateMuteTask(accountId, user_id);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int createFavoriteAsync(final long accountId, final long status_id) {
|
||||
final CreateFavoriteTask task = new CreateFavoriteTask(accountId, status_id);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
@ -207,6 +199,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int createMuteAsync(final long accountId, final long user_id) {
|
||||
final CreateMuteTask task = new CreateMuteTask(accountId, user_id);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int createSavedSearchAsync(final long accountId, final String query) {
|
||||
final CreateSavedSearchTask task = new CreateSavedSearchTask(accountId, query);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
@ -233,29 +230,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
|
||||
public int cancelRetweetAsync(long account_id, long status_id, long my_retweet_id) {
|
||||
if (my_retweet_id > 0)
|
||||
return destroyStatusAsync(account_id, my_retweet_id);
|
||||
else if (status_id > 0)
|
||||
return destroyStatusAsync(account_id, status_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int cancelRetweetAsync(@NonNull final ParcelableStatus status) {
|
||||
return cancelRetweetAsync(status.account_id, status.id, status.my_retweet_id);
|
||||
}
|
||||
|
||||
public int destroyBlockAsync(final long accountId, final long user_id) {
|
||||
final DestroyBlockTask task = new DestroyBlockTask(accountId, user_id);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int destroyMuteAsync(final long accountId, final long user_id) {
|
||||
final DestroyMuteTask task = new DestroyMuteTask(accountId, user_id);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int destroyDirectMessageAsync(final long accountId, final long message_id) {
|
||||
final DestroyDirectMessageTask task = new DestroyDirectMessageTask(accountId, message_id);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
@ -271,6 +250,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int destroyMuteAsync(final long accountId, final long user_id) {
|
||||
final DestroyMuteTask task = new DestroyMuteTask(accountId, user_id);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int destroySavedSearchAsync(final long accountId, final int searchId) {
|
||||
final DestroySavedSearchTask task = new DestroySavedSearchTask(accountId, searchId);
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
@ -291,12 +275,21 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public int getHomeTimelineAsync(final long[] accountIds, final long[] max_ids, final long[] since_ids) {
|
||||
mAsyncTaskManager.cancel(mGetHomeTimelineTaskId);
|
||||
final GetHomeTimelineTask task = new GetHomeTimelineTask(accountIds, max_ids, since_ids);
|
||||
return mGetHomeTimelineTaskId = mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public static AsyncTwitterWrapper getInstance(final Context context) {
|
||||
if (sInstance != null) return sInstance;
|
||||
return sInstance = new AsyncTwitterWrapper(context);
|
||||
}
|
||||
|
||||
public int getLocalTrendsAsync(final long accountId, final int woeid) {
|
||||
mAsyncTaskManager.cancel(mGetLocalTrendsTaskId);
|
||||
final GetLocalTrendsTask task = new GetLocalTrendsTask(accountId, woeid);
|
||||
@ -315,16 +308,38 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mGetReceivedDirectMessagesTaskId = mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public int getSavedSearchesAsync(long[] accountIds) {
|
||||
final GetSavedSearchesTask task = new GetSavedSearchesTask(this);
|
||||
final Long[] ids = new Long[accountIds.length];
|
||||
for (int i = 0, j = accountIds.length; i < j; i++) {
|
||||
ids[i] = accountIds[i];
|
||||
}
|
||||
return mAsyncTaskManager.add(task, true, ids);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public long[] getSendingDraftIds() {
|
||||
return ArrayUtils.toPrimitive(mSendingDraftIds.toArray(new Long[mSendingDraftIds.size()]));
|
||||
}
|
||||
|
||||
public int getSentDirectMessagesAsync(final long[] accountIds, final long[] max_ids, final long[] since_ids) {
|
||||
mAsyncTaskManager.cancel(mGetSentDirectMessagesTaskId);
|
||||
final GetSentDirectMessagesTask task = new GetSentDirectMessagesTask(accountIds, max_ids, since_ids);
|
||||
return mGetSentDirectMessagesTaskId = mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public AsyncTaskManager getTaskManager() {
|
||||
return mAsyncTaskManager;
|
||||
}
|
||||
|
||||
public boolean hasActivatedTask() {
|
||||
return mAsyncTaskManager.hasRunningTask();
|
||||
}
|
||||
|
||||
public boolean isCreatingFavorite(final long accountId, final long statusId) {
|
||||
return mCreatingFavoriteIds.has(accountId, statusId);
|
||||
}
|
||||
|
||||
public boolean isCreatingFriendship(final long accountId, final long userId) {
|
||||
for (final ManagedAsyncTask<?, ?, ?> task : mAsyncTaskManager.getTaskSpecList()) {
|
||||
if (task instanceof CreateFriendshipTask) {
|
||||
@ -338,6 +353,14 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCreatingRetweet(final long accountId, final long statusId) {
|
||||
return mCreatingRetweetIds.has(accountId, statusId);
|
||||
}
|
||||
|
||||
public boolean isDestroyingFavorite(final long accountId, final long statusId) {
|
||||
return mDestroyingFavoriteIds.has(accountId, statusId);
|
||||
}
|
||||
|
||||
public boolean isDestroyingFriendship(final long accountId, final long userId) {
|
||||
for (final ManagedAsyncTask<?, ?, ?> task : mAsyncTaskManager.getTaskSpecList()) {
|
||||
if (task instanceof DestroyFriendshipTask) {
|
||||
@ -351,6 +374,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDestroyingStatus(final long accountId, final long statusId) {
|
||||
return mDestroyingStatusIds.has(accountId, statusId);
|
||||
}
|
||||
|
||||
public boolean isHomeTimelineRefreshing() {
|
||||
return mAsyncTaskManager.hasRunningTasksForTag(TASK_TAG_GET_HOME_TIMELINE)
|
||||
|| mAsyncTaskManager.hasRunningTasksForTag(TASK_TAG_STORE_HOME_TIMELINE);
|
||||
@ -403,6 +430,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return getHomeTimelineAsync(accountIds, null, statusSinceIds);
|
||||
}
|
||||
|
||||
public void removeSendingDraftId(long id) {
|
||||
mSendingDraftIds.remove(id);
|
||||
mResolver.notifyChange(Drafts.CONTENT_URI_UNSENT, null);
|
||||
}
|
||||
|
||||
public void removeUnreadCountsAsync(final int position, final LongSparseArray<Set<Long>> counts) {
|
||||
final RemoveUnreadCountsTask task = new RemoveUnreadCountsTask(position, counts);
|
||||
task.executeTask();
|
||||
@ -482,9 +514,32 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return mAsyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
public static AsyncTwitterWrapper getInstance(final Context context) {
|
||||
if (sInstance != null) return sInstance;
|
||||
return sInstance = new AsyncTwitterWrapper(context);
|
||||
static class GetSavedSearchesTask extends ManagedAsyncTask<Long, Void, SingleResponse<Void>> {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
GetSavedSearchesTask(AsyncTwitterWrapper twitter) {
|
||||
super(twitter.getContext(), twitter.getTaskManager());
|
||||
this.mContext = twitter.getContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SingleResponse<Void> doInBackground(Long... params) {
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
for (long accountId : params) {
|
||||
final Twitter twitter = Utils.getTwitterInstance(mContext, accountId, true);
|
||||
try {
|
||||
final ResponseList<SavedSearch> searches = twitter.getSavedSearches();
|
||||
final ContentValues[] values = ContentValuesCreator.createSavedSearches(searches, accountId);
|
||||
final Expression where = Expression.equals(SavedSearches.ACCOUNT_ID, accountId);
|
||||
cr.delete(SavedSearches.CONTENT_URI, where.getSQL(), null);
|
||||
ContentResolverUtils.bulkInsert(cr, SavedSearches.CONTENT_URI, values);
|
||||
} catch (TwitterException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return SingleResponse.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateProfileBannerImageTask extends ManagedAsyncTask<Void, Void, SingleResponse<ParcelableUser>> {
|
||||
@ -810,49 +865,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
|
||||
}
|
||||
|
||||
class CreateMuteTask extends ManagedAsyncTask<Void, Void, SingleResponse<ParcelableUser>> {
|
||||
|
||||
private final long mAccountId, mUserId;
|
||||
|
||||
public CreateMuteTask(final long accountId, final long userId) {
|
||||
super(mContext, mAsyncTaskManager);
|
||||
this.mAccountId = accountId;
|
||||
this.mUserId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SingleResponse<ParcelableUser> doInBackground(final Void... params) {
|
||||
final Twitter twitter = getTwitterInstance(mContext, mAccountId, false);
|
||||
if (twitter == null) return SingleResponse.getInstance();
|
||||
try {
|
||||
final User user = twitter.createMute(mUserId);
|
||||
Utils.setLastSeen(mContext, user.getId(), -1);
|
||||
final Expression where = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, mAccountId),
|
||||
Expression.equals(Statuses.USER_ID, mUserId));
|
||||
mResolver.delete(Statuses.CONTENT_URI, where.getSQL(), null);
|
||||
|
||||
return SingleResponse.getInstance(new ParcelableUser(user, mAccountId), null);
|
||||
} catch (final TwitterException e) {
|
||||
return SingleResponse.getInstance(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
|
||||
if (result.hasData()) {
|
||||
final String message = mContext.getString(R.string.muted_user,
|
||||
getUserName(mContext, result.getData()));
|
||||
mMessagesManager.showInfoMessage(message, false);
|
||||
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
|
||||
bus.post(new FriendshipUpdatedEvent(result.getData()));
|
||||
} else {
|
||||
mMessagesManager.showErrorMessage(R.string.action_muting, result.getException(), true);
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CreateFavoriteTask extends ManagedAsyncTask<Void, Void, SingleResponse<ParcelableStatus>> {
|
||||
|
||||
private final long account_id, status_id;
|
||||
@ -973,6 +985,15 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
this.user_ids = user_ids;
|
||||
}
|
||||
|
||||
private void deleteCaches(final List<Long> list) {
|
||||
for (final Uri uri : STATUSES_URIS) {
|
||||
bulkDelete(mResolver, uri, Statuses.USER_ID, list, Statuses.ACCOUNT_ID + " = " + account_id, false);
|
||||
}
|
||||
// I bet you don't want to see these users in your auto complete list.
|
||||
//TODO insert to blocked users data
|
||||
// bulkDelete(mResolver, CachedUsers.CONTENT_URI, CachedUsers.USER_ID, list, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListResponse<Long> doInBackground(final Void... params) {
|
||||
final List<Long> blocked_users = new ArrayList<>();
|
||||
@ -1008,14 +1029,50 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
private void deleteCaches(final List<Long> list) {
|
||||
for (final Uri uri : STATUSES_URIS) {
|
||||
bulkDelete(mResolver, uri, Statuses.USER_ID, list, Statuses.ACCOUNT_ID + " = " + account_id, false);
|
||||
}
|
||||
// I bet you don't want to see these users in your auto complete list.
|
||||
//TODO insert to blocked users data
|
||||
// bulkDelete(mResolver, CachedUsers.CONTENT_URI, CachedUsers.USER_ID, list, null, false);
|
||||
|
||||
}
|
||||
|
||||
class CreateMuteTask extends ManagedAsyncTask<Void, Void, SingleResponse<ParcelableUser>> {
|
||||
|
||||
private final long mAccountId, mUserId;
|
||||
|
||||
public CreateMuteTask(final long accountId, final long userId) {
|
||||
super(mContext, mAsyncTaskManager);
|
||||
this.mAccountId = accountId;
|
||||
this.mUserId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SingleResponse<ParcelableUser> doInBackground(final Void... params) {
|
||||
final Twitter twitter = getTwitterInstance(mContext, mAccountId, false);
|
||||
if (twitter == null) return SingleResponse.getInstance();
|
||||
try {
|
||||
final User user = twitter.createMute(mUserId);
|
||||
Utils.setLastSeen(mContext, user.getId(), -1);
|
||||
final Expression where = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, mAccountId),
|
||||
Expression.equals(Statuses.USER_ID, mUserId));
|
||||
mResolver.delete(Statuses.CONTENT_URI, where.getSQL(), null);
|
||||
|
||||
return SingleResponse.getInstance(new ParcelableUser(user, mAccountId), null);
|
||||
} catch (final TwitterException e) {
|
||||
return SingleResponse.getInstance(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
|
||||
if (result.hasData()) {
|
||||
final String message = mContext.getString(R.string.muted_user,
|
||||
getUserName(mContext, result.getData()));
|
||||
mMessagesManager.showInfoMessage(message, false);
|
||||
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
|
||||
bus.post(new FriendshipUpdatedEvent(result.getData()));
|
||||
} else {
|
||||
mMessagesManager.showErrorMessage(R.string.action_muting, result.getException(), true);
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CreateSavedSearchTask extends ManagedAsyncTask<Void, Void, SingleResponse<SavedSearch>> {
|
||||
@ -1287,47 +1344,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
|
||||
}
|
||||
|
||||
class DestroyMuteTask extends ManagedAsyncTask<Void, Void, SingleResponse<ParcelableUser>> {
|
||||
|
||||
private final long mAccountId;
|
||||
private final long mUserId;
|
||||
|
||||
public DestroyMuteTask(final long accountId, final long userId) {
|
||||
super(mContext, mAsyncTaskManager);
|
||||
mAccountId = accountId;
|
||||
mUserId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SingleResponse<ParcelableUser> doInBackground(final Void... params) {
|
||||
final Twitter twitter = getTwitterInstance(mContext, mAccountId, false);
|
||||
if (twitter == null) return SingleResponse.getInstance();
|
||||
try {
|
||||
final User user = twitter.destroyMute(mUserId);
|
||||
Utils.setLastSeen(mContext, user.getId(), -1);
|
||||
return SingleResponse.getInstance(new ParcelableUser(user, mAccountId), null);
|
||||
} catch (final TwitterException e) {
|
||||
return SingleResponse.getInstance(null, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
|
||||
if (result.hasData()) {
|
||||
final String message = mContext.getString(R.string.unmuted_user,
|
||||
getUserName(mContext, result.getData()));
|
||||
mMessagesManager.showInfoMessage(message, false);
|
||||
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
|
||||
bus.post(new FriendshipUpdatedEvent(result.getData()));
|
||||
} else {
|
||||
mMessagesManager.showErrorMessage(R.string.action_unmuting, result.getException(), true);
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DestroyDirectMessageTask extends ManagedAsyncTask<Void, Void, SingleResponse<DirectMessage>> {
|
||||
|
||||
private final long message_id;
|
||||
@ -1340,6 +1356,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
this.message_id = message_id;
|
||||
}
|
||||
|
||||
private void deleteMessages(final long message_id) {
|
||||
final String where = DirectMessages.MESSAGE_ID + " = " + message_id;
|
||||
mResolver.delete(DirectMessages.Inbox.CONTENT_URI, where, null);
|
||||
mResolver.delete(DirectMessages.Outbox.CONTENT_URI, where, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SingleResponse<DirectMessage> doInBackground(final Void... args) {
|
||||
final Twitter twitter = getTwitterInstance(mContext, account_id, false);
|
||||
@ -1356,6 +1378,13 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMessageNotFound(final Exception e) {
|
||||
if (!(e instanceof TwitterException)) return false;
|
||||
final TwitterException te = (TwitterException) e;
|
||||
return te.getErrorCode() == StatusCodeMessageUtils.PAGE_NOT_FOUND
|
||||
|| te.getStatusCode() == HttpResponseCode.NOT_FOUND;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final SingleResponse<DirectMessage> result) {
|
||||
super.onPostExecute(result);
|
||||
@ -1367,18 +1396,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteMessages(final long message_id) {
|
||||
final String where = DirectMessages.MESSAGE_ID + " = " + message_id;
|
||||
mResolver.delete(DirectMessages.Inbox.CONTENT_URI, where, null);
|
||||
mResolver.delete(DirectMessages.Outbox.CONTENT_URI, where, null);
|
||||
}
|
||||
|
||||
private boolean isMessageNotFound(final Exception e) {
|
||||
if (!(e instanceof TwitterException)) return false;
|
||||
final TwitterException te = (TwitterException) e;
|
||||
return te.getErrorCode() == StatusCodeMessageUtils.PAGE_NOT_FOUND
|
||||
|| te.getStatusCode() == HttpResponseCode.NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
class DestroyFavoriteTask extends ManagedAsyncTask<Void, Void, SingleResponse<ParcelableStatus>> {
|
||||
@ -1494,6 +1512,47 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
|
||||
}
|
||||
|
||||
class DestroyMuteTask extends ManagedAsyncTask<Void, Void, SingleResponse<ParcelableUser>> {
|
||||
|
||||
private final long mAccountId;
|
||||
private final long mUserId;
|
||||
|
||||
public DestroyMuteTask(final long accountId, final long userId) {
|
||||
super(mContext, mAsyncTaskManager);
|
||||
mAccountId = accountId;
|
||||
mUserId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SingleResponse<ParcelableUser> doInBackground(final Void... params) {
|
||||
final Twitter twitter = getTwitterInstance(mContext, mAccountId, false);
|
||||
if (twitter == null) return SingleResponse.getInstance();
|
||||
try {
|
||||
final User user = twitter.destroyMute(mUserId);
|
||||
Utils.setLastSeen(mContext, user.getId(), -1);
|
||||
return SingleResponse.getInstance(new ParcelableUser(user, mAccountId), null);
|
||||
} catch (final TwitterException e) {
|
||||
return SingleResponse.getInstance(null, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
|
||||
if (result.hasData()) {
|
||||
final String message = mContext.getString(R.string.unmuted_user,
|
||||
getUserName(mContext, result.getData()));
|
||||
mMessagesManager.showInfoMessage(message, false);
|
||||
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
|
||||
bus.post(new FriendshipUpdatedEvent(result.getData()));
|
||||
} else {
|
||||
mMessagesManager.showErrorMessage(R.string.action_unmuting, result.getException(), true);
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DestroySavedSearchTask extends ManagedAsyncTask<Void, Void, SingleResponse<SavedSearch>> {
|
||||
|
||||
private final long mAccountId;
|
||||
@ -1696,6 +1755,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
public abstract ResponseList<DirectMessage> getDirectMessages(Twitter twitter, Paging paging)
|
||||
throws TwitterException;
|
||||
|
||||
final boolean isMaxIdsValid() {
|
||||
return max_ids != null && max_ids.length == account_ids.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<MessageListResponse> doInBackground(final Void... params) {
|
||||
|
||||
@ -1735,6 +1798,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
|
||||
}
|
||||
|
||||
final boolean isSinceIdsValid() {
|
||||
return since_ids != null && since_ids.length == account_ids.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final List<MessageListResponse> result) {
|
||||
super.onPostExecute(result);
|
||||
@ -1746,13 +1813,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
final boolean isMaxIdsValid() {
|
||||
return max_ids != null && max_ids.length == account_ids.length;
|
||||
}
|
||||
|
||||
final boolean isSinceIdsValid() {
|
||||
return since_ids != null && since_ids.length == account_ids.length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1917,6 +1977,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
public abstract ResponseList<twitter4j.Status> getStatuses(Twitter twitter, Paging paging)
|
||||
throws TwitterException;
|
||||
|
||||
final boolean isMaxIdsValid() {
|
||||
return mMaxIds != null && mMaxIds.length == mAccountIds.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<StatusListResponse> doInBackground(final Void... params) {
|
||||
|
||||
@ -1958,14 +2022,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
final boolean isMaxIdsValid() {
|
||||
return mMaxIds != null && mMaxIds.length == mAccountIds.length;
|
||||
}
|
||||
|
||||
final boolean isSinceIdsValid() {
|
||||
return mSinceIds != null && mSinceIds.length == mAccountIds.length;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
abstract class GetTrendsTask extends ManagedAsyncTask<Void, Void, ListResponse<Trends>> {
|
||||
@ -2185,6 +2246,8 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
this.notify = notify;
|
||||
}
|
||||
|
||||
abstract boolean isOutgoing();
|
||||
|
||||
@Override
|
||||
protected SingleResponse<Boolean> doInBackground(final Void... args) {
|
||||
|
||||
@ -2221,7 +2284,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return SingleResponse.getInstance(succeed);
|
||||
}
|
||||
|
||||
abstract boolean isOutgoing();
|
||||
|
||||
}
|
||||
|
||||
@ -2265,43 +2327,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
|
||||
}
|
||||
|
||||
public int getSavedSearchesAsync(long[] accountIds) {
|
||||
final GetSavedSearchesTask task = new GetSavedSearchesTask(this);
|
||||
final Long[] ids = new Long[accountIds.length];
|
||||
for (int i = 0, j = accountIds.length; i < j; i++) {
|
||||
ids[i] = accountIds[i];
|
||||
}
|
||||
return mAsyncTaskManager.add(task, true, ids);
|
||||
}
|
||||
|
||||
static class GetSavedSearchesTask extends ManagedAsyncTask<Long, Void, SingleResponse<Void>> {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
GetSavedSearchesTask(AsyncTwitterWrapper twitter) {
|
||||
super(twitter.getContext(), twitter.getTaskManager());
|
||||
this.mContext = twitter.getContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SingleResponse<Void> doInBackground(Long... params) {
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
for (long accountId : params) {
|
||||
final Twitter twitter = Utils.getTwitterInstance(mContext, accountId, true);
|
||||
try {
|
||||
final ResponseList<SavedSearch> searches = twitter.getSavedSearches();
|
||||
final ContentValues[] values = ContentValuesCreator.createSavedSearches(searches, accountId);
|
||||
final Expression where = Expression.equals(SavedSearches.ACCOUNT_ID, accountId);
|
||||
cr.delete(SavedSearches.CONTENT_URI, where.getSQL(), null);
|
||||
ContentResolverUtils.bulkInsert(cr, SavedSearches.CONTENT_URI, values);
|
||||
} catch (TwitterException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return SingleResponse.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
class StoreReceivedDirectMessagesTask extends StoreDirectMessagesTask {
|
||||
|
||||
public StoreReceivedDirectMessagesTask(final List<MessageListResponse> result, final boolean notify) {
|
||||
|
@ -110,7 +110,6 @@ import org.apache.http.NameValuePair;
|
||||
import org.json.JSONException;
|
||||
import org.mariotaku.jsonserializer.JSONSerializer;
|
||||
import org.mariotaku.menucomponent.internal.menu.MenuUtils;
|
||||
import org.mariotaku.menucomponent.widget.PopupMenu;
|
||||
import org.mariotaku.querybuilder.AllColumns;
|
||||
import org.mariotaku.querybuilder.Columns;
|
||||
import org.mariotaku.querybuilder.Columns.Column;
|
||||
@ -348,6 +347,8 @@ public final class Utils implements Constants, TwitterConstants {
|
||||
VIRTUAL_TABLE_ID_CACHED_USERS_WITH_RELATIONSHIP);
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, CachedUsers.CONTENT_PATH_WITH_SCORE + "/#",
|
||||
VIRTUAL_TABLE_ID_CACHED_USERS_WITH_SCORE);
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Drafts.CONTENT_PATH_UNSENT,
|
||||
VIRTUAL_TABLE_ID_DRAFTS_UNSENT);
|
||||
|
||||
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS, null, LINK_ID_STATUS);
|
||||
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER, null, LINK_ID_USER);
|
||||
|
@ -21,10 +21,13 @@ package org.mariotaku.twidere.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.RecyclerView.Adapter;
|
||||
import android.support.v7.widget.RecyclerView.ItemDecoration;
|
||||
import android.support.v7.widget.RecyclerView.Recycler;
|
||||
import android.support.v7.widget.RecyclerView.State;
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
@ -34,10 +37,8 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.StackView;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.ArrayAdapter;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.util.ImageLoaderWrapper;
|
||||
@ -47,8 +48,9 @@ import org.mariotaku.twidere.view.iface.IColorLabelView.Helper;
|
||||
* Created by mariotaku on 14/12/8.
|
||||
*/
|
||||
public class ComposeSelectAccountButton extends ViewGroup {
|
||||
private final AccountIconsStackAdapter mAccountIconsAdapter;
|
||||
private final AccountIconsAdapter mAccountIconsAdapter;
|
||||
private final Helper mColorLabelHelper;
|
||||
private final InternalRecyclerView recyclerView;
|
||||
|
||||
public ComposeSelectAccountButton(Context context) {
|
||||
this(context, null);
|
||||
@ -62,19 +64,27 @@ public class ComposeSelectAccountButton extends ViewGroup {
|
||||
super(context, attrs, defStyle);
|
||||
mColorLabelHelper = new Helper(this, context, attrs, defStyle);
|
||||
mColorLabelHelper.setIgnorePaddings(true);
|
||||
mAccountIconsAdapter = new AccountIconsStackAdapter(context);
|
||||
final StackView stackView = new InternalStackView(context);
|
||||
stackView.setAdapter(mAccountIconsAdapter);
|
||||
addView(stackView);
|
||||
// final RecyclerView recyclerView = new InternalRecyclerView(context);
|
||||
// final LinearLayoutManager linearLayoutManager = new MyLinearLayoutManager(context);
|
||||
// linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
|
||||
// linearLayoutManager.setStackFromEnd(true);
|
||||
//// linearLayoutManager.setReverseLayout(true);
|
||||
// recyclerView.setLayoutManager(linearLayoutManager);
|
||||
// recyclerView.setAdapter(mAccountIconsAdapter);
|
||||
// ViewCompat.setOverScrollMode(recyclerView, ViewCompat.OVER_SCROLL_NEVER);
|
||||
// addView(recyclerView);
|
||||
mAccountIconsAdapter = new AccountIconsAdapter(context);
|
||||
recyclerView = new InternalRecyclerView(context);
|
||||
final LinearLayoutManager linearLayoutManager = new MyLinearLayoutManager(context);
|
||||
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
|
||||
recyclerView.setLayoutManager(linearLayoutManager);
|
||||
recyclerView.setAdapter(mAccountIconsAdapter);
|
||||
recyclerView.addItemDecoration(new ItemDecoration() {
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
|
||||
final int pos = parent.getChildPosition(view);
|
||||
if (pos == 0) {
|
||||
outRect.left = 0;
|
||||
} else {
|
||||
final int count = state.getItemCount();
|
||||
outRect.left = -(parent.getHeight() - (parent.getWidth() - parent.getHeight()) / (count - 1));
|
||||
}
|
||||
}
|
||||
});
|
||||
ViewCompat.setOverScrollMode(recyclerView, ViewCompat.OVER_SCROLL_NEVER);
|
||||
addView(recyclerView);
|
||||
mAccountIconsAdapter.setSelectedAccounts(ParcelableAccount.getAccounts(context, false, false));
|
||||
}
|
||||
|
||||
public void setSelectedAccounts(long[] accountIds) {
|
||||
@ -109,7 +119,7 @@ public class ComposeSelectAccountButton extends ViewGroup {
|
||||
if (maxWidth == 0) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
} else {
|
||||
setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), heightMeasureSpec);
|
||||
setMeasuredDimension(maxWidth, heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +165,7 @@ public class ComposeSelectAccountButton extends ViewGroup {
|
||||
|
||||
@Override
|
||||
public AccountIconViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final View view = mInflater.inflate(R.layout.adapter_item_compose_account, parent, false);
|
||||
final View view = mInflater.inflate(R.layout.adapter_item_compose_account2, parent, false);
|
||||
return new AccountIconViewHolder(view);
|
||||
}
|
||||
|
||||
@ -170,56 +180,11 @@ public class ComposeSelectAccountButton extends ViewGroup {
|
||||
}
|
||||
|
||||
public void setSelectedAccounts(ParcelableAccount[] accounts) {
|
||||
if (accounts != null) {
|
||||
// ArrayUtils.reverse(accounts);
|
||||
}
|
||||
mAccounts = accounts;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AccountIconsStackAdapter extends ArrayAdapter<ParcelableAccount> {
|
||||
private final Context mContext;
|
||||
private final LayoutInflater mInflater;
|
||||
private final ImageLoaderWrapper mImageLoader;
|
||||
|
||||
public AccountIconsStackAdapter(Context context) {
|
||||
super(context, R.layout.adapter_item_compose_account);
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final View view = super.getView(position, convertView, parent);
|
||||
final ParcelableAccount account = getItem(position);
|
||||
final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
|
||||
mImageLoader.displayProfileImage(iconView, account.profile_image_url);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
public void setSelectedAccounts(ParcelableAccount[] accounts) {
|
||||
clear();
|
||||
if (accounts != null) {
|
||||
addAll(accounts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class InternalStackView extends StackView {
|
||||
private InternalStackView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InternalRecyclerView extends RecyclerView {
|
||||
public InternalRecyclerView(Context context) {
|
||||
super(context);
|
||||
@ -240,56 +205,15 @@ public class ComposeSelectAccountButton extends ViewGroup {
|
||||
}
|
||||
|
||||
private static class MyLinearLayoutManager extends LinearLayoutManager {
|
||||
private int mWidth, mHeight;
|
||||
|
||||
public MyLinearLayoutManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
private int findChildIndex(View view) {
|
||||
for (int i = 0, j = getChildCount(); i < j; i++) {
|
||||
if (getChildAt(i) == view) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
|
||||
final RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
final int contentWidth = mWidth - getPaddingLeft() - getPaddingRight();
|
||||
final int contentHeight = mHeight - getPaddingTop() - getPaddingBottom();
|
||||
final int itemCount = getItemCount();
|
||||
final int firstVisibleItem = findFirstVisibleItemPosition();
|
||||
final int idx = findChildIndex(child);
|
||||
if (firstVisibleItem < 1 && idx == 0) {
|
||||
// when firstVisibleItem is 0 or -1, assume view with idx == 0 is first view
|
||||
if (itemCount == 1) {
|
||||
layoutParams.leftMargin = (contentWidth - contentHeight) / 2 - child.getPaddingLeft() - child.getPaddingRight();
|
||||
} else {
|
||||
layoutParams.leftMargin = 0;
|
||||
}
|
||||
} else {
|
||||
layoutParams.leftMargin = -Math.min((contentHeight * itemCount - contentWidth)
|
||||
/ (itemCount - 1) + child.getPaddingLeft() + child.getPaddingRight(), contentHeight);
|
||||
}
|
||||
super.measureChildWithMargins(child, widthUsed, heightUsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) {
|
||||
final int height = MeasureSpec.getSize(heightSpec), width;
|
||||
final int itemCount = getItemCount();
|
||||
if (itemCount > 1) {
|
||||
width = Math.round(height * 1.5f);
|
||||
} else if (itemCount > 0 && state.getItemCount() > 0) {
|
||||
final View firstChild = recycler.getViewForPosition(0);
|
||||
width = height + firstChild.getPaddingLeft() + firstChild.getPaddingRight();
|
||||
} else {
|
||||
width = height;
|
||||
}
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
super.onMeasure(recycler, state, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightSpec);
|
||||
final int height = MeasureSpec.getSize(heightSpec), width = Math.round(height * 1.25f);
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
android:minHeight="@dimen/compose_min_height"
|
||||
android:minWidth="@dimen/compose_min_width"
|
||||
android:orientation="vertical"
|
||||
android:showDividers="none">
|
||||
android:showDividers="middle">
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
|
@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/compose_actionbar"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:actionBarItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="8dp">
|
||||
|
||||
<org.mariotaku.twidere.view.ActionBarHomeAsUpIndicator
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="4dp">
|
||||
|
||||
<org.mariotaku.twidere.view.ActionBarTitleView
|
||||
android:id="@+id/actionbar_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<org.mariotaku.twidere.view.ActionBarSubtitleView
|
||||
android:id="@+id/actionbar_subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/quote_protected_status_notice"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/actionbar_progress_indeterminate"
|
||||
style="?android:progressBarStyle"
|
||||
android:layout_width="?android:actionBarSize"
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="0"
|
||||
android:indeterminateOnly="true"
|
||||
android:padding="2dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<!--<include layout="@layout/action_item_compose_account"/>-->
|
||||
|
||||
</LinearLayout>
|
@ -31,6 +31,12 @@
|
||||
android:orientation="horizontal"
|
||||
android:showDividers="middle">
|
||||
|
||||
<!--<org.mariotaku.twidere.view.ComposeSelectAccountButton-->
|
||||
<!--android:layout_width="wrap_content"-->
|
||||
<!--android:layout_height="match_parent"-->
|
||||
<!--android:layout_weight="0"-->
|
||||
<!--android:padding="@dimen/element_spacing_small"/>-->
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/bottom_menu_container"
|
||||
android:layout_width="0dp"
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
<org.mariotaku.twidere.view.SquareShapedImageView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@android:id/icon"
|
||||
style="?profileImageStyle"
|
||||
tools:layout_height="48dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
app:sivBorder="true"
|
||||
app:sivBorderWidth="1.5dp"/>
|
@ -21,15 +21,15 @@
|
||||
<org.mariotaku.twidere.view.ColorLabelLinearLayout
|
||||
android:id="@+id/content"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:activatedBackgroundIndicator"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/element_spacing_small"
|
||||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="@dimen/element_spacing_normal"
|
||||
android:paddingTop="@dimen/element_spacing_small"
|
||||
android:padding="@dimen/element_spacing_normal"
|
||||
app:ignorePadding="true"
|
||||
tools:context=".adapter.DraftsAdapter">
|
||||
|
||||
<org.mariotaku.twidere.view.ImagePreviewContainer
|
||||
@ -84,7 +84,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
style="?android:borderlessButtonStyle"
|
Loading…
x
Reference in New Issue
Block a user