aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/utils
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/utils')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt34
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt31
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt9
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt17
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt102
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt9
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)) }
}
}