1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-09-20 07:31:40 +02:00

Add restore function

This commit is contained in:
Allan Wang 2017-07-02 14:19:50 -07:00
parent 8cc26f47b1
commit b9aab92aee
8 changed files with 92 additions and 37 deletions

View File

@ -44,6 +44,7 @@ import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
import com.pitchedapps.frost.fragments.WebFragment import com.pitchedapps.frost.fragments.WebFragment
import com.pitchedapps.frost.utils.* import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.utils.iab.IAB import com.pitchedapps.frost.utils.iab.IAB
import com.pitchedapps.frost.utils.iab.validatePro
import com.pitchedapps.frost.views.BadgedIcon import com.pitchedapps.frost.views.BadgedIcon
import com.pitchedapps.frost.web.FrostWebViewSearch import com.pitchedapps.frost.web.FrostWebViewSearch
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
@ -133,6 +134,7 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract {
.setAction("Action", null).show() .setAction("Action", null).show()
} }
setFrostColors(toolbar, themeWindow = false, headers = arrayOf(tabs, appBar), backgrounds = arrayOf(viewPager)) setFrostColors(toolbar, themeWindow = false, headers = arrayOf(tabs, appBar), backgrounds = arrayOf(viewPager))
validatePro()
} }
fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) { fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) {
@ -393,11 +395,6 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract {
FbCookie.switchBackUser { } FbCookie.switchBackUser { }
} }
override fun onStart() {
super.onStart()
IAB.setupAsync(this)
}
override fun onBackPressed() { override fun onBackPressed() {
if (searchView?.onBackPressed() ?: false) return if (searchView?.onBackPressed() ?: false) return
if (currentFragment.onBackPressed()) return if (currentFragment.onBackPressed()) return

View File

@ -2,6 +2,7 @@ package com.pitchedapps.frost
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.Snackbar
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import ca.allanwang.kau.changelog.showChangelog import ca.allanwang.kau.changelog.showChangelog
@ -70,16 +71,12 @@ class SettingsActivity : KPrefActivity(), IabBroadcastReceiver.IabBroadcastListe
plainText(R.string.restore_purchases) { plainText(R.string.restore_purchases) {
descRes = R.string.restore_purchases descRes = R.string.restore_purchases
iicon = GoogleMaterial.Icon.gmd_refresh iicon = GoogleMaterial.Icon.gmd_refresh
onClick = { _, _,_ -> this@SettingsActivity.restorePurchases(); true } onClick = { _, _, _ -> this@SettingsActivity.restorePurchases(); true }
} }
plainText(R.string.about_frost) { plainText(R.string.about_frost) {
iicon = GoogleMaterial.Icon.gmd_info iicon = GoogleMaterial.Icon.gmd_info
onClick = { onClick = { _, _, _ -> startActivity(AboutActivity::class.java, transition = true); true }
_, _, _ ->
startActivity(AboutActivity::class.java, transition = true)
true
}
} }
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
@ -142,4 +139,9 @@ class SettingsActivity : KPrefActivity(), IabBroadcastReceiver.IabBroadcastListe
} }
return true return true
} }
override fun onDestroy() {
if (!IAB.isInProgress) IAB.dispose()
super.onDestroy()
}
} }

View File

@ -1,6 +1,5 @@
package com.pitchedapps.frost.utils package com.pitchedapps.frost.utils
import android.graphics.Color
import ca.allanwang.kau.kotlin.lazyResettable import ca.allanwang.kau.kotlin.lazyResettable
import ca.allanwang.kau.kpref.KPref import ca.allanwang.kau.kpref.KPref
import ca.allanwang.kau.kpref.StringSet import ca.allanwang.kau.kpref.StringSet

View File

