diff options
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/utils')
6 files changed, 88 insertions, 65 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt index c5b336bf..ab64ff55 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt @@ -64,8 +64,8 @@ object BiometricUtils { private fun getOrCreatePoolSync(): Executor = pool ?: Executors.newSingleThreadExecutor().also { pool = it } - private fun shouldPrompt(context: Context): Boolean { - return Prefs.biometricsEnabled && System.currentTimeMillis() - lastUnlockTime > UNLOCK_TIME_INTERVAL + private fun shouldPrompt(context: Context, prefs: Prefs): Boolean { + return prefs.biometricsEnabled && System.currentTimeMillis() - lastUnlockTime > UNLOCK_TIME_INTERVAL } /** @@ -73,9 +73,9 @@ object BiometricUtils { * Note that the underlying request will call [androidx.fragment.app.FragmentTransaction.commit], * so this cannot happen after onSaveInstanceState. */ - fun authenticate(activity: FragmentActivity, force: Boolean = false): BiometricDeferred { + fun authenticate(activity: FragmentActivity, prefs: Prefs, force: Boolean = false): BiometricDeferred { val deferred: BiometricDeferred = CompletableDeferred() - if (!force && !shouldPrompt(activity)) { + if (!force && !shouldPrompt(activity, prefs)) { deferred.complete(null) return deferred } 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 389cb6b7..974047e8 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt @@ -16,7 +16,6 @@ */ package com.pitchedapps.frost.utils -import android.util.Log import ca.allanwang.kau.logging.KauLogger import ca.allanwang.kau.logging.KauLoggerExtension import com.bugsnag.android.Bugsnag @@ -27,13 +26,7 @@ import com.pitchedapps.frost.BuildConfig * * Logging for frost */ -object L : KauLogger("Frost", { - when (it) { - Log.VERBOSE -> BuildConfig.DEBUG - Log.INFO, Log.ERROR -> true - else -> BuildConfig.DEBUG || Prefs.verboseLogging - } -}) { +object L : KauLogger("Frost") { inline fun test(message: () -> Any?) { _d { @@ -59,7 +52,7 @@ object L : KauLogger("Frost", { } } - var bugsnagInit = false + var hasAnalytics: () -> Boolean = { false } override fun logImpl(priority: Int, message: String?, t: Throwable?) { /* @@ -67,7 +60,7 @@ object L : KauLogger("Frost", { * bugsnagInit is changed per application and helps prevent crashes (if calling pre init) * analytics is changed by the user, and may be toggled throughout the app */ - if (BuildConfig.DEBUG || !bugsnagInit || !Prefs.analytics) { + if (BuildConfig.DEBUG || !hasAnalytics()) { super.logImpl(priority, message, t) } else { if (message != null) { 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 eb8e4b35..8052533b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt @@ -19,6 +19,7 @@ package com.pitchedapps.frost.utils import android.graphics.Color import ca.allanwang.kau.kotlin.lazyResettable import ca.allanwang.kau.kpref.KPref +import ca.allanwang.kau.kpref.KPrefFactory import ca.allanwang.kau.utils.colorToForeground import ca.allanwang.kau.utils.isColorVisibleOn import ca.allanwang.kau.utils.withAlpha @@ -29,13 +30,15 @@ import com.pitchedapps.frost.enums.FeedSort import com.pitchedapps.frost.enums.MainActivityLayout import com.pitchedapps.frost.enums.Theme import com.pitchedapps.frost.injectors.InjectorContract +import org.koin.core.context.GlobalContext +import org.koin.dsl.module /** * Created by Allan Wang on 2017-05-28. * * Shared Preference object with lazy cached retrievals */ -object Prefs : KPref() { +class Prefs(factory: KPrefFactory) : KPref("${BuildConfig.APPLICATION_ID}.prefs", factory) { var lastLaunch: Long by kpref("last_launch", -1L) @@ -69,15 +72,15 @@ object Prefs : KPref() { var identifier: Int by kpref("identifier", -1) - private val loader = lazyResettable { Theme.values[Prefs.theme] } + private val loader = lazyResettable { Theme.values[theme] } val t: Theme by loader val textColor: Int - get() = t.textColor + get() = t.textColorGetter(this) val accentColor: Int - get() = t.accentColor + get() = t.accentColorGetter(this) inline val accentColorForWhite: Int get() = when { @@ -87,20 +90,20 @@ object Prefs : KPref() { } inline val nativeBgColor: Int - get() = Prefs.bgColor.withAlpha(30) + get() = bgColor.withAlpha(30) - fun nativeBgColor(unread: Boolean) = Prefs.bgColor + fun nativeBgColor(unread: Boolean) = bgColor .colorToForeground(if (unread) 0.7f else 0.0f) .withAlpha(30) val bgColor: Int - get() = t.bgColor + get() = t.backgroundColorGetter(this) val headerColor: Int - get() = t.headerColor + get() = t.headerColorGetter(this) val iconColor: Int - get() = t.iconColor + get() = t.iconColorGetter(this) val themeInjector: InjectorContract get() = t.injector @@ -155,6 +158,10 @@ object Prefs : KPref() { var enablePip: Boolean by kpref("enable_pip", true) + /** + * Despite the naming, this toggle currently only enables debug logging. + * Verbose is never logged in release builds. + */ var verboseLogging: Boolean by kpref("verbose_logging", false) var analytics: Boolean by kpref("analytics", false) { @@ -194,5 +201,11 @@ object Prefs : KPref() { inline val mainActivityLayout: MainActivityLayout get() = MainActivityLayout(mainActivityLayoutType) - override fun deleteKeys() = arrayOf("search_bar") + companion object { + fun get(): Prefs = GlobalContext.get().koin.get() + + fun module() = module { + single { Prefs(get()) } + } + } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt index edbe7682..423eda97 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt @@ -17,18 +17,25 @@ package com.pitchedapps.frost.utils import ca.allanwang.kau.kpref.KPref +import ca.allanwang.kau.kpref.KPrefFactory +import com.pitchedapps.frost.BuildConfig +import org.koin.dsl.module /** * Created by Allan Wang on 2017-07-03. * * Showcase prefs that offer one time helpers to guide new users */ -object Showcase : KPref() { +class Showcase(factory: KPrefFactory) : KPref("${BuildConfig.APPLICATION_ID}.showcase", factory) { // check if this is the first time launching the web overlay; show snackbar if true val firstWebOverlay: Boolean by kprefSingle("first_web_overlay") val intro: Boolean by kprefSingle("intro_pages") - override fun deleteKeys() = arrayOf("shown_release", "experimental_by_default") + companion object { + fun module() = module { + single { Showcase(get()) } + } + } } 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 66cc6a9e..1f266eb9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -123,27 +123,34 @@ fun Activity.cookies(): ArrayList<CookieEntity> { * Note that most requests may need to first check if the url can be launched as an overlay * See [requestWebOverlay] to verify the launch */ -private inline fun <reified T : WebOverlayActivityBase> Context.launchWebOverlayImpl(url: String) { +private inline fun <reified T : WebOverlayActivityBase> Context.launchWebOverlayImpl( + url: String, + fbCookie: FbCookie +) { + val prefs = Prefs.get() val argUrl = url.formattedFbUrl L.v { "Launch received: $url\nLaunch web overlay: $argUrl" } if (argUrl.isFacebookUrl && argUrl.contains("/logout.php")) { L.d { "Logout php found" } ctxCoroutine.launch { - FbCookie.logout(this@launchWebOverlayImpl) + fbCookie.logout(this@launchWebOverlayImpl) } - } else if (!(Prefs.linksInDefaultApp && resolveActivityForUri(Uri.parse(argUrl)))) + } else if (!(prefs.linksInDefaultApp && resolveActivityForUri(Uri.parse(argUrl)))) { startActivity<T>(false, intentBuilder = { putExtra(ARG_URL, argUrl) }) + } } -fun Context.launchWebOverlay(url: String) = launchWebOverlayImpl<WebOverlayActivity>(url) +fun Context.launchWebOverlay(url: String, fbCookie: FbCookie) = + launchWebOverlayImpl<WebOverlayActivity>(url, fbCookie) // TODO Currently, default is overlay. Switch this if default changes -fun Context.launchWebOverlayDesktop(url: String) = launchWebOverlay(url) +fun Context.launchWebOverlayDesktop(url: String, fbCookie: FbCookie) = + launchWebOverlay(url, fbCookie) -fun Context.launchWebOverlayMobile(url: String) = - launchWebOverlayImpl<WebOverlayMobileActivity>(url) +fun Context.launchWebOverlayMobile(url: String, fbCookie: FbCookie) = + launchWebOverlayImpl<WebOverlayMobileActivity>(url, fbCookie) private fun Context.fadeBundle() = ActivityOptions.makeCustomAnimation( this, @@ -172,16 +179,17 @@ fun WebOverlayActivity.url(): String { } fun Activity.setFrostTheme(forceTransparent: Boolean = false) { + val prefs = Prefs.get() val isTransparent = - forceTransparent || (Color.alpha(Prefs.bgColor) != 255) || (Color.alpha(Prefs.headerColor) != 255) - if (Prefs.bgColor.isColorDark) { + forceTransparent || (Color.alpha(prefs.bgColor) != 255) || (Color.alpha(prefs.headerColor) != 255) + if (prefs.bgColor.isColorDark) { setTheme(if (isTransparent) R.style.FrostTheme_Transparent else R.style.FrostTheme) } else { setTheme(if (isTransparent) R.style.FrostTheme_Light_Transparent else R.style.FrostTheme_Light) } } -class ActivityThemeUtils { +class ActivityThemeUtils(val prefs: Prefs) { private var toolbar: Toolbar? = null var themeWindow = true @@ -207,21 +215,21 @@ class ActivityThemeUtils { fun theme(activity: Activity) { with(activity) { - statusBarColor = Prefs.headerColor.darken(0.1f).withAlpha(255) - if (Prefs.tintNavBar) navigationBarColor = Prefs.headerColor - if (themeWindow) window.setBackgroundDrawable(ColorDrawable(Prefs.bgColor)) - toolbar?.setBackgroundColor(Prefs.headerColor) - toolbar?.setTitleTextColor(Prefs.iconColor) - toolbar?.overflowIcon?.setTint(Prefs.iconColor) - texts.forEach { it.setTextColor(Prefs.textColor) } - headers.forEach { it.setBackgroundColor(Prefs.headerColor) } - backgrounds.forEach { it.setBackgroundColor(Prefs.bgColor) } + statusBarColor = prefs.headerColor.darken(0.1f).withAlpha(255) + if (prefs.tintNavBar) navigationBarColor = prefs.headerColor + if (themeWindow) window.setBackgroundDrawable(ColorDrawable(prefs.bgColor)) + toolbar?.setBackgroundColor(prefs.headerColor) + toolbar?.setTitleTextColor(prefs.iconColor) + toolbar?.overflowIcon?.setTint(prefs.iconColor) + texts.forEach { it.setTextColor(prefs.textColor) } + headers.forEach { it.setBackgroundColor(prefs.headerColor) } + backgrounds.forEach { it.setBackgroundColor(prefs.bgColor) } } } } -inline fun Activity.setFrostColors(builder: ActivityThemeUtils.() -> Unit) { - val themer = ActivityThemeUtils() +inline fun Activity.setFrostColors(prefs: Prefs, builder: ActivityThemeUtils.() -> Unit) { + val themer = ActivityThemeUtils(prefs) themer.builder() themer.theme(this) } @@ -248,18 +256,20 @@ fun View.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {}) @SuppressLint("RestrictedApi") private inline fun frostSnackbar(crossinline builder: Snackbar.() -> Unit): Snackbar.() -> Unit = { + val prefs = Prefs.get() builder() // hacky workaround, but it has proper checks and shouldn't crash ((view as? FrameLayout)?.getChildAt(0) as? SnackbarContentLayout)?.apply { - messageView.setTextColor(Prefs.textColor) - actionView.setTextColor(Prefs.accentColor) + messageView.setTextColor(prefs.textColor) + actionView.setTextColor(prefs.accentColor) // only set if previous text colors are set - view.setBackgroundColor(Prefs.bgColor.withAlpha(255).colorToForeground(0.1f)) + view.setBackgroundColor(prefs.bgColor.withAlpha(255).colorToForeground(0.1f)) } } fun Activity.frostNavigationBar() { - navigationBarColor = if (Prefs.tintNavBar) Prefs.headerColor else Color.BLACK + val prefs = Prefs.get() + navigationBarColor = if (prefs.tintNavBar) prefs.headerColor else Color.BLACK } @Throws(IOException::class) @@ -393,15 +403,14 @@ inline fun Context.sendFrostEmail(subjectId: String, crossinline builder: EmailB } fun EmailBuilder.addFrostDetails() { - addItem("Prev version", Prefs.prevVersionCode.toString()) + val prefs = Prefs.get() + addItem("Prev version", prefs.prevVersionCode.toString()) val proTag = "FO" // if (IS_FROST_PRO) "TY" else "FP" - addItem("Random Frost ID", "${Prefs.frostId}-$proTag") + addItem("Random Frost ID", "${prefs.frostId}-$proTag") addItem("Locale", Locale.getDefault().displayName) } -fun frostJsoup(url: String): Document = frostJsoup(FbCookie.webCookie, url) - fun frostJsoup(cookie: String?, url: String): Document = Jsoup.connect(url).run { if (cookie.isNullOrBlank()) this @@ -438,7 +447,7 @@ fun String.unescapeHtml(): String = .replace("\\u003C", "<") .replace("\\\"", "\"") -suspend fun Context.loadAssets(): Unit = coroutineScope { - CssAssets.load(this@loadAssets) +suspend fun Context.loadAssets(prefs: Prefs): Unit = coroutineScope { + CssAssets.load(this@loadAssets, prefs) JsAssets.load(this@loadAssets) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt index 61e2c11f..d6e8f9e9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt @@ -25,12 +25,13 @@ import com.afollestad.materialdialogs.callbacks.onDismiss import com.afollestad.materialdialogs.list.listItems import com.pitchedapps.frost.R import com.pitchedapps.frost.activities.MainActivity +import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.facebook.formattedFbUrl /** * Created by Allan Wang on 2017-07-07. */ -fun Context.showWebContextMenu(wc: WebContext) { +fun Context.showWebContextMenu(wc: WebContext, fbCookie: FbCookie) { if (wc.isEmpty) return var title = wc.url ?: string(R.string.menu) title = @@ -43,7 +44,7 @@ fun Context.showWebContextMenu(wc: WebContext) { materialDialog { title(text = title) listItems(items = menuItems.map { string(it.textId) }) { _, position, _ -> - menuItems[position].onClick(this@showWebContextMenu, wc) + menuItems[position].onClick(this@showWebContextMenu, wc, fbCookie) } onDismiss { // showing the dialog interrupts the touch down event, so we must ensure that the viewpager's swipe is enabled @@ -65,16 +66,16 @@ class WebContext(val unformattedUrl: String?, val text: String?) { enum class WebContextType( val textId: Int, val constraint: (wc: WebContext) -> Boolean, - val onClick: (c: Context, wc: WebContext) -> Unit + val onClick: (c: Context, wc: WebContext, fc: FbCookie) -> Unit ) { OPEN_LINK( R.string.open_link, { it.hasUrl }, - { c, wc -> c.launchWebOverlay(wc.url!!) }), - COPY_LINK(R.string.copy_link, { it.hasUrl }, { c, wc -> c.copyToClipboard(wc.url) }), - COPY_TEXT(R.string.copy_text, { it.hasText }, { c, wc -> c.copyToClipboard(wc.text) }), - SHARE_LINK(R.string.share_link, { it.hasUrl }, { c, wc -> c.shareText(wc.url) }), - DEBUG_LINK(R.string.debug_link, { it.hasUrl }, { c, wc -> + { c, wc, fc -> c.launchWebOverlay(wc.url!!, fc) }), + COPY_LINK(R.string.copy_link, { it.hasUrl }, { c, wc, _ -> c.copyToClipboard(wc.url) }), + COPY_TEXT(R.string.copy_text, { it.hasText }, { c, wc, _ -> c.copyToClipboard(wc.text) }), + SHARE_LINK(R.string.share_link, { it.hasUrl }, { c, wc, _ -> c.shareText(wc.url) }), + DEBUG_LINK(R.string.debug_link, { it.hasUrl }, { c, wc, _ -> c.materialDialog { title(R.string.debug_link) message(R.string.debug_link_desc) |