From ce019ec316cb4a4c9fb21b81120a944d58eb3539 Mon Sep 17 00:00:00 2001 From: Mariotaku Lee Date: Mon, 26 Dec 2016 00:20:08 +0800 Subject: [PATCH] added invalid account alert implementing extra features --- .../twidere/constant/IntentConstants.java | 1 + twidere/build.gradle | 2 +- twidere/proguard-rules.pro | 1 + .../util/premium/DummyExtraFeaturesChecker.kt | 13 +++ ....twidere.util.premium.ExtraFeaturesChecker | 1 + twidere/src/google/AndroidManifest.xml | 16 +++- .../model/premium/GooglePurchaseResult.java | 51 ++++++++++ .../activity/PlayInAppPurchaseActivity.kt | 66 +++++++++++++ .../premium/GooglePlayExtraFeaturesChecker.kt | 30 ++++++ ....twidere.util.premium.ExtraFeaturesChecker | 1 + twidere/src/main/AndroidManifest.xml | 3 + .../twidere/model/premium/PurchaseResult.java | 16 ++++ .../twidere/model/util/AccountUtils.java | 14 +++ .../util/support/AccountManagerSupport.java | 93 ------------------- .../activity/InvalidAccountAlertActivity.kt | 64 +++++++++++++ .../twidere/activity/MainActivity.kt | 12 ++- .../activity/PlusServiceDashboardActivity.kt | 20 +++- .../fragment/AccountsManagerFragment.kt | 4 +- .../twidere/fragment/BaseFiltersFragment.kt | 51 +++++++++- ...ExtraFeaturesIntroductionDialogFragment.kt | 28 ++++++ .../ExtraFeaturesIntroductionCardFragment.kt | 32 +++++++ .../loader/CursorSupportUsersLoader.kt | 2 +- .../util/premium/ExtraFeaturesChecker.kt | 32 +++++++ .../util/support/AccountManagerSupport.kt | 72 ++++++++++++++ .../activity_plus_service_dashboard.xml | 18 +--- ...m_extra_features_purchase_introduction.xml | 17 ++++ .../card_item_extra_features_sync_status.xml | 15 +++ .../dialog_extra_features_introduction.xml | 11 +++ .../fragment_extra_features_introduction.xml | 38 ++++++++ .../layout_extra_features_introduction.xml | 62 +++++++++++++ .../src/main/res/menu/menu_filters_users.xml | 21 +++-- twidere/src/main/res/values/strings.xml | 8 ++ 32 files changed, 683 insertions(+), 132 deletions(-) create mode 100644 twidere/src/fdroid/kotlin/org/mariotaku/twidere/util/premium/DummyExtraFeaturesChecker.kt create mode 100644 twidere/src/fdroid/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker create mode 100644 twidere/src/google/java/org/mariotaku/twidere/model/premium/GooglePurchaseResult.java create mode 100644 twidere/src/google/kotlin/org/mariotaku/twidere/activity/PlayInAppPurchaseActivity.kt create mode 100644 twidere/src/google/kotlin/org/mariotaku/twidere/util/premium/GooglePlayExtraFeaturesChecker.kt create mode 100644 twidere/src/google/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker create mode 100644 twidere/src/main/java/org/mariotaku/twidere/model/premium/PurchaseResult.java delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/util/support/AccountManagerSupport.java create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/activity/InvalidAccountAlertActivity.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/fragment/ExtraFeaturesIntroductionDialogFragment.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/fragment/premium/ExtraFeaturesIntroductionCardFragment.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/util/premium/ExtraFeaturesChecker.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/util/support/AccountManagerSupport.kt create mode 100644 twidere/src/main/res/layout/card_item_extra_features_purchase_introduction.xml create mode 100644 twidere/src/main/res/layout/card_item_extra_features_sync_status.xml create mode 100644 twidere/src/main/res/layout/dialog_extra_features_introduction.xml create mode 100644 twidere/src/main/res/layout/fragment_extra_features_introduction.xml create mode 100644 twidere/src/main/res/layout/layout_extra_features_introduction.xml diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java index f5fe0e880..2750d90e7 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/IntentConstants.java @@ -48,6 +48,7 @@ public interface IntentConstants { String INTENT_ACTION_HIDDEN_SETTINGS_ENTRY = INTENT_PACKAGE_PREFIX + "HIDDEN_SETTINGS_ENTRY"; String INTENT_ACTION_EMOJI_SUPPORT_ABOUT = INTENT_PACKAGE_PREFIX + "EMOJI_SUPPORT_ABOUT"; String INTENT_ACTION_PLUS_SERVICE_SIGN_IN = INTENT_PACKAGE_PREFIX + "PLUS_SERVICE_SIGN_IN"; + String INTENT_ACTION_IN_APP_PURCHASE = INTENT_PACKAGE_PREFIX + "IN_APP_PURCHASE"; String INTENT_ACTION_EXTENSION_EDIT_IMAGE = INTENT_PACKAGE_PREFIX + "EXTENSION_EDIT_IMAGE"; String INTENT_ACTION_EXTENSION_UPLOAD = INTENT_PACKAGE_PREFIX + "EXTENSION_UPLOAD"; diff --git a/twidere/build.gradle b/twidere/build.gradle index bc9ad7a96..c305b9c36 100644 --- a/twidere/build.gradle +++ b/twidere/build.gradle @@ -173,7 +173,7 @@ dependencies { compile "com.github.mariotaku.CommonsLibrary:text:$mariotaku_commons_library_version" compile "com.github.mariotaku.CommonsLibrary:text-kotlin:$mariotaku_commons_library_version" compile 'com.github.mariotaku:KPreferences:0.9.5' - compile 'com.github.mariotaku:Chameleon:0.9.2' + compile 'com.github.mariotaku:Chameleon:0.9.3-SNAPSHOT' compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile 'nl.komponents.kovenant:kovenant:3.3.0' compile 'nl.komponents.kovenant:kovenant-android:3.3.0' diff --git a/twidere/proguard-rules.pro b/twidere/proguard-rules.pro index c091f063b..7fd58f8b8 100644 --- a/twidere/proguard-rules.pro +++ b/twidere/proguard-rules.pro @@ -68,6 +68,7 @@ -keep class * extends org.mariotaku.twidere.util.MapFragmentFactory -keep class * extends org.mariotaku.twidere.util.TwitterCardFragmentFactory -keep class * extends org.mariotaku.twidere.util.Analyzer +-keep class * extends org.mariotaku.twidere.util.premium.ExtraFeaturesChecker -keepclassmembers class * { private ; diff --git a/twidere/src/fdroid/kotlin/org/mariotaku/twidere/util/premium/DummyExtraFeaturesChecker.kt b/twidere/src/fdroid/kotlin/org/mariotaku/twidere/util/premium/DummyExtraFeaturesChecker.kt new file mode 100644 index 000000000..ce468fca4 --- /dev/null +++ b/twidere/src/fdroid/kotlin/org/mariotaku/twidere/util/premium/DummyExtraFeaturesChecker.kt @@ -0,0 +1,13 @@ +package org.mariotaku.twidere.util.premium + +/** + * Created by mariotaku on 2016/12/25. + */ + +class DummyExtraFeaturesChecker() : ExtraFeaturesChecker() { + + override fun isSupported(): Boolean = false + + override fun isEnabled(): Boolean = false + +} diff --git a/twidere/src/fdroid/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker b/twidere/src/fdroid/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker new file mode 100644 index 000000000..64bcad4e4 --- /dev/null +++ b/twidere/src/fdroid/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker @@ -0,0 +1 @@ +org.mariotaku.twidere.util.premium.DummyExtraFeaturesChecker \ No newline at end of file diff --git a/twidere/src/google/AndroidManifest.xml b/twidere/src/google/AndroidManifest.xml index 450c08e39..521afd5a6 100644 --- a/twidere/src/google/AndroidManifest.xml +++ b/twidere/src/google/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -18,7 +19,7 @@ android:value="AIzaSyCVdCIMFFxdNqHnCPrJ9yKUzoTfs8jhYGc"/> + + + + + + - + \ No newline at end of file diff --git a/twidere/src/google/java/org/mariotaku/twidere/model/premium/GooglePurchaseResult.java b/twidere/src/google/java/org/mariotaku/twidere/model/premium/GooglePurchaseResult.java new file mode 100644 index 000000000..9502f849b --- /dev/null +++ b/twidere/src/google/java/org/mariotaku/twidere/model/premium/GooglePurchaseResult.java @@ -0,0 +1,51 @@ +package org.mariotaku.twidere.model.premium; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; + +import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease; + +/** + * Created by mariotaku on 2016/12/25. + */ + +@ParcelablePlease +public class GooglePurchaseResult implements PurchaseResult, Parcelable { + @Override + public boolean isValid(Context context) { + return true; + } + + @Override + public boolean load(Context context) { + return true; + } + + @Override + public boolean save(Context context) { + return true; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + GooglePurchaseResultParcelablePlease.writeToParcel(this, dest, flags); + } + + public static final Creator CREATOR = new Creator() { + public GooglePurchaseResult createFromParcel(Parcel source) { + GooglePurchaseResult target = new GooglePurchaseResult(); + GooglePurchaseResultParcelablePlease.readFromParcel(target, source); + return target; + } + + public GooglePurchaseResult[] newArray(int size) { + return new GooglePurchaseResult[size]; + } + }; +} diff --git a/twidere/src/google/kotlin/org/mariotaku/twidere/activity/PlayInAppPurchaseActivity.kt b/twidere/src/google/kotlin/org/mariotaku/twidere/activity/PlayInAppPurchaseActivity.kt new file mode 100644 index 000000000..264f69e6f --- /dev/null +++ b/twidere/src/google/kotlin/org/mariotaku/twidere/activity/PlayInAppPurchaseActivity.kt @@ -0,0 +1,66 @@ +package org.mariotaku.twidere.activity + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import com.anjlab.android.iab.v3.BillingProcessor +import com.anjlab.android.iab.v3.TransactionDetails +import org.mariotaku.twidere.Constants +import org.mariotaku.twidere.TwidereConstants.EXTRA_DATA +import org.mariotaku.twidere.model.premium.GooglePurchaseResult + +/** + * Created by mariotaku on 2016/12/25. + */ + +class PlayInAppPurchaseActivity : Activity(), BillingProcessor.IBillingHandler { + + lateinit var billingProcessor: BillingProcessor + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + billingProcessor = BillingProcessor(this, Constants.GOOGLE_PLAY_LICENCING_PUBKEY, this) + if (!isFinishing && BillingProcessor.isIabServiceAvailable(this)) { + setResult(RESULT_CANCELED) + finish() + } + } + + override fun onDestroy() { + billingProcessor.release() + super.onDestroy() + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (billingProcessor.handleActivityResult(requestCode, resultCode, data)) { + return + } + super.onActivityResult(requestCode, resultCode, data) + } + + // MARK: Payment methods + override fun onBillingError(code: Int, error: Throwable?) { + setResult(RESULT_CANCELED) + finish() + } + + override fun onBillingInitialized() { + billingProcessor.purchase(this, "android.test.purchased") + } + + override fun onProductPurchased(productId: String?, details: TransactionDetails?) { + billingProcessor.getPurchaseTransactionDetails("android.test.purchased") + val data = Intent() + val purchaseResult = GooglePurchaseResult() + details?.purchaseInfo?.purchaseData?.let { purchaseData -> + + } + data.putExtra(EXTRA_DATA, purchaseResult) + setResult(RESULT_OK, data) + finish() + } + + override fun onPurchaseHistoryRestored() { + } + +} diff --git a/twidere/src/google/kotlin/org/mariotaku/twidere/util/premium/GooglePlayExtraFeaturesChecker.kt b/twidere/src/google/kotlin/org/mariotaku/twidere/util/premium/GooglePlayExtraFeaturesChecker.kt new file mode 100644 index 000000000..748137cc3 --- /dev/null +++ b/twidere/src/google/kotlin/org/mariotaku/twidere/util/premium/GooglePlayExtraFeaturesChecker.kt @@ -0,0 +1,30 @@ +package org.mariotaku.twidere.util.premium + +import android.content.Context +import com.anjlab.android.iab.v3.BillingProcessor +import org.mariotaku.twidere.Constants.GOOGLE_PLAY_LICENCING_PUBKEY + +/** + * Created by mariotaku on 2016/12/25. + */ + +class GooglePlayExtraFeaturesChecker() : ExtraFeaturesChecker() { + private lateinit var bp: BillingProcessor + + override fun init(context: Context) { + super.init(context) + bp = BillingProcessor(context, GOOGLE_PLAY_LICENCING_PUBKEY, null) + } + + override fun release() { + bp.release() + } + + override fun isSupported(): Boolean = true + + override fun isEnabled(): Boolean { + val details = bp.getPurchaseTransactionDetails("android.test.purchased") ?: return false + return bp.isValidTransactionDetails(details) + } + +} diff --git a/twidere/src/google/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker b/twidere/src/google/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker new file mode 100644 index 000000000..2ffa493bc --- /dev/null +++ b/twidere/src/google/resources/META-INF/services/org.mariotaku.twidere.util.premium.ExtraFeaturesChecker @@ -0,0 +1 @@ +org.mariotaku.twidere.util.premium.GooglePlayExtraFeaturesChecker \ No newline at end of file diff --git a/twidere/src/main/AndroidManifest.xml b/twidere/src/main/AndroidManifest.xml index 22e7236ce..0790d579f 100644 --- a/twidere/src/main/AndroidManifest.xml +++ b/twidere/src/main/AndroidManifest.xml @@ -461,6 +461,9 @@ android:name=".activity.IncompatibleAlertActivity" android:label="@string/error_title_device_incompatible" android:theme="@android:style/Theme.DeviceDefault.Dialog"/> + { private final Account account; diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/support/AccountManagerSupport.java b/twidere/src/main/java/org/mariotaku/twidere/util/support/AccountManagerSupport.java deleted file mode 100644 index 0150e9578..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/support/AccountManagerSupport.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.mariotaku.twidere.util.support; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.app.Activity; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -/** - * Created by mariotaku on 2016/12/2. - */ - -public class AccountManagerSupport { - public static AccountManagerFuture removeAccount(@NonNull AccountManager am, - @NonNull Account account, - @Nullable Activity activity, - @Nullable final AccountManagerCallback callback, - @Nullable Handler handler) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - return AccountManagerSupportL.removeAccount(am, account, activity, callback, handler); - } - //noinspection deprecation - final AccountManagerFuture future = am.removeAccount(account, new AccountManagerCallback() { - @Override - public void run(AccountManagerFuture future) { - if (callback != null) { - callback.run(new BooleanToBundleAccountManagerFuture(future)); - } - } - }, handler); - return new BooleanToBundleAccountManagerFuture(future); - } - - public static class AccountManagerSupportL { - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1) - static AccountManagerFuture removeAccount(AccountManager am, Account account, - Activity activity, - AccountManagerCallback callback, - Handler handler) { - return am.removeAccount(account, activity, callback, handler); - } - - } - - private static class BooleanToBundleAccountManagerFuture implements AccountManagerFuture { - - private final AccountManagerFuture future; - - BooleanToBundleAccountManagerFuture(AccountManagerFuture future) { - this.future = future; - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return future.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return future.isCancelled(); - } - - @Override - public boolean isDone() { - return future.isDone(); - } - - @Override - public Bundle getResult() throws OperationCanceledException, IOException, AuthenticatorException { - Bundle result = new Bundle(); - result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, future.getResult()); - return result; - } - - @Override - public Bundle getResult(long timeout, TimeUnit unit) throws OperationCanceledException, IOException, AuthenticatorException { - Bundle result = new Bundle(); - result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, future.getResult(timeout, unit)); - return result; - } - } -} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/InvalidAccountAlertActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/InvalidAccountAlertActivity.kt new file mode 100644 index 000000000..f01dea153 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/InvalidAccountAlertActivity.kt @@ -0,0 +1,64 @@ +package org.mariotaku.twidere.activity + +import android.accounts.AccountManager +import android.app.Dialog +import android.content.DialogInterface +import android.content.Intent +import android.os.Bundle +import android.support.v4.app.FragmentActivity +import android.support.v7.app.AlertDialog +import org.mariotaku.twidere.R +import org.mariotaku.twidere.constant.IntentConstants.EXTRA_INTENT +import org.mariotaku.twidere.fragment.BaseDialogFragment +import org.mariotaku.twidere.model.util.AccountUtils +import org.mariotaku.twidere.util.support.removeAccountSupport + +/** + * Created by mariotaku on 16/4/4. + */ +class InvalidAccountAlertActivity : FragmentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val df = InvalidAccountAlertDialogFragment() + df.show(supportFragmentManager, "invalid_account_alert") + } + + + class InvalidAccountAlertDialogFragment : BaseDialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val builder = AlertDialog.Builder(context) + builder.setTitle(R.string.title_error_invalid_account) + builder.setMessage(R.string.message_error_invalid_account) + builder.setPositiveButton(android.R.string.ok) { dialog, which -> + val am = AccountManager.get(context) + AccountUtils.getAccounts(am).filter { !AccountUtils.isAccountValid(am, it) }.forEach { account -> + am.removeAccountSupport(account) + } + val intent = activity.intent.getParcelableExtra(EXTRA_INTENT) + if (intent != null) { + activity.startActivity(intent) + } + } + builder.setNegativeButton(android.R.string.cancel) { dialog, which -> + + } + return builder.create() + } + + override fun onDismiss(dialog: DialogInterface?) { + super.onDismiss(dialog) + if (!activity.isFinishing) { + activity.finish() + } + } + + override fun onCancel(dialog: DialogInterface?) { + super.onCancel(dialog) + if (!activity.isFinishing) { + activity.finish() + } + } + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/MainActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/MainActivity.kt index 3a1263a79..6b57cb155 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/MainActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/MainActivity.kt @@ -19,9 +19,12 @@ package org.mariotaku.twidere.activity +import android.accounts.AccountManager import android.content.Intent import android.os.Bundle import org.mariotaku.twidere.BuildConfig +import org.mariotaku.twidere.constant.IntentConstants.EXTRA_INTENT +import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.util.StrictModeUtils import org.mariotaku.twidere.util.Utils @@ -33,12 +36,15 @@ open class MainActivity : BaseActivity() { StrictModeUtils.detectAllThreadPolicy() } super.onCreate(savedInstanceState) + val am = AccountManager.get(this) if (!Utils.checkDeviceCompatible()) { - val intent = Intent(this, IncompatibleAlertActivity::class.java) + startActivity(Intent(this, IncompatibleAlertActivity::class.java)) + } else if (AccountUtils.hasInvalidAccount(am)) { + val intent = Intent(this, InvalidAccountAlertActivity::class.java) + intent.putExtra(EXTRA_INTENT, Intent(this, HomeActivity::class.java)) startActivity(intent) } else { - val intent = Intent(this, HomeActivity::class.java) - startActivity(intent) + startActivity(Intent(this, HomeActivity::class.java)) } finish() } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/PlusServiceDashboardActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/PlusServiceDashboardActivity.kt index 16d419160..0eaac335b 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/PlusServiceDashboardActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/PlusServiceDashboardActivity.kt @@ -13,19 +13,35 @@ import android.support.v7.app.AlertDialog import android.view.View import android.view.ViewGroup import android.widget.TextView +import kotlinx.android.synthetic.main.activity_plus_service_dashboard.* import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.METADATA_KEY_PLUS_SERVICE_SIGN_IN_LABEL import org.mariotaku.twidere.adapter.ArrayAdapter import org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_PLUS_SERVICE_SIGN_IN import org.mariotaku.twidere.fragment.BaseDialogFragment +import org.mariotaku.twidere.util.premium.ExtraFeaturesChecker class PlusServiceDashboardActivity : BaseActivity() { + private lateinit var extraFeaturesChecker: ExtraFeaturesChecker + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + extraFeaturesChecker = ExtraFeaturesChecker.instance + extraFeaturesChecker.init(this) setContentView(R.layout.activity_plus_service_dashboard) - // SignInChooserDialogFragment df = new SignInChooserDialogFragment() - // df.show(getSupportFragmentManager(), "sign_in_chooser") + if (extraFeaturesChecker.isSupported()) { + if (extraFeaturesChecker.isEnabled()) { + View.inflate(this, R.layout.card_item_extra_features_sync_status, cardsContainer) + } else { + View.inflate(this, R.layout.card_item_extra_features_purchase_introduction, cardsContainer) + } + } + } + + override fun onDestroy() { + extraFeaturesChecker.release() + super.onDestroy() } class SignInChooserDialogFragment : BaseDialogFragment(), LoaderManager.LoaderCallbacks> { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt index 7197c605e..8310cb4b7 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt @@ -44,7 +44,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Outbox import org.mariotaku.twidere.util.DataStoreUtils import org.mariotaku.twidere.util.IntentUtils import org.mariotaku.twidere.util.Utils -import org.mariotaku.twidere.util.support.AccountManagerSupport +import org.mariotaku.twidere.util.support.removeAccountSupport /** * Sort and toggle account availability @@ -217,7 +217,7 @@ class AccountsManagerFragment : BaseSupportFragment(), LoaderManager.LoaderCallb when (which) { DialogInterface.BUTTON_POSITIVE -> { val accountKey = account.getAccountKey(am) - AccountManagerSupport.removeAccount(am, account, null, null, null) + am.removeAccountSupport(account) val where = Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY).sql val whereArgs = arrayOf(accountKey.toString()) // Also delete tweets related to the account we previously diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFiltersFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFiltersFragment.kt index 03e4dbcce..2639c233a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFiltersFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFiltersFragment.kt @@ -43,11 +43,13 @@ import android.widget.AutoCompleteTextView import android.widget.ListView import android.widget.TextView import kotlinx.android.synthetic.main.fragment_content_listview.* +import org.mariotaku.ktextension.setItemAvailability import org.mariotaku.sqliteqb.library.Columns.Column import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.sqliteqb.library.RawItemArray import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.* +import org.mariotaku.twidere.activity.AccountSelectorActivity import org.mariotaku.twidere.activity.UserListSelectorActivity import org.mariotaku.twidere.activity.iface.IControlBarActivity import org.mariotaku.twidere.adapter.ComposeAutoCompleteAdapter @@ -59,8 +61,12 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Filters import org.mariotaku.twidere.util.* import org.mariotaku.twidere.util.Utils.getDefaultAccountKey import org.mariotaku.twidere.util.dagger.GeneralComponentHelper +import org.mariotaku.twidere.util.premium.ExtraFeaturesChecker import javax.inject.Inject +private const val REQUEST_IMPORT_BLOCKS_SELECT_ACCOUNT = 201 +private const val REQUEST_IMPORT_MUTES_SELECT_ACCOUNT = 202 + abstract class BaseFiltersFragment : AbsContentListViewFragment(), LoaderManager.LoaderCallbacks, MultiChoiceModeListener { private var actionMode: ActionMode? = null @@ -325,12 +331,25 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment get() = Filters.Users.COLUMNS override val contentUri: Uri get() = Filters.Users.CONTENT_URI + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + extraFeaturesChecker = ExtraFeaturesChecker.instance + extraFeaturesChecker.init(context) + } + + override fun onDestroy() { + extraFeaturesChecker.release() + super.onDestroy() + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { REQUEST_SELECT_USER -> { @@ -344,6 +363,12 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment { + + } + REQUEST_IMPORT_MUTES_SELECT_ACCOUNT -> { + + } } } @@ -351,15 +376,39 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment { + R.id.add_user_single, R.id.add_user -> { val intent = Intent(INTENT_ACTION_SELECT_USER) intent.setClass(context, UserListSelectorActivity::class.java) intent.putExtra(EXTRA_ACCOUNT_KEY, getDefaultAccountKey(activity)) startActivityForResult(intent, REQUEST_SELECT_USER) return true } + R.id.import_from_blocked_users, R.id.import_from_muted_users -> { + if (extraFeaturesChecker.isEnabled()) { + val intent = Intent(context, AccountSelectorActivity::class.java) + intent.putExtra(EXTRA_SINGLE_SELECTION, true) + intent.putExtra(EXTRA_SELECT_ONLY_ITEM_AUTOMATICALLY, true) + val requestCode = when (item.itemId) { + R.id.import_from_blocked_users -> REQUEST_IMPORT_BLOCKS_SELECT_ACCOUNT + R.id.import_from_muted_users -> REQUEST_IMPORT_MUTES_SELECT_ACCOUNT + else -> throw AssertionError() + } + startActivityForResult(intent, requestCode) + } else { + val df = ExtraFeaturesIntroductionDialogFragment() + df.show(childFragmentManager, "extra_features_introduction") + } + return true + } } return super.onOptionsItemSelected(item) } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/ExtraFeaturesIntroductionDialogFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/ExtraFeaturesIntroductionDialogFragment.kt new file mode 100644 index 000000000..6f2f43ccf --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/ExtraFeaturesIntroductionDialogFragment.kt @@ -0,0 +1,28 @@ +package org.mariotaku.twidere.fragment + +import android.app.Dialog +import android.os.Bundle +import android.support.v7.app.AlertDialog +import org.mariotaku.twidere.R + +/** + * Created by mariotaku on 2016/12/25. + */ + +class ExtraFeaturesIntroductionDialogFragment : BaseDialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val builder = AlertDialog.Builder(context) + builder.setTitle(R.string.title_extra_features) + builder.setView(R.layout.dialog_extra_features_introduction) + builder.setPositiveButton(R.string.action_purchase) { dialog, which -> + + } + builder.setNegativeButton(R.string.action_later) { dialog, which -> + + } + builder.setNeutralButton(R.string.action_restore_purchase) { dialog, which -> + + } + return builder.create() + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/premium/ExtraFeaturesIntroductionCardFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/premium/ExtraFeaturesIntroductionCardFragment.kt new file mode 100644 index 000000000..f55e16e44 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/premium/ExtraFeaturesIntroductionCardFragment.kt @@ -0,0 +1,32 @@ +package org.mariotaku.twidere.fragment.premium + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.fragment_extra_features_introduction.* +import org.mariotaku.twidere.BuildConfig +import org.mariotaku.twidere.R +import org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_IN_APP_PURCHASE +import org.mariotaku.twidere.fragment.BaseSupportFragment + +/** + * Created by mariotaku on 2016/12/25. + */ + +class ExtraFeaturesIntroductionCardFragment : BaseSupportFragment() { + + // MARK: Fragment lifecycle + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + purchaseButton.setOnClickListener { + startActivity(Intent(INTENT_ACTION_IN_APP_PURCHASE).setPackage(BuildConfig.APPLICATION_ID)) + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_extra_features_introduction, container, false) + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/loader/CursorSupportUsersLoader.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/loader/CursorSupportUsersLoader.kt index 94bd83171..6756c97ee 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/loader/CursorSupportUsersLoader.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/loader/CursorSupportUsersLoader.kt @@ -93,8 +93,8 @@ abstract class CursorSupportUsersLoader( val users: List if (useIDs(details)) { val ids = getIDs(twitter, details, paging) - setCursors(ids) users = twitter.lookupUsers(ids.iDs) + setCursors(ids) } else { users = getCursoredUsers(twitter, details, paging) if (users is CursorSupport) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/premium/ExtraFeaturesChecker.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/premium/ExtraFeaturesChecker.kt new file mode 100644 index 000000000..5aff9e0ef --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/premium/ExtraFeaturesChecker.kt @@ -0,0 +1,32 @@ +package org.mariotaku.twidere.util.premium + +import android.content.Context +import android.support.annotation.CallSuper +import java.util.* + +/** + * Created by mariotaku on 2016/12/25. + */ + +abstract class ExtraFeaturesChecker { + protected lateinit var context: Context + + @CallSuper + open fun init(context: Context) { + this.context = context + } + + open fun release() { + } + + abstract fun isSupported(): Boolean + + abstract fun isEnabled(): Boolean + + companion object { + + val instance: ExtraFeaturesChecker + get() = ServiceLoader.load(ExtraFeaturesChecker::class.java).first() + + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/support/AccountManagerSupport.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/support/AccountManagerSupport.kt new file mode 100644 index 000000000..e769c40fd --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/support/AccountManagerSupport.kt @@ -0,0 +1,72 @@ +package org.mariotaku.twidere.util.support + +import android.accounts.* +import android.app.Activity +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.support.annotation.RequiresApi +import java.io.IOException +import java.util.concurrent.TimeUnit + +/** + * Created by mariotaku on 2016/12/2. + */ + +fun AccountManager.removeAccountSupport( + account: Account, + activity: Activity? = null, + callback: AccountManagerCallback? = null, + handler: Handler? = null +): AccountManagerFuture { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + return AccountManagerSupportL.removeAccount(this, account, activity, callback, handler) + } + + val future = this.removeAccount(account, { future -> + callback?.run(BooleanToBundleAccountManagerFuture(future)) + }, handler) + return BooleanToBundleAccountManagerFuture(future) +} + +object AccountManagerSupportL { + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1) + internal fun removeAccount( + am: AccountManager, account: Account, + activity: Activity?, + callback: AccountManagerCallback?, + handler: Handler? + ): AccountManagerFuture { + return am.removeAccount(account, activity, callback, handler) + } + +} + +private class BooleanToBundleAccountManagerFuture internal constructor(private val future: AccountManagerFuture) : AccountManagerFuture { + + override fun cancel(mayInterruptIfRunning: Boolean): Boolean { + return future.cancel(mayInterruptIfRunning) + } + + override fun isCancelled(): Boolean { + return future.isCancelled + } + + override fun isDone(): Boolean { + return future.isDone + } + + @Throws(OperationCanceledException::class, IOException::class, AuthenticatorException::class) + override fun getResult(): Bundle { + val result = Bundle() + result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, future.result) + return result + } + + @Throws(OperationCanceledException::class, IOException::class, AuthenticatorException::class) + override fun getResult(timeout: Long, unit: TimeUnit): Bundle { + val result = Bundle() + result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, future.getResult(timeout, unit)) + return result + } +} diff --git a/twidere/src/main/res/layout/activity_plus_service_dashboard.xml b/twidere/src/main/res/layout/activity_plus_service_dashboard.xml index 85deb4bb1..e968e2935 100644 --- a/twidere/src/main/res/layout/activity_plus_service_dashboard.xml +++ b/twidere/src/main/res/layout/activity_plus_service_dashboard.xml @@ -1,7 +1,6 @@ - - - - - - - diff --git a/twidere/src/main/res/layout/card_item_extra_features_purchase_introduction.xml b/twidere/src/main/res/layout/card_item_extra_features_purchase_introduction.xml new file mode 100644 index 000000000..463685974 --- /dev/null +++ b/twidere/src/main/res/layout/card_item_extra_features_purchase_introduction.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/layout/card_item_extra_features_sync_status.xml b/twidere/src/main/res/layout/card_item_extra_features_sync_status.xml new file mode 100644 index 000000000..2adeccdd7 --- /dev/null +++ b/twidere/src/main/res/layout/card_item_extra_features_sync_status.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/layout/dialog_extra_features_introduction.xml b/twidere/src/main/res/layout/dialog_extra_features_introduction.xml new file mode 100644 index 000000000..ff5138ff9 --- /dev/null +++ b/twidere/src/main/res/layout/dialog_extra_features_introduction.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/layout/fragment_extra_features_introduction.xml b/twidere/src/main/res/layout/fragment_extra_features_introduction.xml new file mode 100644 index 000000000..10fc90ad0 --- /dev/null +++ b/twidere/src/main/res/layout/fragment_extra_features_introduction.xml @@ -0,0 +1,38 @@ + + + + + + + + + +