@ -3,13 +3,14 @@ package com.pitchedapps.frost.utils.iab
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.support.design.widget.Snackbar
import ca.allanwang.kau.utils.isFromGooglePlay import ca.allanwang.kau.utils.isFromGooglePlay
import ca.allanwang.kau.utils.snackbar
import com.crashlytics.android.answers.PurchaseEvent import com.crashlytics.android.answers.PurchaseEvent
import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
import com.pitchedapps.frost.SettingsActivity import com.pitchedapps.frost.SettingsActivity
import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.frostAnswers
/** /**
* Created by Allan Wang on 2017-06-23. * Created by Allan Wang on 2017-06-23.
@ -27,13 +28,14 @@ object IAB {
* and false otherwise * and false otherwise
* *
*/ */
operator fun invoke(activity: Activity, mustHavePlayStore: Boolean = true, onStart: (helper: IabHelper) -> Boolean) { operator fun invoke(activity: Activity, mustHavePlayStore: Boolean = true, onFailed: () -> Unit = {}, onStart: (helper: IabHelper) -> Boolean) {
with(activity) { with(activity) {
if (helper?.mDisposed ?: true) { if (helper?.mDisposed ?: true) {
helper = null helper = null
L.d("IAB setup async") L.d("IAB setup async")
if (!isFrostPlay) { if (!isFrostPlay) {
if (mustHavePlayStore) playStoreNotFound() if (mustHavePlayStore) playStoreNotFound()
onFailed()
return return
} }
try { try {
@ -44,13 +46,17 @@ object IAB {
if (result.isSuccess) { if (result.isSuccess) {
if (onStart(helper!!)) if (onStart(helper!!))
helper!!.disposeWhenFinished() helper!!.disposeWhenFinished()
} else if (mustHavePlayStore) } else {
activity.playStoreGenericError("Setup error: ${result.response} ${result.message}") if (mustHavePlayStore)
activity.playStoreGenericError("Setup error: ${result.response} ${result.message}")
onFailed()
}
} }
} catch (e: Exception) { } catch (e: Exception) {
L.e(e, "IAB error") L.e(e, "IAB error")
if (mustHavePlayStore) if (mustHavePlayStore)
playStoreGenericError(null) playStoreGenericError(null)
onFailed()
} }
} else if (onStart(helper!!)) } else if (onStart(helper!!))
helper!!.disposeWhenFinished() helper!!.disposeWhenFinished()
@ -60,14 +66,21 @@ object IAB {
fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean
= helper?.handleActivityResult(requestCode, resultCode, data) ?: false = helper?.handleActivityResult(requestCode, resultCode, data) ?: false
fun cancel() {
}
/** /**
* Call this after any execution to dispose the helper * Call this after any execution to dispose the helper
* Ensure that async calls have already finished beforehand
*/ */
fun dispose() { fun dispose() {
helper?.disposeWhenFinished() helper?.dispose()
helper = null helper = null
} }
val isInProgress: Boolean
get() = helper?.mAsyncInProgress ?: false
} }
private const val FROST_PRO = "frost_pro" private const val FROST_PRO = "frost_pro"
@ -79,30 +92,60 @@ private val Context.isFrostPlay: Boolean
get() = isFromGooglePlay || BuildConfig.DEBUG get() = isFromGooglePlay || BuildConfig.DEBUG
fun SettingsActivity.restorePurchases() { fun SettingsActivity.restorePurchases() {
validatePro(this) //like validate, but with a snackbar and without other prompts
var restore: Snackbar? = null
restore = container.snackbar(R.string.restoring_purchases, Snackbar.LENGTH_INDEFINITE) {
setAction(R.string.kau_close) { restore?.dismiss() }
}
//called if inventory is not properly retrieved
val reset = {
if (Prefs.previouslyPro) {
Prefs.previouslyPro = false
Prefs.theme = Theme.DEFAULT.ordinal
}
finishRestore(restore)
}
getInventory(false, true, reset) {
val proSku = it.getSkuDetails(FROST_PRO)
Prefs.previouslyPro = proSku != null
finishRestore(restore)
}
}
private fun SettingsActivity.finishRestore(snackbar: Snackbar?) {
snackbar?.dismiss()
materialDialogThemed {
title(R.string.purchases_restored)
content(if (Prefs.previouslyPro) R.string.purchases_restored_with_pro else R.string.purchases_restored_without_pro)
positiveText(R.string.reload)
dismissListener { adapter.notifyAdapterDataSetChanged() }
}
} }
/** /**
* If user has pro, check if it's valid and destroy the helper * If user has pro, check if it's valid and destroy the helper
*/ */
fun Activity.validatePro(activity: Activity) { fun Activity.validatePro() {
IAB(activity, Prefs.previouslyPro) { //if pro, ensure that it is in inventory; if not, check quietly if it exists getInventory(Prefs.previouslyPro, true, { if (Prefs.previouslyPro) playStoreNoLongerPro() }) {
val proSku = it.getSkuDetails(FROST_PRO)
if (proSku == null && Prefs.previouslyPro) playStoreNoLongerPro()
else if (proSku != null && !Prefs.previouslyPro) playStoreFoundPro()
}
}
fun Activity.getInventory(
mustHavePlayStore: Boolean = true,
disposeOnFinish: Boolean = true,
onFailed: () -> Unit = {},
onSuccess: (inv: Inventory) -> Unit) {
IAB(this, mustHavePlayStore, onFailed) {
helper -> helper ->
with(activity) { helper.queryInventoryAsync {
helper.queryInventoryAsync { res, inv ->
res, inv -> if (res.isFailure || inv == null) onFailed()
if (res.isFailure) return@queryInventoryAsync playStoreGenericError("Query res error") else onSuccess(inv)
if (inv?.getSkuDetails(FROST_PRO) != null) {
//owns pro
if (!Prefs.previouslyPro)
playStoreFoundPro()
} else if (Prefs.previouslyPro) {
//doesn't own pro but has it
playStoreNoLongerPro()
}
}
} }
true disposeOnFinish
} }
} }

View File

@ -103,4 +103,12 @@ fun Activity.playStorePurchasedSuccessfully(key: String) {
content(R.string.play_purchased_pro) content(R.string.play_purchased_pro)
positiveText(R.string.kau_ok) positiveText(R.string.kau_ok)
} }
}
fun SettingsActivity.purchaseRestored() {
materialDialogThemed {
title(R.string.play_thank_you)
content(R.string.play_purchased_pro)
positiveText(R.string.kau_ok)
}
} }

