improved link handler

This commit is contained in:
Mariotaku Lee 2016-04-02 21:37:18 +08:00
parent afc8f0ac04
commit b8c7cdb11d
19 changed files with 223 additions and 70 deletions

View File

@ -112,6 +112,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
String AUTHORITY_PROFILE_EDITOR = "profile_editor";
String QUERY_PARAM_ACCOUNT_KEY = "account_key";
String QUERY_PARAM_ACCOUNT_HOST = "account_host";
String QUERY_PARAM_ACCOUNT_NAME = "account_name";
String QUERY_PARAM_STATUS_ID = "status_id";
String QUERY_PARAM_USER_KEY = "user_key";

View File

@ -93,6 +93,7 @@ public interface IntentConstants {
String EXTRA_URI_ORIG = "uri_orig";
String EXTRA_MENTIONS = "mentions";
String EXTRA_ACCOUNT_KEY = "account_key";
String EXTRA_ACCOUNT_HOST = "account_host";
String EXTRA_ACCOUNT_KEYS = "account_keys";
String EXTRA_PAGE = "page";
String EXTRA_DATA = "data";
@ -204,9 +205,10 @@ public interface IntentConstants {
String EXTRA_NEW_DOCUMENT = "new_document";
String EXTRA_MAKE_GAP = "make_gap";
String EXTRA_QUOTE_ORIGINAL_STATUS = "quote_original_status";
String EXTRA_KEY = "key";
String EXTRA_CARD = "card";
String EXTRA_IS_POSSIBLY_SENSITIVE = "is_possibly_sensitive";
String EXTRA_REFERRAL = "referral";
String EXTRA_LOADING_MORE = "loading_more";
String EXTRA_START_INTENT = "start_intent";
String EXTRA_SELECT_ONLY_ITEM = "select_only_item";
}

View File

@ -136,7 +136,8 @@ public class ParcelableCredentials extends ParcelableAccount implements Parcelab
ParcelableCredentialsParcelablePlease.writeToParcel(this, dest, flags);
}
@IntDef({AuthType.OAUTH, AuthType.XAUTH, AuthType.BASIC, AuthType.TWIP_O_MODE})
@IntDef({AuthType.OAUTH, AuthType.XAUTH, AuthType.BASIC, AuthType.TWIP_O_MODE,
AuthType.OAUTH2})
@Retention(RetentionPolicy.SOURCE)
public @interface AuthType {
@ -144,5 +145,6 @@ public class ParcelableCredentials extends ParcelableAccount implements Parcelab
int XAUTH = 1;
int BASIC = 2;
int TWIP_O_MODE = 3;
int OAUTH2 = 4;
}
}

View File

