diff options
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/utils')
6 files changed, 138 insertions, 64 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt new file mode 100644 index 00000000..da8672f4 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt @@ -0,0 +1,34 @@ +package com.pitchedapps.frost.utils + +import org.jsoup.Jsoup +import org.jsoup.nodes.Attribute +import org.jsoup.nodes.Element +import org.jsoup.safety.Whitelist + +/** + * Created by Allan Wang on 2017-08-10. + * + * Parses html with Jsoup and cleans the data, emitting just the frame containing debugging info + * + * Removes text, removes unnecessary nodes + */ +fun String.cleanHtml() = cleanText().cleanJsoup() + +internal fun String.cleanText(): String = replace(Regex(">(?s).+?<"), "><") + +internal fun String.cleanJsoup(): String = Jsoup.clean(this, PrivacyWhitelist()) + +class PrivacyWhitelist : Whitelist() { + + val blacklistAttrs = arrayOf("style", "aria-label", "rel") + val blacklistTags = arrayOf("body", "html", "head", "i", "b", "u", "style", "script", + "br", "p", "span", "ul", "ol", "li") + + override fun isSafeAttribute(tagName: String, el: Element, attr: Attribute): Boolean { + val key = attr.key + if (key == "href") attr.setValue("-") + return key !in blacklistAttrs + } + + override fun isSafeTag(tag: String) = tag !in blacklistTags +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt index 16a3d2ae..d5c1a6fb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt @@ -1,9 +1,8 @@ package com.pitchedapps.frost.utils -import android.util.Log -import ca.allanwang.kau.logging.TimberLogger +import ca.allanwang.kau.logging.KauLogger import com.crashlytics.android.Crashlytics -import timber.log.Timber +import com.pitchedapps.frost.BuildConfig /** @@ -16,25 +15,15 @@ import timber.log.Timber * Debug and Error logs must not reveal person info * Person info logs can be marked as info or verbose */ -object L : TimberLogger("Frost") { +object L : KauLogger("Frost") { - /** - * Helper function to separate private info - */ - fun d(tag: String, personal: String?) { - L.d(tag) - L.i("-\t$personal") - } -} - -internal class CrashReportingTree : Timber.Tree() { - override fun log(priority: Int, tag: String?, message: String?, t: Throwable?) { - when (priority) { - Log.VERBOSE, Log.INFO -> return - Log.DEBUG -> if (!Prefs.verboseLogging) return + override fun logImpl(priority: Int, message: String?, privateMessage: String?, t: Throwable?) { + if (BuildConfig.DEBUG) { + super.logImpl(priority, message, privateMessage, t) + } else { + if (message != null) + Crashlytics.log(priority, "Frost", message) + if (t != null) Crashlytics.logException(t) } - if (message != null) - Crashlytics.log(priority, "Frost", message) - if (t != null) Crashlytics.logException(t) } }
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt index b053b9dd..9b8064a4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt @@ -97,8 +97,7 @@ object Prefs : KPref() { var notificationAllAccounts: Boolean by kpref("notification_all_accounts", true) - //todo remove from experimental once stabilized - var notificationsInstantMessages: Boolean by kpref("notification_im", Showcase.experimentalDefault) + var notificationsInstantMessages: Boolean by kpref("notification_im", false) var notificationVibrate: Boolean by kpref("notification_vibrate", true) @@ -106,6 +105,8 @@ object Prefs : KPref() { var notificationLights: Boolean by kpref("notification_lights", true) + var messageScrollToBottom: Boolean by kpref("message_scroll_to_bottom", false) + /** * Cache like value to determine if user has or had pro * In most cases, [com.pitchedapps.frost.utils.iab.IS_FROST_PRO] should be looked at instead @@ -128,4 +129,8 @@ object Prefs : KPref() { var viewpagerSwipe: Boolean by kpref("viewpager_swipe", true) + var loadMediaOnMeteredNetwork: Boolean by kpref("media_on_metered_network", true) + + var debugSettings: Boolean by kpref("debug_settings", false) + } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt index 496a6b5b..e79816f3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -25,7 +25,7 @@ import com.pitchedapps.frost.R import com.pitchedapps.frost.activities.* import com.pitchedapps.frost.dbflow.CookieModel import com.pitchedapps.frost.facebook.FACEBOOK_COM -import com.pitchedapps.frost.facebook.FbTab +import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.formattedFbUrl import java.io.IOException import java.util.* @@ -56,8 +56,8 @@ fun Activity.cookies(): ArrayList<CookieModel> { fun Context.launchWebOverlay(url: String) { val argUrl = url.formattedFbUrl - L.v("Launch received $url") - L.i("Launch web overlay: $argUrl") + L.v("Launch received", url) + L.i("Launch web overlay", argUrl) startActivity(WebOverlayActivity::class.java, false, intentBuilder = { putExtra(ARG_URL, argUrl) }) @@ -74,7 +74,7 @@ fun Activity.launchIntroActivity(cookieList: ArrayList<CookieModel>) = launchNewTask(IntroActivity::class.java, cookieList, true) fun WebOverlayActivity.url(): String { - return intent.extras?.getString(ARG_URL) ?: FbTab.FEED.url + return intent.extras?.getString(ARG_URL) ?: FbItem.FEED.url } fun Context.materialDialogThemed(action: MaterialDialog.Builder.() -> Unit): MaterialDialog { @@ -132,6 +132,15 @@ fun frostAnswersCustom(name: String, vararg events: Pair<String, Any>) { } } +/** + * Helper method to quietly keep track of throwable issues + */ +fun Throwable?.logFrostAnswers(text: String) { + val msg = if (this == null) text else "$text: $message" + L.e(msg) + frostAnswersCustom("Errors", "text" to text, "message" to (this?.message ?: "NA")) +} + fun View.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {}) { Snackbar.make(this, text, Snackbar.LENGTH_LONG).apply { builder() diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt index bad7f8fd..7f6e8a6d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt @@ -9,6 +9,13 @@ import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.frostAnswers +import com.pitchedapps.frost.utils.logFrostAnswers +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.onComplete +import org.jetbrains.anko.uiThread +import java.lang.ref.WeakReference +import java.math.BigDecimal +import java.util.* /** * Created by Allan Wang on 2017-07-22. @@ -33,31 +40,48 @@ interface FrostBilling : BillingProcessor.IBillingHandler { abstract class IABBinder : FrostBilling { var bp: BillingProcessor? = null - var activity: Activity? = null - - override fun Activity.onCreateBilling() { - activity = this - bp = BillingProcessor.newBillingProcessor(this, PUBLIC_BILLING_KEY, this@IABBinder) - bp?.initialize() + lateinit var activityRef: WeakReference<Activity> + val activity + get() = activityRef.get() + + override final fun Activity.onCreateBilling() { + activityRef = WeakReference(this) + doAsync { + bp = BillingProcessor.newBillingProcessor(this@onCreateBilling, PUBLIC_BILLING_KEY, this@IABBinder) + bp?.initialize() + } } override fun onDestroyBilling() { + activityRef.clear() bp?.release() bp = null - activity = null } - override fun onBillingInitialized() = L.d("IAB initialized") + override fun onBillingInitialized() = L.i("IAB initialized") override fun onPurchaseHistoryRestored() = L.d("IAB restored") override fun onProductPurchased(productId: String, details: TransactionDetails?) { - L.d("IAB $productId purchased") - frostAnswers { - logPurchase(PurchaseEvent() - .putItemId(productId) - .putSuccess(true) - ) + bp.doAsync { + L.i("IAB $productId purchased") + val listing = weakRef.get()?.getPurchaseListingDetails(productId) ?: return@doAsync + val currency = try { + Currency.getInstance(listing.currency) + } catch (e: Exception) { + null + } + frostAnswers { + logPurchase(PurchaseEvent().apply { + putItemId(productId) + putSuccess(true) + if (currency != null) { + putCurrency(Currency.getInstance(Locale.getDefault())) + putItemType(productId) + putItemPrice(BigDecimal.valueOf(listing.priceValue)) + } + }) + } } } @@ -67,13 +91,14 @@ abstract class IABBinder : FrostBilling { .putCustomAttribute("result", errorCode.toString()) .putSuccess(false)) } - L.e(error, "IAB error $errorCode") + error.logFrostAnswers("IAB error $errorCode") } override fun onActivityResultBilling(requestCode: Int, resultCode: Int, data: Intent?): Boolean = bp?.handleActivityResult(requestCode, resultCode, data) ?: false override fun purchasePro() { + val bp = this.bp if (bp == null) { frostAnswers { logPurchase(PurchaseEvent() @@ -83,10 +108,12 @@ abstract class IABBinder : FrostBilling { L.eThrow("IAB null bp on purchase attempt") return } - if (!(bp?.isOneTimePurchaseSupported ?: false)) - activity?.playStorePurchaseUnsupported() + val a = activity ?: return + + if (!BillingProcessor.isIabServiceAvailable(a) || !bp.isOneTimePurchaseSupported) + a.playStorePurchaseUnsupported() else - bp?.purchase(activity, FROST_PRO) + bp.purchase(a, FROST_PRO) } } @@ -107,15 +134,18 @@ class IABSettings : IABBinder() { * Attempts to get pro, or launch purchase flow if user doesn't have it */ override fun restorePurchases() { - if (bp == null) return - val load = bp?.loadOwnedPurchasesFromGoogle() ?: return - L.d("IAB settings load from google $load") - if (!(bp?.isPurchased(FROST_PRO) ?: return)) { - if (Prefs.pro) activity.playStoreNoLongerPro() - else purchasePro() - } else { - if (!Prefs.pro) activity.playStoreFoundPro() - else activity?.purchaseRestored() + bp.doAsync { + val load = weakRef.get()?.loadOwnedPurchasesFromGoogle() ?: return@doAsync + L.d("IAB settings load from google $load") + uiThread { + if (!(weakRef.get()?.isPurchased(FROST_PRO) ?: return@uiThread)) { + if (Prefs.pro) activity.playStoreNoLongerPro() + else purchasePro() + } else { + if (!Prefs.pro) activity.playStoreFoundPro() + else activity?.purchaseRestored() + } + } } } } @@ -142,13 +172,17 @@ class IABMain : IABBinder() { override fun restorePurchases() { if (restored || bp == null) return restored = true - val load = bp?.loadOwnedPurchasesFromGoogle() ?: false - L.d("IAB main load from google $load") - if (!(bp?.isPurchased(FROST_PRO) ?: false)) { - if (Prefs.pro) activity.playStoreNoLongerPro() - } else { - if (!Prefs.pro) activity.playStoreFoundPro() + bp.doAsync { + val load = weakRef.get()?.loadOwnedPurchasesFromGoogle() ?: false + L.d("IAB main load from google $load") + onComplete { + if (!(weakRef.get()?.isPurchased(FROST_PRO) ?: false)) { + if (Prefs.pro) activity.playStoreNoLongerPro() + } else { + if (!Prefs.pro) activity.playStoreFoundPro() + } + onDestroyBilling() + } } - onDestroyBilling() } }
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt index df0f04fd..e997731b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt @@ -2,6 +2,7 @@ package com.pitchedapps.frost.utils.iab import android.app.Activity import ca.allanwang.kau.utils.restart +import ca.allanwang.kau.utils.startLink import ca.allanwang.kau.utils.startPlayStoreLink import ca.allanwang.kau.utils.string import com.crashlytics.android.answers.PurchaseEvent @@ -69,9 +70,11 @@ fun Activity.playStorePurchaseUnsupported() { materialDialogThemed { title(R.string.uh_oh) content(R.string.play_store_unsupported) - positiveText(R.string.kau_ok) - neutralText(R.string.kau_play_store) - onNeutral { _, _ -> startPlayStoreLink(R.string.play_store_package_id) } + negativeText(R.string.kau_close) + positiveText(R.string.kau_play_store) + neutralText(R.string.paypal) + onPositive { _, _ -> startPlayStoreLink(R.string.play_store_package_id) } + onNeutral { _, _ -> startLink(string(R.string.dev_paypal)) } } } |