aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/injectors
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/injectors')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAsset.kt (renamed from app/src/main/kotlin/com/pitchedapps/frost/injectors/CssSmallAssets.kt)2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt115
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/ThemeProvider.kt150
3 files changed, 151 insertions, 116 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssSmallAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAsset.kt
index 30ee7a8f..b384efad 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssSmallAssets.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAsset.kt
@@ -22,7 +22,7 @@ import com.pitchedapps.frost.prefs.Prefs
/**
* Small misc inline css assets
*/
-enum class CssSmallAssets(private val content: String) : InjectorContract {
+enum class CssAsset(private val content: String) : InjectorContract {
FullSizeImage("div._4prr[style*=\"max-width\"][style*=\"max-height\"]{max-width:none !important;max-height:none !important}")
;
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt
deleted file mode 100644
index 5329046f..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2018 Allan Wang
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.pitchedapps.frost.injectors
-
-import android.content.Context
-import android.graphics.Color
-import android.webkit.WebView
-import androidx.annotation.VisibleForTesting
-import ca.allanwang.kau.utils.adjustAlpha
-import ca.allanwang.kau.utils.colorToBackground
-import ca.allanwang.kau.utils.colorToForeground
-import ca.allanwang.kau.utils.toRgbaString
-import ca.allanwang.kau.utils.use
-import ca.allanwang.kau.utils.withAlpha
-import com.pitchedapps.frost.prefs.Prefs
-import com.pitchedapps.frost.utils.L
-import java.io.BufferedReader
-import java.io.FileNotFoundException
-import java.util.Locale
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-
-/**
- * Created by Allan Wang on 2017-05-31.
- * Mapping of the available assets
- * The enum name must match the css file name
- */
-enum class CssAssets(val folder: String = THEME_FOLDER) : InjectorContract {
- MATERIAL_LIGHT, MATERIAL_DARK, MATERIAL_AMOLED, MATERIAL_GLASS, CUSTOM
- ;
-
- @VisibleForTesting
- internal val file = "${name.toLowerCase(Locale.CANADA)}.css"
-
- /**
- * Note that while this can be loaded from any thread, it is typically done through [load]
- */
- private var injector: JsInjector? = null
-
- private fun injector(context: Context, prefs: Prefs): JsInjector =
- injector ?: createInjector(context, prefs).also { injector = it }
-
- /**
- * Note that while this can be loaded from any thread, it is typically done through [load]
- */
- private fun createInjector(context: Context, prefs: Prefs): JsInjector =
- try {
- var content =
- context.assets.open("css/$folder/$file").bufferedReader()
- .use(BufferedReader::readText)
- if (this == CUSTOM) {
- val bt = if (Color.alpha(prefs.bgColor) == 255)
- prefs.bgColor.toRgbaString()
- else
- "transparent"
-
- val bb = prefs.bgColor.colorToForeground(0.35f)
-
- content = content
- .replace("\$T\$", prefs.textColor.toRgbaString())
- .replace("\$TT\$", prefs.textColor.colorToBackground(0.05f).toRgbaString())
- .replace("\$A\$", prefs.accentColor.toRgbaString())
- .replace("\$AT\$", prefs.iconColor.toRgbaString())
- .replace("\$B\$", prefs.bgColor.toRgbaString())
- .replace("\$BT\$", bt)
- .replace("\$BBT\$", bb.withAlpha(51).toRgbaString())
- .replace("\$O\$", prefs.bgColor.withAlpha(255).toRgbaString())
- .replace("\$OO\$", bb.withAlpha(255).toRgbaString())
- .replace("\$D\$", prefs.textColor.adjustAlpha(0.3f).toRgbaString())
- .replace("\$TI\$", bb.withAlpha(60).toRgbaString())
- .replace("\$C\$", bt)
- }
- JsBuilder().css(content).build()
- } catch (e: FileNotFoundException) {
- L.e(e) { "CssAssets file not found" }
- JsInjector(JsActions.EMPTY.function)
- }
-
- override fun inject(webView: WebView, prefs: Prefs) =
- injector(webView.context, prefs).inject(webView, prefs)
-
- fun reset() {
- injector = null
- }
-
- companion object {
-
- // Ensures that all non themes and the selected theme are loaded
- suspend fun load(context: Context, prefs: Prefs) {
- withContext(Dispatchers.IO) {
- val currentTheme = prefs.themeInjector as? CssAssets
- val (themes, others) = values().partition { it.folder == THEME_FOLDER }
- themes.filter { it != currentTheme }.forEach { it.reset() }
- currentTheme?.injector(context, prefs)
- others.forEach { it.injector(context, prefs) }
- }
- }
- }
-}
-
-private const val THEME_FOLDER = "themes"
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/ThemeProvider.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/ThemeProvider.kt
new file mode 100644
index 00000000..570f3719
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/ThemeProvider.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.pitchedapps.frost.injectors
+
+import android.content.Context
+import android.graphics.Color
+import ca.allanwang.kau.utils.adjustAlpha
+import ca.allanwang.kau.utils.colorToBackground
+import ca.allanwang.kau.utils.colorToForeground
+import ca.allanwang.kau.utils.isColorVisibleOn
+import ca.allanwang.kau.utils.toRgbaString
+import ca.allanwang.kau.utils.use
+import ca.allanwang.kau.utils.withAlpha
+import com.pitchedapps.frost.enums.FACEBOOK_BLUE
+import com.pitchedapps.frost.enums.Theme
+import com.pitchedapps.frost.enums.ThemeCategory
+import com.pitchedapps.frost.prefs.Prefs
+import com.pitchedapps.frost.utils.L
+import java.io.BufferedReader
+import java.io.FileNotFoundException
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.koin.core.context.GlobalContext
+
+/**
+ * Provides [InjectorContract] for each [ThemeCategory].
+ * Can be reloaded to take in changes from [Prefs]
+ */
+class ThemeProvider(private val context: Context, private val prefs: Prefs) {
+
+ private var theme: Theme = Theme.values[prefs.theme]
+
+ private val injectors: MutableMap<ThemeCategory, InjectorContract> = mutableMapOf()
+
+ val textColor: Int
+ get() = theme.textColorGetter(prefs)
+
+ val accentColor: Int
+ get() = theme.accentColorGetter(prefs)
+
+ val accentColorForWhite: Int
+ get() = when {
+ accentColor.isColorVisibleOn(Color.WHITE) -> accentColor
+ textColor.isColorVisibleOn(Color.WHITE) -> textColor
+ else -> FACEBOOK_BLUE
+ }
+
+ val nativeBgColor: Int
+ get() = bgColor.withAlpha(30)
+
+ fun nativeBgColor(unread: Boolean) = bgColor
+ .colorToForeground(if (unread) 0.7f else 0.0f)
+ .withAlpha(30)
+
+ val bgColor: Int
+ get() = theme.backgroundColorGetter(prefs)
+
+ val headerColor: Int
+ get() = theme.headerColorGetter(prefs)
+
+ val iconColor: Int
+ get() = theme.iconColorGetter(prefs)
+
+ val isCustomTheme: Boolean
+ get() = theme == Theme.CUSTOM
+
+ /**
+ * Note that while this can be loaded from any thread, it is typically done through [preload]]
+ */
+ fun injector(category: ThemeCategory): InjectorContract =
+ injectors.getOrPut(category) { createInjector(category) }
+
+ /**
+ * Note that while this can be loaded from any thread, it is typically done through [preload]
+ */
+ private fun createInjector(category: ThemeCategory): InjectorContract {
+ val file = theme.file ?: return JsActions.EMPTY
+ try {
+ var content =
+ context.assets.open("css/${category.folder}/themes/$file").bufferedReader()
+ .use(BufferedReader::readText)
+ if (theme == Theme.CUSTOM) {
+ val bt = if (Color.alpha(bgColor) == 255)
+ bgColor.toRgbaString()
+ else
+ "transparent"
+
+ val bb = bgColor.colorToForeground(0.35f)
+
+ content = content
+ .replace("\$T\$", textColor.toRgbaString())
+ .replace("\$TT\$", textColor.colorToBackground(0.05f).toRgbaString())
+ .replace("\$TD\$", textColor.adjustAlpha(0.6f).toRgbaString())
+ .replace("\$A\$", accentColor.toRgbaString())
+ .replace("\$AT\$", iconColor.toRgbaString())
+ .replace("\$B\$", bgColor.toRgbaString())
+ .replace("\$BT\$", bt)
+ .replace("\$BBT\$", bb.withAlpha(51).toRgbaString())
+ .replace("\$O\$", bgColor.withAlpha(255).toRgbaString())
+ .replace("\$OO\$", bb.withAlpha(255).toRgbaString())
+ .replace("\$D\$", textColor.adjustAlpha(0.3f).toRgbaString())
+ .replace("\$TI\$", bb.withAlpha(60).toRgbaString())
+ .replace("\$C\$", bt)
+ }
+ return JsBuilder().css(content).build()
+ } catch (e: FileNotFoundException) {
+ L.e(e) { "CssAssets file not found" }
+ return JsActions.EMPTY
+ }
+ }
+
+ fun setTheme(id: Int) {
+ theme = Theme.values[id]
+ reset()
+ }
+
+ fun reset() {
+ injectors.clear()
+ }
+
+ suspend fun preload() {
+ withContext(Dispatchers.IO) {
+ reset()
+ ThemeCategory.values().forEach { injector(it) }
+ }
+ }
+
+ companion object {
+
+ fun get(): ThemeProvider = GlobalContext.get().get()
+
+ fun module() = org.koin.dsl.module {
+ single { ThemeProvider(get(), get()) }
+ }
+ }
+}