View File

@ -60,6 +60,10 @@
<string name="play_already_purchased_content">Looks like you\'ve already purchased %s. Enjoy!</string> <string name="play_already_purchased_content">Looks like you\'ve already purchased %s. Enjoy!</string>
<string name="found_pro">Found Frost Pro!</string> <string name="found_pro">Found Frost Pro!</string>
<string name="found_pro_desc">Looks like you have frost pro! We\'ll reload the app so you can enjoy the awesome features!</string> <string name="found_pro_desc">Looks like you have frost pro! We\'ll reload the app so you can enjoy the awesome features!</string>
<string name="restoring_purchases">Restoring purchases…</string>
<string name="purchases_restored">Purchases Restored</string>
<string name="purchases_restored_with_pro">Frost Pro has been restored. Enjoy the features!</string>
<string name="purchases_restored_without_pro">It seems like you don\'t have pro. If this is a persistent issue, contact me and attach your purchase receipt.</string>
<string name="define_dbflow"></string> <string name="define_dbflow"></string>
<!-- Author section --> <!-- Author section -->

View File

@ -1,5 +1,7 @@
# Changelog # Changelog
## v1.1
## v1.0 ## v1.0
* Added more global preferences * Added more global preferences
* Added fully customizable theme engine * Added fully customizable theme engine

View File

@ -17,7 +17,7 @@ MIN_SDK=21
TARGET_SDK=26 TARGET_SDK=26
BUILD_TOOLS=26.0.0 BUILD_TOOLS=26.0.0
KAU=e1e3b37000 KAU=f4090285eb
KOTLIN=1.1.3 KOTLIN=1.1.3
MATERIAL_DRAWER=5.9.3 MATERIAL_DRAWER=5.9.3
MATERIAL_DRAWER_KT=1.0.4 MATERIAL_DRAWER_KT=1.0.4