@ -21,13 +21,17 @@ import java.util.List;
@ParcelablePlease
public class UserKey implements Comparable<UserKey>, Parcelable {
public static final UserKey SELF_REFERENCE = new UserKey("#self#", "#self#");
public static final Creator<UserKey> CREATOR = new Creator<UserKey>() {
@Override
public UserKey createFromParcel(Parcel source) {
UserKey target = new UserKey();
UserKeyParcelablePlease.readFromParcel(target, source);
return target;
}
@Override
public UserKey[] newArray(int size) {
return new UserKey[size];
}
@ -51,6 +55,10 @@ public class UserKey implements Comparable<UserKey>, Parcelable {
}
public boolean isSelfReference() {
return equals(SELF_REFERENCE);
}
@NonNull
public String getId() {
return id;

View File

@ -388,7 +388,7 @@
android:label="@string/import_settings"
android:theme="@style/Theme.Twidere.NoDisplay"/>
<activity
android:name=".activity.TwitterLinkHandlerActivity"
android:name=".activity.WebLinkHandlerActivity"
android:excludeFromRecents="true"
android:taskAffinity=":twidere_twitter_link_handler"
android:theme="@style/Theme.Twidere.NoDisplay">
@ -399,6 +399,7 @@
<data android:host="twitter.com"/>
<data android:host="www.twitter.com"/>
<data android:host="mobile.twitter.com"/>
<data android:host="fanfou.com"/>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>

View File

@ -28,6 +28,7 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
@ -36,6 +37,7 @@ import android.widget.ListView;
import android.widget.Toast;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.AccountsAdapter;
@ -43,6 +45,9 @@ import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import java.util.ArrayList;
import java.util.List;
public class AccountSelectorActivity extends BaseActivity implements
LoaderCallbacks<Cursor>, OnClickListener, OnItemClickListener {
@ -98,16 +103,28 @@ public class AccountSelectorActivity extends BaseActivity implements
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
final List<Expression> conditions = new ArrayList<>();
final List<String> conditionArgs = new ArrayList<>();
if (isOAuthOnly()) {
conditions.add(Expression.equalsArgs(Accounts.AUTH_TYPE));
conditionArgs.add(String.valueOf(ParcelableCredentials.AuthType.OAUTH));
}
final String accountHost = getAccountHost();
if (!TextUtils.isEmpty(accountHost)) {
conditions.add(Expression.likeRaw(new Columns.Column(Accounts.ACCOUNT_KEY), "'%@'||?"));
conditionArgs.add(accountHost);
}
final String where;
final String[] whereArgs;
if (isOAuthOnly()) {
where = Expression.equalsArgs(Accounts.AUTH_TYPE).getSQL();
whereArgs = new String[]{String.valueOf(ParcelableCredentials.AuthType.OAUTH)};
} else {
if (conditions.isEmpty()) {
where = null;
whereArgs = null;
} else {
where = Expression.and(conditions.toArray(new Expression[conditions.size()])).getSQL();
whereArgs = conditionArgs.toArray(new String[conditionArgs.size()]);
}
return new CursorLoader(this, Accounts.CONTENT_URI, Accounts.COLUMNS, where, whereArgs, null);
return new CursorLoader(this, Accounts.CONTENT_URI, Accounts.COLUMNS, where, whereArgs,
Accounts.SORT_POSITION);
}
@Override
@ -119,6 +136,9 @@ public class AccountSelectorActivity extends BaseActivity implements
mListView.setItemChecked(i, ArrayUtils.contains(activatedIds, mAdapter.getItemId(i)));
}
}
if (mAdapter.getCount() == 1 && isSingleSelection()) {
selectSingleAccount(0);
}
}
@Override
@ -128,10 +148,21 @@ public class AccountSelectorActivity extends BaseActivity implements
@Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
final Intent data = new Intent();
selectSingleAccount(position);
}
public void selectSingleAccount(int position) {
final ParcelableAccount account = mAdapter.getAccount(position);
final Intent data = new Intent();
data.putExtra(EXTRA_ID, account.account_key.getId());
data.putExtra(EXTRA_KEY, account.account_key);
data.putExtra(EXTRA_ACCOUNT_KEY, account.account_key);
final Intent startIntent = getStartIntent();
if (startIntent != null) {
startIntent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key);
startActivity(startIntent);
}
setResult(RESULT_OK, data);
finish();
}
@ -185,6 +216,11 @@ public class AccountSelectorActivity extends BaseActivity implements
return intent.getBooleanExtra(EXTRA_OAUTH_ONLY, false);
}
private String getAccountHost() {
final Intent intent = getIntent();
return intent.getStringExtra(EXTRA_ACCOUNT_HOST);
}
private boolean isSelectNoneAllowed() {
final Intent intent = getIntent();
return intent.getBooleanExtra(EXTRA_ALLOW_SELECT_NONE, false);
@ -195,4 +231,14 @@ public class AccountSelectorActivity extends BaseActivity implements
return intent.getBooleanExtra(EXTRA_SINGLE_SELECTION, false);
}
private boolean shouldSelectOnlyItem() {
final Intent intent = getIntent();
return intent.getBooleanExtra(EXTRA_SELECT_ONLY_ITEM, false);
}
private Intent getStartIntent() {
final Intent intent = getIntent();
return intent.getParcelableExtra(EXTRA_START_INTENT);
}
}

View File

