added subscribe to filters link

This commit is contained in:
Mariotaku Lee 2017-01-19 01:48:29 +08:00
parent 87f2e604f4
commit 172e85ee42
11 changed files with 439 additions and 288 deletions

View File

@ -127,6 +127,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
String PATH_FILTERS_IMPORT_BLOCKS = "import/blocks";
String PATH_FILTERS_IMPORT_MUTES = "import/mutes";
String PATH_FILTERS_SUBSCRIPTIONS = "subscriptions";
String PATH_FILTERS_SUBSCRIPTIONS_ADD = "subscriptions/add";
String QUERY_PARAM_ACCOUNT_KEY = "account_key";
String QUERY_PARAM_ACCOUNT_HOST = "account_host";

View File

@ -13,7 +13,6 @@ import org.mariotaku.twidere.activity.premium.AbsExtraFeaturePurchaseActivity
*/
class GooglePlayExtraFeaturesService() : ExtraFeaturesService() {
private val PRODUCT_ID_EXTRA_FEATURES_PACK = "twidere.extra.features"
private lateinit var bp: BillingProcessor
@ -37,7 +36,12 @@ class GooglePlayExtraFeaturesService() : ExtraFeaturesService() {
}
override fun destroyPurchase(): Boolean {
return bp.consumePurchase(PRODUCT_ID_EXTRA_FEATURES_PACK)
bp.consumePurchase(PRODUCT_ID_EXTRA_FEATURES_PACK)
bp.consumePurchase(PRODUCT_ID_DATA_SYNC)
bp.consumePurchase(PRODUCT_ID_FILTERS_IMPORT)
bp.consumePurchase(PRODUCT_ID_FILTERS_SUBSCRIPTION)
bp.consumePurchase(PRODUCT_ID_SCHEDULE_STATUS)
return true
}
override fun createPurchaseIntent(context: Context, feature: String): Intent? {
@ -56,14 +60,20 @@ class GooglePlayExtraFeaturesService() : ExtraFeaturesService() {
}
companion object {
private const val PRODUCT_ID_EXTRA_FEATURES_PACK = "twidere.extra.features"
private const val PRODUCT_ID_DATA_SYNC = "twidere.extra.feature.data_sync"
private const val PRODUCT_ID_FILTERS_IMPORT = "twidere.extra.feature.filter_import"
private const val PRODUCT_ID_FILTERS_SUBSCRIPTION = "twidere.extra.feature.filter_subscription"
private const val PRODUCT_ID_SCHEDULE_STATUS = "twidere.extra.feature.schedule_status"
@JvmStatic
fun getProductId(feature: String): String {
return when (feature) {
FEATURE_FEATURES_PACK -> "twidere.extra.features"
FEATURE_SYNC_DATA -> "twidere.extra.feature.data_sync"
FEATURE_FILTERS_IMPORT -> "twidere.extra.feature.filter_import"
FEATURE_FILTERS_SUBSCRIPTION -> "twidere.extra.feature.filter_subscription"
FEATURE_SCHEDULE_STATUS -> "twidere.extra.feature.schedule_status"
FEATURE_FEATURES_PACK -> PRODUCT_ID_EXTRA_FEATURES_PACK
FEATURE_SYNC_DATA -> PRODUCT_ID_DATA_SYNC
FEATURE_FILTERS_IMPORT -> PRODUCT_ID_FILTERS_IMPORT
FEATURE_FILTERS_SUBSCRIPTION -> PRODUCT_ID_FILTERS_SUBSCRIPTION
FEATURE_SCHEDULE_STATUS -> PRODUCT_ID_SCHEDULE_STATUS
else -> throw UnsupportedOperationException(feature)
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.mariotaku.twidere"
xmlns:android="http://schemas.android.com/apk/res/android"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.mariotaku.twidere"
android:installLocation="internalOnly">
<uses-sdk tools:overrideLibrary="android.support.customtabs" />
@ -410,6 +410,9 @@
<data android:host="www.twitter.com" />
<data android:host="mobile.twitter.com" />
<data android:host="fanfou.com" />
<data
android:host="twidere.mariotaku.org"
android:pathPrefix="/external" />
<action android:name="android.intent.action.VIEW" />
<action android:name="android.nfc.action.NDEF_DISCOVERED" />

View File

@ -79,6 +79,7 @@ public interface Constants extends TwidereConstants {
int LINK_ID_FILTERS_IMPORT_BLOCKS = 111;
int LINK_ID_FILTERS_IMPORT_MUTES = 112;
int LINK_ID_FILTERS_SUBSCRIPTIONS = 113;
int LINK_ID_FILTERS_SUBSCRIPTIONS_ADD = 114;
int LINK_ID_PROFILE_EDITOR = 121;
String TWIDERE_PREVIEW_NICKNAME = "Twidere";

View File

@ -155,51 +155,10 @@ public final class Utils implements Constants {
public static final Pattern PATTERN_XML_RESOURCE_IDENTIFIER = Pattern.compile("res/xml/([\\w_]+)\\.xml");
public static final Pattern PATTERN_RESOURCE_IDENTIFIER = Pattern.compile("@([\\w_]+)/([\\w_]+)");
private static final UriMatcher LINK_HANDLER_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final UriMatcher HOME_TABS_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static {
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS, null, LINK_ID_STATUS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER, null, LINK_ID_USER);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_TIMELINE, null, LINK_ID_USER_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_MEDIA_TIMELINE, null, LINK_ID_USER_MEDIA_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FOLLOWERS, null, LINK_ID_USER_FOLLOWERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FRIENDS, null, LINK_ID_USER_FRIENDS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FAVORITES, null, LINK_ID_USER_FAVORITES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_BLOCKS, null, LINK_ID_USER_BLOCKS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_DIRECT_MESSAGES_CONVERSATION, null,
LINK_ID_DIRECT_MESSAGES_CONVERSATION);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_DIRECT_MESSAGES, null, LINK_ID_DIRECT_MESSAGES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_INTERACTIONS, null, LINK_ID_INTERACTIONS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_PUBLIC_TIMELINE, null, LINK_ID_PUBLIC_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST, null, LINK_ID_USER_LIST);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_GROUP, null, LINK_ID_GROUP);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_TIMELINE, null, LINK_ID_USER_LIST_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_MEMBERS, null, LINK_ID_USER_LIST_MEMBERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_SUBSCRIBERS, null, LINK_ID_USER_LIST_SUBSCRIBERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_MEMBERSHIPS, null, LINK_ID_USER_LIST_MEMBERSHIPS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LISTS, null, LINK_ID_USER_LISTS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_GROUPS, null, LINK_ID_USER_GROUPS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_SAVED_SEARCHES, null, LINK_ID_SAVED_SEARCHES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_MENTIONS, null, LINK_ID_USER_MENTIONS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_INCOMING_FRIENDSHIPS, null, LINK_ID_INCOMING_FRIENDSHIPS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_ITEMS, null, LINK_ID_ITEMS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS_RETWEETERS, null, LINK_ID_STATUS_RETWEETERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS_FAVORITERS, null, LINK_ID_STATUS_FAVORITERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_SEARCH, null, LINK_ID_SEARCH);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_MUTES_USERS, null, LINK_ID_MUTES_USERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_MAP, null, LINK_ID_MAP);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_SCHEDULED_STATUSES, null, LINK_ID_SCHEDULED_STATUSES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_ACCOUNTS, null, LINK_ID_ACCOUNTS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_DRAFTS, null, LINK_ID_DRAFTS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, null, LINK_ID_FILTERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_BLOCKS, LINK_ID_FILTERS_IMPORT_BLOCKS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_MUTES, LINK_ID_FILTERS_IMPORT_MUTES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, PATH_FILTERS_SUBSCRIPTIONS, LINK_ID_FILTERS_SUBSCRIPTIONS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_PROFILE_EDITOR, null, LINK_ID_PROFILE_EDITOR);
HOME_TABS_URI_MATCHER.addURI(CustomTabType.HOME_TIMELINE, null, TAB_CODE_HOME_TIMELINE);
HOME_TABS_URI_MATCHER.addURI(CustomTabType.NOTIFICATIONS_TIMELINE, null, TAB_CODE_NOTIFICATIONS_TIMELINE);
HOME_TABS_URI_MATCHER.addURI(CustomTabType.DIRECT_MESSAGES, null, TAB_CODE_DIRECT_MESSAGES);
@ -915,12 +874,6 @@ public final class Utils implements Constants {
}
}
public static int matchLinkId(@Nullable final Uri uri) {
if (uri == null) return UriMatcher.NO_MATCH;
return LINK_HANDLER_URI_MATCHER.match(uri);
}
public static int matchTabCode(@Nullable final Uri uri) {
if (uri == null) return UriMatcher.NO_MATCH;
return HOME_TABS_URI_MATCHER.match(uri);

View File

@ -43,12 +43,8 @@ import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.iface.IControlBarActivity
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper
import org.mariotaku.twidere.constant.CompatibilityConstants
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_SIMPLE_LAYOUT
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER_KEY
import org.mariotaku.twidere.constant.KeyboardShortcutConstants
import org.mariotaku.twidere.constant.SharedPreferenceConstants
import org.mariotaku.twidere.constant.iWantMyStarsBackKey
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.fragment.*
import org.mariotaku.twidere.fragment.filter.FiltersFragment
import org.mariotaku.twidere.fragment.filter.FiltersImportBlocksFragment
@ -64,7 +60,7 @@ import org.mariotaku.twidere.model.analyzer.PurchaseFinished
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
import org.mariotaku.twidere.util.Utils.LINK_ID_FILTERS_IMPORT_BLOCKS
import org.mariotaku.twidere.util.Utils.matchLinkId
import org.mariotaku.twidere.util.linkhandler.TwidereLinkMatcher
class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IControlBarActivity,
SupportFragmentCallback {
@ -85,8 +81,11 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
controlBarShowHideHelper = ControlBarShowHideHelper(this)
multiSelectHandler.dispatchOnCreate()
val uri = intent.data
val linkId = matchLinkId(uri)
val uri = intent.data ?: run {
finish()
return
}
val linkId = TwidereLinkMatcher.match(uri)
intent.setExtrasClassLoader(classLoader)
val fragment: Fragment
try {
@ -413,6 +412,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
LINK_ID_FILTERS_IMPORT_MUTES -> {
title = getString(R.string.title_select_users)
}
LINK_ID_FILTERS_SUBSCRIPTIONS_ADD,
LINK_ID_FILTERS_SUBSCRIPTIONS -> {
title = getString(R.string.title_manage_filter_subscriptions)
}
@ -761,6 +761,15 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
fragment = FiltersSubscriptionsFragment()
isAccountIdRequired = false
}
LINK_ID_FILTERS_SUBSCRIPTIONS_ADD -> {
val url = uri.getQueryParameter("url") ?: return null
val name = uri.getQueryParameter("name")
fragment = FiltersSubscriptionsFragment()
args.putString(IntentConstants.EXTRA_ACTION, FiltersSubscriptionsFragment.ACTION_ADD_URL_SUBSCRIPTION)
args.putString(FiltersSubscriptionsFragment.EXTRA_ADD_SUBSCRIPTION_URL, url)
args.putString(FiltersSubscriptionsFragment.EXTRA_ADD_SUBSCRIPTION_NAME, name)
isAccountIdRequired = false
}
else -> {
return null
}

View File

@ -2,10 +2,10 @@ package org.mariotaku.twidere.activity
import android.app.Activity
import android.content.Intent
import android.content.UriMatcher
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.util.Pair
import org.apache.commons.lang3.ArrayUtils
import org.mariotaku.ktextension.toLong
import org.mariotaku.twidere.Constants
@ -17,35 +17,29 @@ import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.IntentUtils
import org.mariotaku.twidere.util.Utils
class WebLinkHandlerActivity : Activity(), Constants {
class WebLinkHandlerActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val packageManager = packageManager
val intent = intent
intent.setExtrasClassLoader(TwidereApplication::class.java.classLoader)
val uri = intent.data
if (uri == null || uri.host == null) {
finish()
return
}
val handled: Pair<Intent, Boolean>
when (uri.host) {
"twitter.com", "www.twitter.com", "mobile.twitter.com" -> {
handled = handleTwitterLink(regulateTwitterUri(uri))
val (handledIntent, handledSuccessfully) = when (uri.host) {
"twitter.com", "www.twitter.com", "mobile.twitter.com" -> handleTwitterLink(regulateTwitterUri(uri))
"fanfou.com" -> handleFanfouLink(uri)
"twidere.mariotaku.org" -> handleTwidereExternalLink(uri)
else -> Pair(null, false)
}
"fanfou.com" -> {
handled = handleFanfouLink(uri)
}
else -> {
handled = Pair.create<Intent, Boolean>(null, false)
}
}
if (handled.first != null) {
handled.first.putExtras(intent)
startActivity(handled.first)
if (handledIntent != null) {
handledIntent.putExtras(intent)
startActivity(handledIntent)
} else {
if (!handled.second) {
if (!handledSuccessfully) {
Analyzer.logException(TwitterLinkException("Unable to handle twitter uri " + uri))
}
val fallbackIntent = Intent(Intent.ACTION_VIEW, uri)
@ -70,7 +64,25 @@ class WebLinkHandlerActivity : Activity(), Constants {
setVisible(true)
}
private fun handleFanfouLink(uri: Uri): Pair<Intent, Boolean> {
private fun handleTwidereExternalLink(uri: Uri): Pair<Intent?, Boolean> {
val pathSegments = uri.pathSegments
if (pathSegments.size < 2 || pathSegments[0] != "external") {
return Pair(null, false)
}
val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE)
builder.authority(pathSegments[1])
if (pathSegments.size >= 3) {
for (segment in pathSegments.slice(2..pathSegments.lastIndex)) {
builder.appendPath(segment)
}
}
builder.encodedQuery(uri.encodedQuery)
builder.encodedFragment(uri.encodedFragment)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
private fun handleFanfouLink(uri: Uri): Pair<Intent?, Boolean> {
val pathSegments = uri.pathSegments
if (pathSegments.size > 0) {
when (pathSegments[0]) {
@ -80,7 +92,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_STATUS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM)
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
else -> {
if (!ArrayUtils.contains(FANFOU_RESERVED_PATHS, pathSegments[0])) {
@ -91,17 +103,17 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM)
val userKey = UserKey(pathSegments[0], USER_TYPE_FANFOU_COM)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, userKey.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
}
return Pair.create<Intent, Boolean>(null, false)
return Pair(null, false)
}
}
}
return Pair.create<Intent, Boolean>(null, false)
return Pair(null, false)
}
private fun handleTwitterLink(uri: Uri): Pair<Intent, Boolean> {
private fun handleTwitterLink(uri: Uri): Pair<Intent?, Boolean> {
val pathSegments = uri.pathSegments
if (pathSegments.size > 0) {
when (pathSegments[0]) {
@ -117,7 +129,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
val text = uri.getQueryParameter("text")
val url = uri.getQueryParameter("url")
handledIntent.putExtra(Intent.EXTRA_TEXT, Utils.getShareStatus(this, text, url))
return Pair.create(handledIntent, true)
return Pair(handledIntent, true)
}
"search" -> {
val builder = Uri.Builder()
@ -125,7 +137,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_SEARCH)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_QUERY, uri.getQueryParameter("q"))
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
"hashtag" -> {
val builder = Uri.Builder()
@ -133,41 +145,41 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_SEARCH)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_QUERY, "#${uri.lastPathSegment}")
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
"following" -> {
val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE)
builder.authority(AUTHORITY_USER_FRIENDS)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
"followers" -> {
val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE)
builder.authority(AUTHORITY_USER_FOLLOWERS)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
"favorites" -> {
val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE)
builder.authority(AUTHORITY_USER_FAVORITES)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
else -> {
if (ArrayUtils.contains(TWITTER_RESERVED_PATHS, pathSegments[0])) {
return Pair.create<Intent, Boolean>(null, true)
return Pair(null, true)
}
return handleUserSpecificPageIntent(uri, pathSegments, pathSegments[0])
}
}
}
return Pair.create<Intent, Boolean>(null, false)
return Pair(null, false)
}
private fun handleUserSpecificPageIntent(uri: Uri, pathSegments: List<String>, screenName: String): Pair<Intent, Boolean> {
private fun handleUserSpecificPageIntent(uri: Uri, pathSegments: List<String>, screenName: String): Pair<Intent?, Boolean> {
val segsSize = pathSegments.size
if (segsSize == 1) {
val builder = Uri.Builder()
@ -175,7 +187,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} else if (segsSize == 2) {
when (pathSegments[1]) {
"following" -> {
@ -184,7 +196,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER_FRIENDS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
"followers" -> {
val builder = Uri.Builder()
@ -192,7 +204,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER_FOLLOWERS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
"favorites" -> {
val builder = Uri.Builder()
@ -200,7 +212,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER_FAVORITES)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
else -> {
val builder = Uri.Builder()
@ -209,7 +221,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
}
} else if (segsSize >= 3) {
@ -219,7 +231,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_STATUS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments[2])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} else {
when (pathSegments[2]) {
"members" -> {
@ -229,7 +241,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
"subscribers" -> {
val builder = Uri.Builder()
@ -238,16 +250,16 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
}
}
}
return Pair.create<Intent, Boolean>(null, false)
return Pair(null, false)
}
private fun getTwitterIntentUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent, Boolean> {
if (pathSegments.size < 2) return Pair.create<Intent, Boolean>(null, false)
private fun getTwitterIntentUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent?, Boolean> {
if (pathSegments.size < 2) return Pair(null, false)
when (pathSegments[1]) {
"tweet" -> {
val handledIntent = Intent(this, ComposeActivity::class.java)
@ -265,14 +277,14 @@ class WebLinkHandlerActivity : Activity(), Constants {
sb.append(url)
}
handledIntent.putExtra(Intent.EXTRA_TEXT, sb.toString())
return Pair.create(handledIntent, true)
return Pair(handledIntent, true)
}
}
return Pair.create<Intent, Boolean>(null, false)
return Pair(null, false)
}
private fun getIUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent, Boolean> {
return Pair.create<Intent, Boolean>(null, false)
private fun getIUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent?, Boolean> {
return Pair(null, false)
}
private inner class TwitterLinkException(s: String) : Exception(s)

View File

@ -1,6 +1,9 @@
package org.mariotaku.twidere.fragment
import android.app.Activity
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
@ -43,12 +46,12 @@ class ExtraFeaturesIntroductionDialogFragment : BaseDialogFragment() {
Analyzer.log(PurchaseConfirm(PurchaseFinished.NAME_EXTRA_FEATURES))
}
builder.setNegativeButton(R.string.action_later) { dialog, which ->
onDialogCancelled()
}
val restorePurchaseIntent = extraFeaturesService.createRestorePurchaseIntent(context, feature)
if (restorePurchaseIntent != null) {
builder.setNeutralButton(R.string.action_restore_purchase) { dialog, which ->
startActivity(restorePurchaseIntent)
startActivityForResultOnTarget(restorePurchaseIntent)
}
}
val dialog = builder.create()
@ -75,14 +78,30 @@ class ExtraFeaturesIntroductionDialogFragment : BaseDialogFragment() {
return dialog
}
override fun onCancel(dialog: DialogInterface?) {
onDialogCancelled()
}
private fun onDialogCancelled() {
if (targetRequestCode != 0) {
targetFragment?.onActivityResult(targetRequestCode, Activity.RESULT_CANCELED, null)
}
}
private fun startPurchase(feature: String) {
val purchaseIntent = extraFeaturesService.createPurchaseIntent(context, feature)
if (requestCode == 0) {
startActivity(purchaseIntent)
val purchaseIntent = extraFeaturesService.createPurchaseIntent(context, feature) ?: return
startActivityForResultOnTarget(purchaseIntent)
}
private fun startActivityForResultOnTarget(intent: Intent) {
if (targetFragment != null) {
targetFragment.startActivityForResult(intent, targetRequestCode)
} else if (requestCode == 0) {
startActivity(intent)
} else if (parentFragment != null) {
parentFragment.startActivityForResult(purchaseIntent, requestCode)
parentFragment.startActivityForResult(intent, requestCode)
} else {
activity.startActivityForResult(purchaseIntent, requestCode)
activity.startActivityForResult(intent, requestCode)
}
}

View File

@ -1,10 +1,13 @@
package org.mariotaku.twidere.fragment.filter
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.database.Cursor
import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.support.v4.app.LoaderManager
import android.support.v4.content.CursorLoader
import android.support.v4.content.Loader
@ -16,19 +19,28 @@ import com.rengwuxian.materialedittext.MaterialEditText
import kotlinx.android.synthetic.main.layout_list_with_empty_view.*
import okhttp3.HttpUrl
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.empty
import org.mariotaku.ktextension.isEmpty
import org.mariotaku.ktextension.set
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.REQUEST_PURCHASE_EXTRA_FEATURES
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACTION
import org.mariotaku.twidere.constant.IntentConstants.INTENT_PACKAGE_PREFIX
import org.mariotaku.twidere.extension.model.getComponentLabel
import org.mariotaku.twidere.extension.model.setupUrl
import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.fragment.BaseFragment
import org.mariotaku.twidere.fragment.ExtraFeaturesIntroductionDialogFragment
import org.mariotaku.twidere.fragment.ProgressDialogFragment
import org.mariotaku.twidere.model.FiltersSubscription
import org.mariotaku.twidere.model.FiltersSubscriptionCursorIndices
import org.mariotaku.twidere.model.FiltersSubscriptionValuesCreator
import org.mariotaku.twidere.model.analyzer.PurchaseFinished
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
import org.mariotaku.twidere.task.filter.RefreshFiltersSubscriptionsTask
import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
import org.mariotaku.twidere.util.view.SimpleTextWatcher
import java.lang.ref.WeakReference
@ -49,6 +61,53 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
listContainer.visibility = View.GONE
progressContainer.visibility = View.VISIBLE
loaderManager.initLoader(0, null, this)
if (!extraFeaturesService.isSupported()) {
activity?.finish()
return
}
if (savedInstanceState == null) {
when (arguments?.getString(EXTRA_ACTION)) {
ACTION_ADD_URL_SUBSCRIPTION -> {
if (extraFeaturesService.isEnabled(ExtraFeaturesService.FEATURE_FILTERS_SUBSCRIPTION).not()) {
val df = ExtraFeaturesIntroductionDialogFragment.show(childFragmentManager,
ExtraFeaturesService.FEATURE_FILTERS_SUBSCRIPTION)
df.setTargetFragment(this, REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE)
} else {
showAddUrlSubscription()
}
}
else -> {
val df = ExtraFeaturesIntroductionDialogFragment.show(childFragmentManager,
ExtraFeaturesService.FEATURE_FILTERS_SUBSCRIPTION)
df.setTargetFragment(this, REQUEST_PURCHASE_EXTRA_FEATURES)
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE -> {
if (resultCode == Activity.RESULT_OK) {
Analyzer.log(PurchaseFinished.create(data!!))
executeAfterFragmentResumed { fragment ->
(fragment as FiltersSubscriptionsFragment).showAddUrlSubscription()
}
} else {
activity?.finish()
}
}
REQUEST_PURCHASE_EXTRA_FEATURES -> {
if (resultCode == Activity.RESULT_OK) {
Analyzer.log(PurchaseFinished.create(data!!))
} else {
activity?.finish()
}
}
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -63,12 +122,18 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
return true
}
R.id.refresh -> {
val dfRef = WeakReference(ProgressDialogFragment.show(childFragmentManager, "refresh_filters"))
val task = RefreshFiltersSubscriptionsTask(context)
executeAfterFragmentResumed { fragment ->
val dfRef = WeakReference(ProgressDialogFragment.show(fragment.childFragmentManager, "refresh_filters"))
val task = RefreshFiltersSubscriptionsTask(fragment.context)
val fragmentRef = WeakReference(fragment)
task.callback = {
dfRef.get()?.dismiss()
fragmentRef.get()?.executeAfterFragmentResumed { fragment ->
val df = dfRef.get() ?: fragment.childFragmentManager.findFragmentByTag("refresh_filters") as? DialogFragment
df?.dismiss()
}
}
TaskStarter.execute(task)
}
return true
}
else -> return false
@ -105,6 +170,15 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
progressContainer.visibility = View.GONE
}
private fun showAddUrlSubscription() {
val df = AddUrlSubscriptionDialogFragment()
df.arguments = Bundle {
this[EXTRA_ADD_SUBSCRIPTION_URL] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_URL)
this[EXTRA_ADD_SUBSCRIPTION_NAME] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_NAME)
}
df.show(fragmentManager, "add_url_subscription")
}
class FilterSubscriptionsAdapter(context: Context) : SimpleCursorAdapter(context,
R.layout.list_item_two_line, null, arrayOf(Filters.Subscriptions.NAME),
intArrayOf(android.R.id.text1), 0) {
@ -163,11 +237,25 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
}
editName.addTextChangedListener(watcher)
editUrl.addTextChangedListener(watcher)
val args = arguments
if (savedInstanceState == null && args != null) {
editName.setText(args.getString(EXTRA_ADD_SUBSCRIPTION_NAME))
editUrl.setText(args.getString(EXTRA_ADD_SUBSCRIPTION_URL))
}
updateEnableState()
}
return dialog
}
}
companion object {
const val ACTION_ADD_URL_SUBSCRIPTION = "${INTENT_PACKAGE_PREFIX}ADD_URL_FILTERS_SUBSCRIPTION"
const val REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE = 101
const val EXTRA_ADD_SUBSCRIPTION_URL = "add_subscription.url"
const val EXTRA_ADD_SUBSCRIPTION_NAME = "add_subscription.name"
}
}

View File

@ -155,6 +155,7 @@ object ParcelableStatusUtils {
result.spans = textWithIndices.spans
result.extras.display_text_range = textWithIndices.range
}
result.media = ParcelableMediaUtils.fromStatus(status)
result.source = status.source
result.location = getLocation(status)
@ -191,10 +192,6 @@ object ParcelableStatusUtils {
return text.contains("<") && text.contains(">")
}
private fun isFanfouStatus(accountKey: UserKey): Boolean {
return USER_TYPE_FANFOU_COM == accountKey.host
}
private fun getInReplyToUserId(status: Status, accountKey: UserKey): UserKey? {
val inReplyToUserId = status.inReplyToUserId ?: return null
val entities = status.userMentionEntities

View File

@ -0,0 +1,58 @@
package org.mariotaku.twidere.util.linkhandler
import android.content.UriMatcher
import android.net.Uri
import org.mariotaku.twidere.Constants.*
/**
* Created by Mariotaku on 2017/1/18.
*/
object TwidereLinkMatcher {
private val matcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI(AUTHORITY_STATUS, null, LINK_ID_STATUS)
addURI(AUTHORITY_USER, null, LINK_ID_USER)
addURI(AUTHORITY_USER_TIMELINE, null, LINK_ID_USER_TIMELINE)
addURI(AUTHORITY_USER_MEDIA_TIMELINE, null, LINK_ID_USER_MEDIA_TIMELINE)
addURI(AUTHORITY_USER_FOLLOWERS, null, LINK_ID_USER_FOLLOWERS)
addURI(AUTHORITY_USER_FRIENDS, null, LINK_ID_USER_FRIENDS)
addURI(AUTHORITY_USER_FAVORITES, null, LINK_ID_USER_FAVORITES)
addURI(AUTHORITY_USER_BLOCKS, null, LINK_ID_USER_BLOCKS)
addURI(AUTHORITY_DIRECT_MESSAGES_CONVERSATION, null,
LINK_ID_DIRECT_MESSAGES_CONVERSATION)
addURI(AUTHORITY_DIRECT_MESSAGES, null, LINK_ID_DIRECT_MESSAGES)
addURI(AUTHORITY_INTERACTIONS, null, LINK_ID_INTERACTIONS)
addURI(AUTHORITY_PUBLIC_TIMELINE, null, LINK_ID_PUBLIC_TIMELINE)
addURI(AUTHORITY_USER_LIST, null, LINK_ID_USER_LIST)
addURI(AUTHORITY_GROUP, null, LINK_ID_GROUP)
addURI(AUTHORITY_USER_LIST_TIMELINE, null, LINK_ID_USER_LIST_TIMELINE)
addURI(AUTHORITY_USER_LIST_MEMBERS, null, LINK_ID_USER_LIST_MEMBERS)
addURI(AUTHORITY_USER_LIST_SUBSCRIBERS, null, LINK_ID_USER_LIST_SUBSCRIBERS)
addURI(AUTHORITY_USER_LIST_MEMBERSHIPS, null, LINK_ID_USER_LIST_MEMBERSHIPS)
addURI(AUTHORITY_USER_LISTS, null, LINK_ID_USER_LISTS)
addURI(AUTHORITY_USER_GROUPS, null, LINK_ID_USER_GROUPS)
addURI(AUTHORITY_SAVED_SEARCHES, null, LINK_ID_SAVED_SEARCHES)
addURI(AUTHORITY_USER_MENTIONS, null, LINK_ID_USER_MENTIONS)
addURI(AUTHORITY_INCOMING_FRIENDSHIPS, null, LINK_ID_INCOMING_FRIENDSHIPS)
addURI(AUTHORITY_ITEMS, null, LINK_ID_ITEMS)
addURI(AUTHORITY_STATUS_RETWEETERS, null, LINK_ID_STATUS_RETWEETERS)
addURI(AUTHORITY_STATUS_FAVORITERS, null, LINK_ID_STATUS_FAVORITERS)
addURI(AUTHORITY_SEARCH, null, LINK_ID_SEARCH)
addURI(AUTHORITY_MUTES_USERS, null, LINK_ID_MUTES_USERS)
addURI(AUTHORITY_MAP, null, LINK_ID_MAP)
addURI(AUTHORITY_SCHEDULED_STATUSES, null, LINK_ID_SCHEDULED_STATUSES)
addURI(AUTHORITY_ACCOUNTS, null, LINK_ID_ACCOUNTS)
addURI(AUTHORITY_DRAFTS, null, LINK_ID_DRAFTS)
addURI(AUTHORITY_FILTERS, null, LINK_ID_FILTERS)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_BLOCKS, LINK_ID_FILTERS_IMPORT_BLOCKS)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_MUTES, LINK_ID_FILTERS_IMPORT_MUTES)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_SUBSCRIPTIONS, LINK_ID_FILTERS_SUBSCRIPTIONS)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_SUBSCRIPTIONS_ADD, LINK_ID_FILTERS_SUBSCRIPTIONS_ADD)
addURI(AUTHORITY_PROFILE_EDITOR, null, LINK_ID_PROFILE_EDITOR)
}
fun match(uri: Uri): Int {
return matcher.match(uri)
}
}