From fd2cbf25f5744a939ef6245809a1655e013a6420 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 10 Jan 2021 22:29:01 -0800 Subject: Start converting pref colors into themeProvider colors --- .../kotlin/com/pitchedapps/frost/FrostTestApp.kt | 4 +- .../main/kotlin/com/pitchedapps/frost/FrostApp.kt | 4 +- .../frost/activities/BaseMainActivity.kt | 2 +- .../pitchedapps/frost/activities/DebugActivity.kt | 2 +- .../pitchedapps/frost/activities/ImageActivity.kt | 2 +- .../pitchedapps/frost/activities/LoginActivity.kt | 2 +- .../frost/activities/SelectorActivity.kt | 2 +- .../frost/activities/SettingsActivity.kt | 2 + .../frost/activities/TabCustomizerActivity.kt | 2 +- .../frost/activities/WebOverlayActivity.kt | 2 +- .../kotlin/com/pitchedapps/frost/enums/Theme.kt | 30 +++-- .../com/pitchedapps/frost/injectors/CssAsset.kt | 36 +++++ .../com/pitchedapps/frost/injectors/CssAssets.kt | 115 ---------------- .../pitchedapps/frost/injectors/CssSmallAssets.kt | 36 ----- .../pitchedapps/frost/injectors/ThemeProvider.kt | 146 +++++++++++++++++++++ .../pitchedapps/frost/prefs/sections/ThemePrefs.kt | 2 +- .../com/pitchedapps/frost/settings/Appearance.kt | 6 +- .../kotlin/com/pitchedapps/frost/utils/Utils.kt | 11 +- .../com/pitchedapps/frost/web/DebugWebView.kt | 4 +- .../pitchedapps/frost/web/FrostWebViewClients.kt | 4 +- .../pitchedapps/frost/injectors/CssAssetsTest.kt | 32 ----- .../frost/injectors/ThemeProviderTest.kt | 32 +++++ 22 files changed, 265 insertions(+), 213 deletions(-) create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAsset.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/injectors/CssSmallAssets.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/injectors/ThemeProvider.kt delete mode 100644 app/src/test/kotlin/com/pitchedapps/frost/injectors/CssAssetsTest.kt create mode 100644 app/src/test/kotlin/com/pitchedapps/frost/injectors/ThemeProviderTest.kt diff --git a/app/src/androidTest/kotlin/com/pitchedapps/frost/FrostTestApp.kt b/app/src/androidTest/kotlin/com/pitchedapps/frost/FrostTestApp.kt index 5103a0cf..9d0caae6 100644 --- a/app/src/androidTest/kotlin/com/pitchedapps/frost/FrostTestApp.kt +++ b/app/src/androidTest/kotlin/com/pitchedapps/frost/FrostTestApp.kt @@ -23,6 +23,7 @@ import ca.allanwang.kau.kpref.KPrefFactory import ca.allanwang.kau.kpref.KPrefFactoryInMemory import com.pitchedapps.frost.db.FrostDatabase import com.pitchedapps.frost.facebook.FbCookie +import com.pitchedapps.frost.injectors.ThemeProvider import com.pitchedapps.frost.prefs.Prefs import org.junit.rules.TestRule import org.junit.runner.Description @@ -70,7 +71,8 @@ class FrostTestApp : Application() { FrostDatabase.module(), prefFactoryModule(), Prefs.module(), - FbCookie.module() + FbCookie.module(), + ThemeProvider.module() ) ) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt index 40333d25..059b2a0e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt @@ -26,6 +26,7 @@ import ca.allanwang.kau.logging.KL import ca.allanwang.kau.utils.buildIsLollipopAndUp import com.pitchedapps.frost.db.FrostDatabase import com.pitchedapps.frost.facebook.FbCookie +import com.pitchedapps.frost.injectors.ThemeProvider import com.pitchedapps.frost.prefs.Prefs import com.pitchedapps.frost.services.scheduleNotificationsFromPrefs import com.pitchedapps.frost.services.setupNotificationChannels @@ -58,7 +59,8 @@ class FrostApp : Application(), KoinComponent { FrostDatabase.module(), prefFactoryModule(), Prefs.module(), - FbCookie.module() + FbCookie.module(), + ThemeProvider.module() ) ) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt index 0cb037a5..e352b2fc 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt @@ -202,7 +202,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, } drawerWrapperBinding.mainContainer.addView(contentBinding.root) with(contentBinding) { - setFrostColors(prefs) { + setFrostColors { toolbar(toolbar) themeWindow = false header(appbar) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt index 54baa184..6067fa82 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt @@ -71,7 +71,7 @@ class DebugActivity : KauBaseActivity() { } setTitle(R.string.debug_frost) - setFrostColors(prefs) { + setFrostColors { toolbar(toolbar) } debugWebview.loadUrl(FbItem.FEED.url) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt index bcfd9c99..ea81bcde 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -222,7 +222,7 @@ class ImageActivity : KauBaseActivity() { loadError(e) } }) - setFrostColors(prefs) { + setFrostColors { themeWindow = false } dragHelper = ViewDragHelper.create(imageDrag, ViewDragCallback()).apply { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt index be53f2c2..601516de 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -80,7 +80,7 @@ class LoginActivity : BaseActivity() { setContentView(R.layout.activity_login) setSupportActionBar(toolbar) setTitle(R.string.kau_login) - setFrostColors(prefs) { + setFrostColors { toolbar(toolbar) } profileLoader = GlideApp.with(profile) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt index a0e3ae42..33215c7e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt @@ -67,7 +67,7 @@ class SelectorActivity : BaseActivity() { } } }) - setFrostColors(prefs) { + setFrostColors { text(text) background(container) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt index a016ca22..ee0cd669 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt @@ -43,6 +43,7 @@ import com.pitchedapps.frost.R import com.pitchedapps.frost.db.NotificationDao import com.pitchedapps.frost.enums.Support import com.pitchedapps.frost.facebook.FbCookie +import com.pitchedapps.frost.injectors.ThemeProvider import com.pitchedapps.frost.prefs.Prefs import com.pitchedapps.frost.settings.getAppearancePrefs import com.pitchedapps.frost.settings.getBehaviourPrefs @@ -73,6 +74,7 @@ class SettingsActivity : KPrefActivity() { val fbCookie: FbCookie by inject() val notifDao: NotificationDao by inject() val prefs: Prefs by inject() + val themeProvider: ThemeProvider by inject() private var resultFlag = Activity.RESULT_CANCELED diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt index 11126803..589289ab 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt @@ -107,7 +107,7 @@ class TabCustomizerActivity : BaseActivity() { fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, prefs.iconColor) fabCancel.backgroundTintList = ColorStateList.valueOf(prefs.accentColor) fabCancel.setOnClickListener { finish() } - setFrostColors(prefs) { + setFrostColors { themeWindow = true } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt index abc07d57..c21f7362 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt @@ -205,7 +205,7 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT toolbar.navigationIcon = GoogleMaterial.Icon.gmd_close.toDrawable(this, 16, prefs.iconColor) toolbar.setNavigationOnClickListener { finishSlideOut() } - setFrostColors(prefs) { + setFrostColors { toolbar(toolbar) themeWindow = false } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt index bb2514f5..3dccc446 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt @@ -18,11 +18,10 @@ package com.pitchedapps.frost.enums import android.graphics.Color import androidx.annotation.StringRes +import androidx.annotation.VisibleForTesting import com.pitchedapps.frost.R -import com.pitchedapps.frost.injectors.CssAssets -import com.pitchedapps.frost.injectors.InjectorContract -import com.pitchedapps.frost.injectors.JsActions import com.pitchedapps.frost.prefs.sections.ThemePrefs +import java.util.Locale /** * Created by Allan Wang on 2017-06-14. @@ -32,7 +31,7 @@ const val BLUE_LIGHT = 0xff5d86dd.toInt() enum class Theme( @StringRes val textRes: Int, - val injector: InjectorContract, + file: String?, val textColorGetter: (ThemePrefs) -> Int, val accentColorGetter: (ThemePrefs) -> Int, val backgroundColorGetter: (ThemePrefs) -> Int, @@ -41,7 +40,7 @@ enum class Theme( ) { DEFAULT(R.string.kau_default, - JsActions.EMPTY, + null, { 0xde000000.toInt() }, { FACEBOOK_BLUE }, { 0xfffafafa.toInt() }, @@ -49,7 +48,7 @@ enum class Theme( { Color.WHITE }), LIGHT(R.string.kau_light, - CssAssets.MATERIAL_LIGHT, + "material_light", { 0xde000000.toInt() }, { FACEBOOK_BLUE }, { 0xfffafafa.toInt() }, @@ -57,7 +56,7 @@ enum class Theme( { Color.WHITE }), DARK(R.string.kau_dark, - CssAssets.MATERIAL_DARK, + "material_dark", { Color.WHITE }, { BLUE_LIGHT }, { 0xff303030.toInt() }, @@ -65,7 +64,7 @@ enum class Theme( { Color.WHITE }), AMOLED(R.string.kau_amoled, - CssAssets.MATERIAL_AMOLED, + "material_amoled", { Color.WHITE }, { BLUE_LIGHT }, { Color.BLACK }, @@ -73,7 +72,7 @@ enum class Theme( { Color.WHITE }), GLASS(R.string.kau_glass, - CssAssets.MATERIAL_GLASS, + "material_glass", { Color.WHITE }, { BLUE_LIGHT }, { 0x80000000.toInt() }, @@ -81,15 +80,26 @@ enum class Theme( { Color.WHITE }), CUSTOM(R.string.kau_custom, - CssAssets.CUSTOM, + "custom", { it.customTextColor }, { it.customAccentColor }, { it.customBackgroundColor }, { it.customHeaderColor }, { it.customIconColor }); + @VisibleForTesting + internal val file = file?.let { "${it}.css" } + companion object { val values = values() // save one instance operator fun invoke(index: Int) = values[index] } } + +enum class ThemeCategory { + FACEBOOK, MESSENGER + ; + + @VisibleForTesting + internal val folder = name.toLowerCase(Locale.CANADA) +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAsset.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAsset.kt new file mode 100644 index 00000000..b384efad --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAsset.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2020 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 . + */ +package com.pitchedapps.frost.injectors + +import android.webkit.WebView +import com.pitchedapps.frost.prefs.Prefs + +/** + * Small misc inline css assets + */ +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}") + ; + + val injector: JsInjector by lazy { + JsBuilder().css(content).single("css-small-assets-$name").build() + } + + override fun inject(webView: WebView, prefs: Prefs) { + injector.inject(webView, prefs) + } +} 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 e012de3f..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 . - */ -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 - -private const val THEME_FOLDER = "themes" - -/** - * 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) } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssSmallAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssSmallAssets.kt deleted file mode 100644 index 30ee7a8f..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssSmallAssets.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 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 . - */ -package com.pitchedapps.frost.injectors - -import android.webkit.WebView -import com.pitchedapps.frost.prefs.Prefs - -/** - * Small misc inline css assets - */ -enum class CssSmallAssets(private val content: String) : InjectorContract { - FullSizeImage("div._4prr[style*=\"max-width\"][style*=\"max-height\"]{max-width:none !important;max-height:none !important}") - ; - - val injector: JsInjector by lazy { - JsBuilder().css(content).single("css-small-assets-$name").build() - } - - override fun inject(webView: WebView, prefs: Prefs) { - injector.inject(webView, prefs) - } -} 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..5a9576d2 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/ThemeProvider.kt @@ -0,0 +1,146 @@ +/* + * 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 . + */ +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 + +/** + * Created by Allan Wang on 2017-05-31. + * Mapping of the available assets + * The enum name must match the css file name + */ +class ThemeProvider(private val context: Context, private val prefs: Prefs) { + + var theme: Theme = Theme.values[prefs.theme] + + private val injectors: MutableMap = 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}/theme/${file}").bufferedReader() + .use(BufferedReader::readText) + if (theme == Theme.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) + } + 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 module() = org.koin.dsl.module { + single { ThemeProvider(get(), get()) } + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/prefs/sections/ThemePrefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/prefs/sections/ThemePrefs.kt index 84f64435..a5a66ee9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/prefs/sections/ThemePrefs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/prefs/sections/ThemePrefs.kt @@ -106,7 +106,7 @@ class ThemePrefsImpl( private val loader = lazyResettable { Theme.values[theme] } - private val t: Theme by loader + val t: Theme by loader override val textColor: Int get() = t.textColorGetter(this) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt index 65e24ab8..a5f7ec28 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt @@ -27,7 +27,7 @@ import com.pitchedapps.frost.R import com.pitchedapps.frost.activities.SettingsActivity import com.pitchedapps.frost.enums.MainActivityLayout import com.pitchedapps.frost.enums.Theme -import com.pitchedapps.frost.injectors.CssAssets +import com.pitchedapps.frost.injectors.ThemeProvider import com.pitchedapps.frost.utils.REQUEST_NAV import com.pitchedapps.frost.utils.REQUEST_TEXT_ZOOM import com.pitchedapps.frost.utils.frostEvent @@ -44,7 +44,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = { header(R.string.theme_customization) - text(R.string.theme, prefs::theme, { prefs.theme = it }) { + text(R.string.theme, prefs::theme, { prefs.theme = it; themeProvider.setTheme(it) }) { onClick = { materialDialog { title(R.string.theme) @@ -76,7 +76,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = { } fun invalidateCustomTheme() { - CssAssets.CUSTOM.reset() + themeProvider.reset() } colorPicker(R.string.text_color, prefs::customTextColor, { 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 ebefa4ca..63483da0 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -67,7 +67,7 @@ import com.pitchedapps.frost.facebook.FbUrlFormatter.Companion.VIDEO_REDIRECT import com.pitchedapps.frost.facebook.USER_AGENT import com.pitchedapps.frost.facebook.formattedFbUri import com.pitchedapps.frost.facebook.formattedFbUrl -import com.pitchedapps.frost.injectors.CssAssets +import com.pitchedapps.frost.injectors.ThemeProvider import com.pitchedapps.frost.injectors.JsAssets import com.pitchedapps.frost.prefs.Prefs import java.io.File @@ -84,6 +84,8 @@ import org.apache.commons.text.StringEscapeUtils import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject /** * Created by Allan Wang on 2017-06-03. @@ -191,7 +193,10 @@ fun Activity.setFrostTheme(prefs: Prefs, forceTransparent: Boolean = false) { } } -class ActivityThemeUtils(val prefs: Prefs) { +class ActivityThemeUtils : KoinComponent { + + private val prefs: Prefs by inject() + private val themeProvider: ThemeProvider by inject() private var toolbar: Toolbar? = null var themeWindow = true @@ -455,6 +460,6 @@ fun String.unescapeHtml(): String = .replace("\\\"", "\"") suspend fun Context.loadAssets(prefs: Prefs): Unit = coroutineScope { - CssAssets.load(this@loadAssets, prefs) + ThemeProvider.load(this@loadAssets, prefs) JsAssets.load(this@loadAssets) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt index 17ab77a7..c68d3f57 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt @@ -26,7 +26,7 @@ import android.webkit.WebView import ca.allanwang.kau.utils.withAlpha import com.pitchedapps.frost.facebook.USER_AGENT import com.pitchedapps.frost.injectors.CssHider -import com.pitchedapps.frost.injectors.CssSmallAssets +import com.pitchedapps.frost.injectors.CssAsset import com.pitchedapps.frost.injectors.jsInject import com.pitchedapps.frost.prefs.Prefs import com.pitchedapps.frost.utils.L @@ -117,7 +117,7 @@ class DebugWebView @JvmOverloads constructor( (url?.contains("?sk=h_chr") ?: false) && prefs.aggressiveRecents ), - CssSmallAssets.FullSizeImage.maybe(prefs.fullSizeImage), + CssAsset.FullSizeImage.maybe(prefs.fullSizeImage), prefs = prefs ) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt index 324af69b..cf248baf 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt @@ -29,7 +29,7 @@ import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.WWW_FACEBOOK_COM import com.pitchedapps.frost.facebook.formattedFbUrl import com.pitchedapps.frost.injectors.CssHider -import com.pitchedapps.frost.injectors.CssSmallAssets +import com.pitchedapps.frost.injectors.CssAsset import com.pitchedapps.frost.injectors.JsActions import com.pitchedapps.frost.injectors.JsAssets import com.pitchedapps.frost.injectors.jsInject @@ -118,7 +118,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() { CssHider.ADS.maybe(!prefs.showFacebookAds), CssHider.POST_ACTIONS.maybe(!prefs.showPostActions), CssHider.POST_REACTIONS.maybe(!prefs.showPostReactions), - CssSmallAssets.FullSizeImage.maybe(prefs.fullSizeImage), + CssAsset.FullSizeImage.maybe(prefs.fullSizeImage), JsAssets.DOCUMENT_WATCHER, JsAssets.HORIZONTAL_SCROLLING, JsAssets.AUTO_RESIZE_TEXTAREA.maybe(prefs.autoExpandTextBox), diff --git a/app/src/test/kotlin/com/pitchedapps/frost/injectors/CssAssetsTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/injectors/CssAssetsTest.kt deleted file mode 100644 index 8894e5b6..00000000 --- a/app/src/test/kotlin/com/pitchedapps/frost/injectors/CssAssetsTest.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2019 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 . - */ -package com.pitchedapps.frost.injectors - -import java.io.File -import kotlin.test.Test -import kotlin.test.assertTrue - -class CssAssetsTest { - - @Test - fun verifyAssetsExist() { - CssAssets.values().forEach { asset -> - val file = File("src/web/assets/css/${asset.folder}/${asset.file}").absoluteFile - assertTrue(file.exists(), "${asset.name} not found at ${file.path}") - } - } -} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/injectors/ThemeProviderTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/injectors/ThemeProviderTest.kt new file mode 100644 index 00000000..f59980d2 --- /dev/null +++ b/app/src/test/kotlin/com/pitchedapps/frost/injectors/ThemeProviderTest.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2019 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 . + */ +package com.pitchedapps.frost.injectors + +import java.io.File +import kotlin.test.Test +import kotlin.test.assertTrue + +class ThemeProviderTest { + + @Test + fun verifyAssetsExist() { + ThemeProvider.values().forEach { asset -> + val file = File("src/web/assets/css/${asset.folder}/${asset.file}").absoluteFile + assertTrue(file.exists(), "${asset.name} not found at ${file.path}") + } + } +} -- cgit v1.2.3