@ -198,13 +198,14 @@ public class BaseActivity extends ATEActivity implements Constants, IExtendedAct
final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
if (adapter != null && adapter.isEnabled()) {
final PendingIntent intent = PendingIntent.getActivity(this, 0, new Intent(this,
TwitterLinkHandlerActivity.class), 0);
WebLinkHandlerActivity.class), 0);
final IntentFilter intentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
intentFilter.addDataScheme("http");
intentFilter.addDataScheme("https");
intentFilter.addDataAuthority("twitter.com", null);
intentFilter.addDataAuthority("www.twitter.com", null);
intentFilter.addDataAuthority("mobile.twitter.com", null);
intentFilter.addDataAuthority("fanfou.com", null);
try {
adapter.enableForegroundDispatch(this, intent, new IntentFilter[]{intentFilter}, null);
} catch (SecurityException e) {

View File

@ -167,7 +167,23 @@ public class LinkHandlerActivity extends BaseActivity implements SystemWindowsIn
final Uri uri = intent.getData();
final int linkId = matchLinkId(uri);
intent.setExtrasClassLoader(getClassLoader());
final Fragment fragment = createFragmentForIntent(this, linkId, intent);
final Fragment fragment;
try {
fragment = createFragmentForIntent(this, linkId, intent);
} catch (Utils.NoAccountException e) {
super.onCreate(savedInstanceState);
Intent selectIntent = new Intent(this, AccountSelectorActivity.class);
String accountHost = intent.getStringExtra(EXTRA_ACCOUNT_HOST);
if (accountHost == null) {
accountHost = uri.getQueryParameter(QUERY_PARAM_ACCOUNT_HOST);
}
selectIntent.putExtra(EXTRA_SINGLE_SELECTION, true);
selectIntent.putExtra(EXTRA_ACCOUNT_HOST, accountHost);
selectIntent.putExtra(EXTRA_START_INTENT, intent);
startActivity(selectIntent);
finish();
return;
}
if (fragment instanceof IToolBarSupportFragment) {
if (!((IToolBarSupportFragment) fragment).setupWindow(this)) {
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);

View File

@ -14,15 +14,14 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.BugReporter;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.Utils;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.getDefaultAccountKey;
public class TwitterLinkHandlerActivity extends Activity implements Constants {
public class WebLinkHandlerActivity extends Activity implements Constants {
@SuppressWarnings("SpellCheckingInspection")
public static final String[] TWITTER_RESERVED_PATHS = {"about", "account", "accounts", "activity", "all",
@ -37,6 +36,11 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
"statistics", "terms", "tos", "translate", "trends", "tweetbutton", "twttr", "update_discoverability",
"users", "welcome", "who_to_follow", "widgets", "zendesk_auth", "media_signup"};
@SuppressWarnings("SpellCheckingInspection")
public static final String[] FANFOU_RESERVED_PATHS = {"home", "privatemsg", "finder", "browse",
"search", "settings", "message", "mentions", "favorites", "friends", "followers",
"sharer", "photo", "album", "paipai", "q", "userview", "dialogue"};
private static final String AUTHORITY_TWITTER_COM = "twitter.com";
@ -58,13 +62,28 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
super.onCreate(savedInstanceState);
final PackageManager packageManager = getPackageManager();
final Intent intent = getIntent();
final Uri data = intent.getData();
if (data == null) {
final Uri uri = intent.getData();
if (uri == null || uri.getHost() == null) {
finish();
return;
}
final Uri uri = regulateTwitterUri(data);
final Pair<Intent, Boolean> handled = getHandledIntent(uri);
final Pair<Intent, Boolean> handled;
switch (uri.getHost()) {
case "twitter.com":
case "www.twitter.com":
case "mobile.twitter.com": {
handled = handleTwitterLink(regulateTwitterUri(uri));
break;
}
case "fanfou.com": {
handled = handleFanfouLink(uri);
break;
}
default: {
handled = Pair.create(null, false);
break;
}
}
if (handled.first != null) {
startActivity(handled.first);
} else {
@ -95,7 +114,39 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
}
@NonNull
private Pair<Intent, Boolean> getHandledIntent(final Uri uri) {
private Pair<Intent, Boolean> handleFanfouLink(final Uri uri) {
final List<String> pathSegments = uri.getPathSegments();
if (pathSegments.size() > 0) {
switch (pathSegments.get(0)) {
case "statuses": {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_STATUS);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM);
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments.get(1));
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
default: {
if (!ArrayUtils.contains(FANFOU_RESERVED_PATHS, pathSegments.get(0))) {
if (pathSegments.size() == 1) {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM);
final UserKey userKey = new UserKey(pathSegments.get(0), USER_TYPE_FANFOU_COM);
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, userKey.toString());
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
}
return Pair.create(null, false);
}
}
}
return Pair.create(null, false);
}
@NonNull
private Pair<Intent, Boolean> handleTwitterLink(final Uri uri) {
final List<String> pathSegments = uri.getPathSegments();
if (pathSegments.size() > 0) {
switch (pathSegments.get(0)) {
@ -103,7 +154,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
return getIUriIntent(uri, pathSegments);
}
case "intent": {
return getIntentUriIntent(uri, pathSegments);
return getTwitterIntentUriIntent(uri, pathSegments);
}
case "share": {
final Intent handledIntent = new Intent(this, ComposeActivity.class);
@ -117,6 +168,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_SEARCH);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_QUERY, uri.getQueryParameter("q"));
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
@ -124,21 +176,21 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_FRIENDS);
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, String.valueOf(getDefaultAccountKey(this)));
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString());
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
case "followers": {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_FOLLOWERS);
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, String.valueOf(getDefaultAccountKey(this)));
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString());
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
case "favorites": {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_FAVORITES);
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, String.valueOf(getDefaultAccountKey(this)));
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString());
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
default: {
@ -167,6 +219,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_FRIENDS);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
@ -174,6 +227,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_FOLLOWERS);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
@ -181,6 +235,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_FAVORITES);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
}
@ -188,6 +243,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_LIST);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments.get(1));
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
@ -199,6 +255,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_STATUS);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments.get(2));
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
} else {
@ -207,6 +264,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_LIST_MEMBERS);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments.get(1));
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
@ -215,6 +273,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER_LIST_SUBSCRIBERS);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, "twitter.com");
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments.get(1));
return Pair.create(new Intent(Intent.ACTION_VIEW, builder.build()), true);
@ -225,7 +284,7 @@ public class TwitterLinkHandlerActivity extends Activity implements Constants {
return Pair.create(null, false);
}
private Pair<Intent, Boolean> getIntentUriIntent(Uri uri, List<String> pathSegments) {
private Pair<Intent, Boolean> getTwitterIntentUriIntent(Uri uri, List<String> pathSegments) {
if (pathSegments.size() < 2) return Pair.create(null, false);
switch (pathSegments.get(1)) {
case "tweet": {

View File

@ -342,7 +342,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
if (status == null) return;
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return;
final UserKey accountKey = data.getParcelableExtra(EXTRA_KEY);
final UserKey accountKey = data.getParcelableExtra(EXTRA_ACCOUNT_KEY);
IntentUtils.openStatus(activity, accountKey, status.id);
}
break;

View File

@ -709,7 +709,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
if (user == null) return;
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return;
final UserKey accountKey = data.getParcelableExtra(EXTRA_KEY);
final UserKey accountKey = data.getParcelableExtra(EXTRA_ACCOUNT_KEY);
@Referral
final String referral = getArguments().getString(EXTRA_REFERRAL);
IntentUtils.openUserProfile(getActivity(), accountKey, user.key,
@ -1039,6 +1039,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final Intent intent = new Intent(INTENT_ACTION_SELECT_ACCOUNT);
intent.setClass(getActivity(), AccountSelectorActivity.class);
intent.putExtra(EXTRA_SINGLE_SELECTION, true);
intent.putExtra(EXTRA_ACCOUNT_HOST, user.key.getHost());
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT);
break;
}

View File

@ -127,7 +127,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return;
final ParcelableUserList userList = mUserList;
final UserKey accountKey = data.getParcelableExtra(EXTRA_KEY);
final UserKey accountKey = data.getParcelableExtra(EXTRA_ACCOUNT_KEY);
IntentUtils.openUserListDetails(getActivity(), accountKey, userList.id,
userList.user_key, userList.user_screen_name, userList.name);
}

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.loader;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.AsyncTaskLoader;
import org.mariotaku.twidere.api.twitter.TwitterException;
@ -48,14 +49,17 @@ public class ParcelableStatusLoader extends AsyncTaskLoader<SingleResponse<Parce
private final boolean mOmitIntentExtra;
private final Bundle mExtras;
@Nullable
private final UserKey mAccountId;
@Nullable
private final String mStatusId;
@Inject
UserColorNameManager mUserColorNameManager;
public ParcelableStatusLoader(final Context context, final boolean omitIntentExtra, final Bundle extras,
final UserKey accountId, final String statusId) {
@Nullable final UserKey accountId,
@Nullable final String statusId) {
super(context);
GeneralComponentHelper.build(context).inject(this);
mOmitIntentExtra = omitIntentExtra;
@ -66,6 +70,7 @@ public class ParcelableStatusLoader extends AsyncTaskLoader<SingleResponse<Parce
@Override
public SingleResponse<ParcelableStatus> loadInBackground() {
if (mAccountId == null || mStatusId == null) return SingleResponse.getInstance();
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableStatus cache = mExtras.getParcelable(IntentConstants.EXTRA_STATUS);
if (cache != null) {

View File

@ -914,14 +914,14 @@ public class DataStoreUtils implements Constants {
if (host != null) {
for (final Uri uri : STATUSES_URIS) {
final String deleteWhere = Expression.and(
Expression.likeRaw(new Column(Statuses.ACCOUNT_KEY), "%@?"),
Expression.likeRaw(new Column(Statuses.ACCOUNT_KEY), "'%@'||?"),
Expression.or(
Expression.equalsArgs(Statuses.STATUS_ID),
Expression.equalsArgs(Statuses.RETWEET_ID)
)).getSQL();
cr.delete(uri, deleteWhere, new String[]{host, statusId, statusId});
final String updateWhere = Expression.and(
Expression.likeRaw(new Column(Statuses.ACCOUNT_KEY), "%@?"),
Expression.likeRaw(new Column(Statuses.ACCOUNT_KEY), "'%@'||?"),
Expression.equalsArgs(Statuses.MY_RETWEET_ID)
).getSQL();
if (status != null) {

View File

@ -47,7 +47,6 @@ import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.AccountSelectorActivity;
import org.mariotaku.twidere.activity.ColorPickerDialogActivity;
import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.constant.SharedPreferenceConstants;
import org.mariotaku.twidere.fragment.AbsStatusesFragment;
import org.mariotaku.twidere.fragment.AddStatusFilterDialogFragment;
@ -219,8 +218,8 @@ public class MenuUtils implements Constants {
setMenuItemAvailability(menu, R.id.translate, isOfficialKey);
}
menu.removeGroup(Constants.MENU_GROUP_STATUS_EXTENSION);
Utils.addIntentToMenuForExtension(context, menu, Constants.MENU_GROUP_STATUS_EXTENSION, IntentConstants.INTENT_ACTION_EXTENSION_OPEN_STATUS,
IntentConstants.EXTRA_STATUS, IntentConstants.EXTRA_STATUS_JSON, status);
Utils.addIntentToMenuForExtension(context, menu, Constants.MENU_GROUP_STATUS_EXTENSION, INTENT_ACTION_EXTENSION_OPEN_STATUS,
EXTRA_STATUS, EXTRA_STATUS_JSON, status);
final MenuItem shareItem = menu.findItem(R.id.share);
final ActionProvider shareProvider = MenuItemCompat.getActionProvider(shareItem);
if (shareProvider instanceof SupportStatusShareProvider) {
@ -267,14 +266,14 @@ public class MenuUtils implements Constants {
break;
}
case R.id.quote: {
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_QUOTE);
intent.putExtra(IntentConstants.EXTRA_STATUS, status);
final Intent intent = new Intent(INTENT_ACTION_QUOTE);
intent.putExtra(EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
case R.id.reply: {
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_REPLY);
intent.putExtra(IntentConstants.EXTRA_STATUS, status);
final Intent intent = new Intent(INTENT_ACTION_REPLY);
intent.putExtra(EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
@ -304,10 +303,10 @@ public class MenuUtils implements Constants {
final Intent intent = new Intent(context, ColorPickerDialogActivity.class);
final int color = colorNameManager.getUserColor(status.user_key);
if (color != 0) {
intent.putExtra(IntentConstants.EXTRA_COLOR, color);
intent.putExtra(EXTRA_COLOR, color);
}
intent.putExtra(IntentConstants.EXTRA_CLEAR_BUTTON, color != 0);
intent.putExtra(IntentConstants.EXTRA_ALPHA_SLIDER, false);
intent.putExtra(EXTRA_CLEAR_BUTTON, color != 0);
intent.putExtra(EXTRA_ALPHA_SLIDER, false);
if (fragment != null) {
fragment.startActivityForResult(intent, REQUEST_SET_COLOR);
} else if (context instanceof Activity) {
@ -329,9 +328,10 @@ public class MenuUtils implements Constants {
break;
}
case R.id.open_with_account: {
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_SELECT_ACCOUNT);
final Intent intent = new Intent(INTENT_ACTION_SELECT_ACCOUNT);
intent.setClass(context, AccountSelectorActivity.class);
intent.putExtra(IntentConstants.EXTRA_SINGLE_SELECTION, true);
intent.putExtra(EXTRA_SINGLE_SELECTION, true);
intent.putExtra(EXTRA_ACCOUNT_HOST, status.user_key.getHost());
if (fragment != null) {
fragment.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT);
} else if (context instanceof Activity) {

View File

@ -37,6 +37,7 @@ import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterCaps;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.TwitterOAuth;
import org.mariotaku.twidere.api.twitter.TwitterOAuth2;
import org.mariotaku.twidere.api.twitter.TwitterUpload;
import org.mariotaku.twidere.api.twitter.TwitterUserStream;
import org.mariotaku.twidere.api.twitter.auth.BasicAuthorization;
@ -264,7 +265,10 @@ public class TwitterAPIFactory implements TwidereConstants {
versionSuffix = noVersionSuffix ? null : "/1.1/";
} else if (TwitterOAuth.class.isAssignableFrom(cls)) {
domain = "api";
versionSuffix = "/oauth";
versionSuffix = null;
} else if (TwitterOAuth2.class.isAssignableFrom(cls)) {
domain = "api";
versionSuffix = null;
} else if (TwitterUserStream.class.isAssignableFrom(cls)) {
domain = "userstream";
versionSuffix = noVersionSuffix ? null : "/1.1/";

View File

@ -63,6 +63,7 @@ import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.annotation.WorkerThread;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
@ -443,12 +444,7 @@ public final class Utils implements Constants {
return colors;
}
public static Fragment createFragmentForIntent(final Context context, final Intent intent) {
final Uri uri = intent.getData();
return createFragmentForIntent(context, matchLinkId(uri), intent);
}
public static Fragment createFragmentForIntent(final Context context, final int linkId, final Intent intent) {
public static Fragment createFragmentForIntent(final Context context, final int linkId, final Intent intent) throws NoAccountException {
intent.setExtrasClassLoader(context.getClassLoader());
final Bundle extras = intent.getExtras();
final Uri uri = intent.getData();
@ -461,14 +457,17 @@ public final class Utils implements Constants {
boolean isAccountIdRequired = true;
switch (linkId) {
case LINK_ID_ACCOUNTS: {
isAccountIdRequired = false;
fragment = new AccountsManagerFragment();
break;
}
case LINK_ID_DRAFTS: {
isAccountIdRequired = false;
fragment = new DraftsFragment();
break;
}
case LINK_ID_FILTERS: {
isAccountIdRequired = false;
fragment = new FiltersFragment();
break;
}
@ -477,6 +476,7 @@ public final class Utils implements Constants {
break;
}
case LINK_ID_MAP: {
isAccountIdRequired = false;
if (!args.containsKey(EXTRA_LATITUDE) && !args.containsKey(EXTRA_LONGITUDE)) {
final double lat = NumberUtils.toDouble(uri.getQueryParameter(QUERY_PARAM_LAT), Double.NaN);
final double lng = NumberUtils.toDouble(uri.getQueryParameter(QUERY_PARAM_LNG), Double.NaN);
@ -775,7 +775,10 @@ public final class Utils implements Constants {
return null;
}
}
UserKey accountKey = UserKey.valueOf(uri.getQueryParameter(QUERY_PARAM_ACCOUNT_KEY));
UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
if (accountKey == null) {
accountKey = UserKey.valueOf(uri.getQueryParameter(QUERY_PARAM_ACCOUNT_KEY));
}
if (accountKey == null) {
final String accountId = uri.getQueryParameter(QUERY_PARAM_ACCOUNT_ID);
final String paramAccountName = uri.getQueryParameter(QUERY_PARAM_ACCOUNT_NAME);
@ -784,19 +787,21 @@ public final class Utils implements Constants {
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey);
} else if (paramAccountName != null) {
accountKey = DataStoreUtils.findAccountKeyByScreenName(context, paramAccountName);
} else {
accountKey = getDefaultAccountKey(context);
}
}
if (isAccountIdRequired && accountKey == null) {
return null;
throw new NoAccountException();
}
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey);
fragment.setArguments(args);
return fragment;
}
public static class NoAccountException extends Exception {
}
public static String getUserKeyParam(Uri uri) {
final String paramUserKey = uri.getQueryParameter(QUERY_PARAM_USER_KEY);
if (paramUserKey == null) {
@ -915,10 +920,11 @@ public final class Utils implements Constants {
}
@NonNull
public static ParcelableStatus findStatus(final Context context, final UserKey accountKey,
final String statusId)
@WorkerThread
public static ParcelableStatus findStatus(@NonNull final Context context,
@NonNull final UserKey accountKey,
@NonNull final String statusId)
throws TwitterException {
if (context == null) throw new NullPointerException();
final ParcelableStatus cached = findStatusInDatabases(context, accountKey, statusId);
if (cached != null) return cached;
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(context, accountKey, true);
@ -934,9 +940,10 @@ public final class Utils implements Constants {
}
@Nullable
public static ParcelableStatus findStatusInDatabases(final Context context, final UserKey accountKey,
final String statusId) {
if (context == null) return null;
@WorkerThread
public static ParcelableStatus findStatusInDatabases(@NonNull final Context context,
@NonNull final UserKey accountKey,
@NonNull final String statusId) {
final ContentResolver resolver = context.getContentResolver();
ParcelableStatus status = null;
final String where = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),

View File

@ -23,12 +23,7 @@
android:clipChildren="false"
android:descendantFocusability="blocksDescendants"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingEnd="@dimen/element_spacing_normal"
android:paddingLeft="0dp"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingStart="0dp"
android:paddingTop="@dimen/element_spacing_normal"
android:padding="@dimen/element_spacing_normal"
app:ignorePadding="true">
<View
@ -38,8 +33,11 @@
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_weight="0"
android:background="@drawable/list_drag_handle"
android:visibility="visible"
tools:layout_height="?android:attr/listPreferredItemHeight"/>
<org.mariotaku.twidere.view.ProfileImageView
@ -80,11 +78,12 @@
<TextView
android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:textColorPrimary"/>
android:textColor="?android:textColorPrimary"
tools:text="Name"/>
<TextView
android:id="@android:id/text2"
@ -92,7 +91,8 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorSecondary"/>
android:textColor="?android:textColorSecondary"
tools:text="\@screenname"/>
</LinearLayout>
<com.lnikkila.extendedtouchview.ExtendedTouchView

View File

@ -51,7 +51,7 @@
android:key="translation_destination"
android:title="@string/translation_destination"/>
<org.mariotaku.twidere.preference.ComponentStatePreference
android:name="org.mariotaku.twidere.activity.TwitterLinkHandlerActivity"
android:name="org.mariotaku.twidere.activity.WebLinkHandlerActivity"
android:key="twitter_link_handler"
android:title="@string/open_twitter_links"/>
<Preference