aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2021-01-24 22:04:37 -0800
committerGitHub <noreply@github.com>2021-01-24 22:04:37 -0800
commit94aa2dd8125f474570f366408645e5a81236c573 (patch)
tree2952e3ca17872ef10545081a100f16b720f0072a
parent68db99597b68c87f1e0eb2d1feb6b6c63bbff1e9 (diff)
parent35adc9529f1466e3ae45ee1934536f696bc24547 (diff)
downloadfrost-94aa2dd8125f474570f366408645e5a81236c573.tar.gz
frost-94aa2dd8125f474570f366408645e5a81236c573.tar.bz2
frost-94aa2dd8125f474570f366408645e5a81236c573.zip
Merge pull request #1742 from AllanWang/messenger
-rw-r--r--app/build.gradle9
-rw-r--r--app/src/androidTest/kotlin/com/pitchedapps/frost/FrostTestApp.kt4
-rw-r--r--app/src/androidTest/kotlin/com/pitchedapps/frost/db/CookieMigrationTest.kt58
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt8
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt42
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt19
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt28
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt24
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt19
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt30
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt51
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt13
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt6
-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
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt32
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt9
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/prefs/Prefs.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/prefs/sections/ThemePrefs.kt73
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt13
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt73
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt8
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt30
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshLayout.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt115
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt16
-rw-r--r--app/src/main/play/en-US/whatsnew7
-rw-r--r--app/src/main/res/values/strings.xml1
-rw-r--r--app/src/main/res/xml/frost_changelog.xml11
-rw-r--r--app/src/schemas/com.pitchedapps.frost.db.FrostPrivateDatabase/2.json201
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/facebook/FbConstTest.kt53
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/injectors/ThemeProviderTest.kt (renamed from app/src/test/kotlin/com/pitchedapps/frost/injectors/CssAssetsTest.kt)12
-rw-r--r--app/src/web/scss/core/_base.scss22
-rw-r--r--app/src/web/scss/core/_colors.scss1
-rw-r--r--app/src/web/scss/facebook/core/_core_bg.scss (renamed from app/src/web/scss/core/_core_bg.scss)0
-rw-r--r--app/src/web/scss/facebook/core/_core_border.scss (renamed from app/src/web/scss/core/_core_border.scss)0
-rw-r--r--app/src/web/scss/facebook/core/_core_hider.scss4
-rw-r--r--app/src/web/scss/facebook/core/_core_messages.scss (renamed from app/src/web/scss/core/_core_messenger.scss)2
-rw-r--r--app/src/web/scss/facebook/core/_core_text.scss (renamed from app/src/web/scss/core/_core_text.scss)0
-rw-r--r--app/src/web/scss/facebook/core/_main.scss (renamed from app/src/web/scss/core/_main.scss)0
-rw-r--r--app/src/web/scss/facebook/core/_svg.scss (renamed from app/src/web/scss/core/_svg.scss)0
-rw-r--r--app/src/web/scss/facebook/core/core.scss (renamed from app/src/web/scss/core/core.scss)14
-rw-r--r--app/src/web/scss/facebook/themes/.gitignore (renamed from app/src/web/scss/themes/.gitignore)0
-rw-r--r--app/src/web/scss/facebook/themes/custom.scss2
-rw-r--r--app/src/web/scss/facebook/themes/default.scss1
-rw-r--r--app/src/web/scss/facebook/themes/material_amoled.scss2
-rw-r--r--app/src/web/scss/facebook/themes/material_dark.scss2
-rw-r--r--app/src/web/scss/facebook/themes/material_glass.scss2
-rw-r--r--app/src/web/scss/facebook/themes/material_light.scss2
-rw-r--r--app/src/web/scss/messenger/core/_core_bg.scss4
-rw-r--r--app/src/web/scss/messenger/core/_core_border.scss3
-rw-r--r--app/src/web/scss/messenger/core/_core_hider.scss15
-rw-r--r--app/src/web/scss/messenger/core/_core_text.scss3
-rw-r--r--app/src/web/scss/messenger/core/_core_vars.scss34
-rw-r--r--app/src/web/scss/messenger/core/_main.scss3
-rw-r--r--app/src/web/scss/messenger/core/core.scss11
-rw-r--r--app/src/web/scss/messenger/themes/.gitignore1
-rw-r--r--app/src/web/scss/messenger/themes/custom.scss2
-rw-r--r--app/src/web/scss/messenger/themes/default.scss1
-rw-r--r--app/src/web/scss/messenger/themes/material_amoled.scss2
-rw-r--r--app/src/web/scss/messenger/themes/material_dark.scss2
-rw-r--r--app/src/web/scss/messenger/themes/material_glass.scss2
-rw-r--r--app/src/web/scss/messenger/themes/material_light.scss2
-rw-r--r--app/src/web/scss/palette/_custom.scss (renamed from app/src/web/scss/themes/custom.scss)3
-rw-r--r--app/src/web/scss/palette/_material_amoled.scss (renamed from app/src/web/scss/themes/material_amoled.scss)2
-rw-r--r--app/src/web/scss/palette/_material_dark.scss (renamed from app/src/web/scss/themes/material_dark.scss)2
-rw-r--r--app/src/web/scss/palette/_material_glass.scss (renamed from app/src/web/scss/themes/material_glass.scss)4
-rw-r--r--app/src/web/scss/palette/_material_light.scss (renamed from app/src/web/scss/themes/material_light.scss)4
-rw-r--r--buildSrc/src/main/kotlin/Versions.kt2
-rw-r--r--docs/Changelog.md5
96 files changed, 1085 insertions, 509 deletions
diff --git a/app/build.gradle b/app/build.gradle
index c6e1aef8..24fdd28e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,6 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
//apply plugin: 'com.getkeepsafe.dexcount'
apply plugin: 'com.gladed.androidgitversion'
@@ -204,11 +204,6 @@ android {
}
}
- androidExtensions {
- experimental = true
- features = ["parcelize"]
- }
-
}
node {
@@ -314,7 +309,7 @@ dependencies {
implementation "androidx.room:room-ktx:${Versions.room}"
implementation "androidx.room:room-runtime:${Versions.room}"
kapt "androidx.room:room-compiler:${Versions.room}"
- testImplementation "androidx.room:room-testing:${Versions.room}"
+ androidTestImplementation "androidx.room:room-testing:${Versions.room}"
}
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/androidTest/kotlin/com/pitchedapps/frost/db/CookieMigrationTest.kt b/app/src/androidTest/kotlin/com/pitchedapps/frost/db/CookieMigrationTest.kt
new file mode 100644
index 00000000..6ba6e0b6
--- /dev/null
+++ b/app/src/androidTest/kotlin/com/pitchedapps/frost/db/CookieMigrationTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 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.db
+
+import androidx.room.Room
+import androidx.room.testing.MigrationTestHelper
+import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import kotlin.test.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class CookieMigrationTest {
+
+ private val TEST_DB = "cookie_migration_test"
+
+ private val ALL_MIGRATIONS = arrayOf(COOKIES_MIGRATION_1_2)
+
+ val helper: MigrationTestHelper = MigrationTestHelper(
+ InstrumentationRegistry.getInstrumentation(),
+ FrostPrivateDatabase::class.java.canonicalName,
+ FrameworkSQLiteOpenHelperFactory()
+ )
+
+ @Test
+ fun migrateAll() {
+ // Create earliest version of the database.
+ helper.createDatabase(TEST_DB, 1).apply {
+ close()
+ }
+
+ // Open latest version of the database. Room will validate the schema
+ // once all migrations execute.
+ Room.databaseBuilder(
+ InstrumentationRegistry.getInstrumentation().targetContext,
+ FrostPrivateDatabase::class.java,
+ TEST_DB
+ ).addMigrations(*ALL_MIGRATIONS).build().apply {
+ openHelper.writableDatabase
+ close()
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index 40333d25..100aeecb 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
@@ -46,6 +47,7 @@ import org.koin.dsl.module
class FrostApp : Application(), KoinComponent {
private lateinit var prefs: Prefs
+ private lateinit var themeProvider: ThemeProvider
override fun onCreate() {
startKoin {
@@ -58,7 +60,8 @@ class FrostApp : Application(), KoinComponent {
FrostDatabase.module(),
prefFactoryModule(),
Prefs.module(),
- FbCookie.module()
+ FbCookie.module(),
+ ThemeProvider.module()
)
)
}
@@ -67,6 +70,7 @@ class FrostApp : Application(), KoinComponent {
return
}
prefs = get()
+ themeProvider = get()
initPrefs()
L.i { "Begin Frost for Facebook" }
@@ -74,7 +78,7 @@ class FrostApp : Application(), KoinComponent {
super.onCreate()
- setupNotificationChannels(this, prefs)
+ setupNotificationChannels(this, themeProvider)
scheduleNotificationsFromPrefs(prefs)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
index b2031f96..3248eb14 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
@@ -37,6 +37,7 @@ import com.pitchedapps.frost.db.CookieEntity
import com.pitchedapps.frost.db.GenericDao
import com.pitchedapps.frost.db.selectAll
import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.BiometricUtils
import com.pitchedapps.frost.utils.EXTRA_COOKIES
@@ -54,6 +55,7 @@ class StartActivity : KauBaseActivity() {
private val fbCookie: FbCookie by inject()
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
private val cookieDao: CookieDao by inject()
private val genericDao: GenericDao by inject()
@@ -85,7 +87,7 @@ class StartActivity : KauBaseActivity() {
transform = CookieEntity::toSensitiveString
)}"
}
- loadAssets(prefs)
+ loadAssets(themeProvider)
authDefer.await()
when {
cookies.isEmpty() -> launchNewTask<LoginActivity>()
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt
index 17cac703..74d876cb 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt
@@ -47,9 +47,11 @@ import com.mikepenz.iconics.typeface.library.community.material.CommunityMateria
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import org.koin.android.ext.android.inject
+import org.koin.core.component.inject
/**
* Created by Allan Wang on 2017-06-26.
@@ -57,12 +59,13 @@ import org.koin.android.ext.android.inject
class AboutActivity : AboutActivityBase(null) {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
override fun Configs.buildConfigs() {
- textColor = prefs.textColor
- accentColor = prefs.accentColor
- backgroundColor = prefs.bgColor.withMinAlpha(200)
- cutoutForeground = prefs.accentColor
+ textColor = themeProvider.textColor
+ accentColor = themeProvider.accentColor
+ backgroundColor = themeProvider.bgColor.withMinAlpha(200)
+ cutoutForeground = themeProvider.accentColor
cutoutDrawableRes = R.drawable.frost_f_200
faqPageTitleRes = R.string.faq_title
faqXmlRes = R.xml.frost_faq
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
index d2ba0a92..0553086c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
@@ -22,9 +22,11 @@ import ca.allanwang.kau.internal.KauBaseActivity
import ca.allanwang.kau.searchview.SearchViewHolder
import com.pitchedapps.frost.contracts.VideoViewHolder
import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.setFrostTheme
import org.koin.android.ext.android.inject
+import org.koin.core.component.inject
/**
* Created by Allan Wang on 2017-06-12.
@@ -33,6 +35,7 @@ abstract class BaseActivity : KauBaseActivity() {
val fbCookie: FbCookie by inject()
val prefs: Prefs by inject()
+ val themeProvider: ThemeProvider by inject()
/**
* Inherited consumer to customize back press
@@ -48,7 +51,7 @@ abstract class BaseActivity : KauBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (this !is WebOverlayActivityBase) setFrostTheme(prefs)
+ if (this !is WebOverlayActivityBase) setFrostTheme(themeProvider)
}
override fun onStop() {
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..394969cb 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)
@@ -210,7 +210,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
setSupportActionBar(toolbar)
viewpager.adapter = adapter
- tabs.setBackgroundColor(prefs.mainActivityLayout.backgroundColor(prefs))
+ tabs.setBackgroundColor(prefs.mainActivityLayout.backgroundColor(themeProvider))
}
onNestedCreate(savedInstanceState)
L.i { "Main finished loading UI in ${System.currentTimeMillis() - start} ms" }
@@ -288,7 +288,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
drawer.addDrawerListener(toggle)
toggle.syncState()
- val foregroundColor = ColorStateList.valueOf(prefs.textColor)
+ val foregroundColor = ColorStateList.valueOf(themeProvider.textColor)
with(navigation) {
FrostMenuBuilder(this@BaseMainActivity, menu).apply {
@@ -317,9 +317,9 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
launchWebOverlay(item.url, fbCookie, prefs)
false
}
- val navBg = prefs.bgColor.withMinAlpha(200)
+ val navBg = themeProvider.bgColor.withMinAlpha(200)
setBackgroundColor(navBg)
- itemBackground = createNavDrawable(prefs.accentColor, navBg)
+ itemBackground = createNavDrawable(themeProvider.accentColor, navBg)
itemTextColor = foregroundColor
itemIconTintList = foregroundColor
@@ -331,7 +331,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
private fun ActivityMainContentBinding.initFab() {
hasFab = false
shouldShow = false
- fab.backgroundTintList = ColorStateList.valueOf(prefs.headerColor.withMinAlpha(200))
+ fab.backgroundTintList = ColorStateList.valueOf(themeProvider.headerColor.withMinAlpha(200))
fab.hide()
appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
if (!hasFab) return@OnOffsetChangedListener
@@ -351,12 +351,12 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
if (shouldShow) {
if (fab.isShown) {
fab.fadeScaleTransition {
- setIcon(iicon, color = prefs.iconColor)
+ setIcon(iicon, color = themeProvider.iconColor)
}
return
}
}
- fab.setIcon(iicon, color = prefs.iconColor)
+ fab.setIcon(iicon, color = themeProvider.iconColor)
fab.showIf(shouldShow)
}
}
@@ -383,7 +383,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
private var pendingUpdate: Boolean = false
private val binding = ViewNavHeaderBinding.inflate(layoutInflater)
val root: View get() = binding.root
- private val optionsBackground = prefs.bgColor.withMinAlpha(200).colorToForeground(
+ private val optionsBackground = themeProvider.bgColor.withMinAlpha(200).colorToForeground(
0.1f
)
@@ -448,7 +448,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
animator.start()
}
- val textColor = prefs.textColor
+ val textColor = themeProvider.textColor
fun TextView.setOptionsIcon(iicon: IIcon) {
setCompoundDrawablesRelativeWithIntrinsicBounds(
@@ -458,7 +458,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
null
)
setTextColor(textColor)
- background = createNavDrawable(prefs.accentColor, optionsBackground)
+ background = createNavDrawable(themeProvider.accentColor, optionsBackground)
}
with(optionsLogout) {
@@ -506,7 +506,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
arrow.setImageDrawable(
GoogleMaterial.Icon.gmd_arrow_drop_down.toDrawable(
this@BaseMainActivity,
- color = prefs.textColor
+ color = themeProvider.textColor
)
)
}
@@ -531,10 +531,10 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
avatarTertiary.setAccount(orderedAccounts.getOrNull(2), false)
optionsAccountsContainer.removeAllViews()
name.text = orderedAccounts.getOrNull(0)?.name
- name.setTextColor(prefs.textColor)
+ name.setTextColor(themeProvider.textColor)
val glide = Glide.with(root)
val accountSize = dimenPixelSize(R.dimen.drawer_account_avatar_size)
- val textColor = prefs.textColor
+ val textColor = themeProvider.textColor
orderedAccounts.forEach { cookie ->
val tv =
TextView(
@@ -568,7 +568,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
})
tv.text = cookie.name
tv.setTextColor(textColor)
- tv.background = createNavDrawable(prefs.accentColor, optionsBackground)
+ tv.background = createNavDrawable(themeProvider.accentColor, optionsBackground)
tv.setOnClickListener {
switchAccount(cookie.id)
}
@@ -626,9 +626,9 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
- contentBinding.toolbar.tint(prefs.iconColor)
+ contentBinding.toolbar.tint(themeProvider.iconColor)
setMenuIcons(
- menu, prefs.iconColor,
+ menu, themeProvider.iconColor,
R.id.action_settings to GoogleMaterial.Icon.gmd_settings,
R.id.action_search to GoogleMaterial.Icon.gmd_search
)
@@ -638,7 +638,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
private fun bindSearchView(menu: Menu) {
searchViewBindIfNull {
- bindSearchView(menu, R.id.action_search, prefs.iconColor) {
+ bindSearchView(menu, R.id.action_search, themeProvider.iconColor) {
textCallback = { query, searchView ->
val results = searchViewCache[query]
if (results != null)
@@ -671,8 +671,8 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
); true
}
closeListener = { _ -> searchViewCache.clear() }
- foregroundColor = prefs.textColor
- backgroundColor = prefs.bgColor.withMinAlpha(200)
+ foregroundColor = themeProvider.textColor
+ backgroundColor = themeProvider.bgColor.withMinAlpha(200)
onItemClick = { _, key, _, _ -> launchWebOverlay(key, fbCookie, prefs) }
}
}
@@ -731,7 +731,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
fragmentChannel.offer(REQUEST_REFRESH)
}
if (hasRequest(REQUEST_NAV)) {
- frostNavigationBar(prefs)
+ frostNavigationBar(prefs, themeProvider)
}
if (hasRequest(REQUEST_TEXT_ZOOM)) {
fragmentChannel.offer(REQUEST_TEXT_ZOOM)
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..935b88c9 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
@@ -30,7 +30,7 @@ import com.pitchedapps.frost.R
import com.pitchedapps.frost.databinding.ActivityDebugBinding
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.injectors.JsActions
-import com.pitchedapps.frost.prefs.Prefs
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.createFreshDir
import com.pitchedapps.frost.utils.setFrostColors
@@ -39,6 +39,7 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineExceptionHandler
import org.koin.android.ext.android.inject
+import org.koin.core.component.inject
/**
* Created by Allan Wang on 05/01/18.
@@ -52,7 +53,7 @@ class DebugActivity : KauBaseActivity() {
fun baseDir(context: Context) = File(context.externalCacheDir, "offline_debug")
}
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
lateinit var binding: ActivityDebugBinding
@@ -71,7 +72,7 @@ class DebugActivity : KauBaseActivity() {
}
setTitle(R.string.debug_frost)
- setFrostColors(prefs) {
+ setFrostColors {
toolbar(toolbar)
}
debugWebview.loadUrl(FbItem.FEED.url)
@@ -79,8 +80,8 @@ class DebugActivity : KauBaseActivity() {
swipeRefresh.setOnRefreshListener(debugWebview::reload)
- fab.visible().setIcon(GoogleMaterial.Icon.gmd_bug_report, prefs.iconColor)
- fab.backgroundTintList = ColorStateList.valueOf(prefs.accentColor)
+ fab.visible().setIcon(GoogleMaterial.Icon.gmd_bug_report, themeProvider.iconColor)
+ fab.backgroundTintList = ColorStateList.valueOf(themeProvider.accentColor)
fab.setOnClickListener { _ ->
fab.hide()
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 06626752..7b8ee4d3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
@@ -55,6 +55,7 @@ import com.pitchedapps.frost.facebook.get
import com.pitchedapps.frost.facebook.requests.call
import com.pitchedapps.frost.facebook.requests.getFullSizedImageUrl
import com.pitchedapps.frost.facebook.requests.requestBuilder
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.services.LocalService
import com.pitchedapps.frost.utils.ARG_COOKIE
@@ -78,6 +79,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
+import org.koin.core.component.inject
/**
* Created by Allan Wang on 2017-07-15.
@@ -85,6 +87,7 @@ import org.koin.android.ext.android.inject
class ImageActivity : KauBaseActivity() {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
@Volatile
internal var errorRef: Throwable? = null
@@ -128,7 +131,7 @@ class ImageActivity : KauBaseActivity() {
private var bottomBehavior: BottomSheetBehavior<View>? = null
private val baseBackgroundColor = if (prefs.blackMediaBg) Color.BLACK
- else prefs.bgColor.withMinAlpha(235)
+ else themeProvider.bgColor.withMinAlpha(235)
private fun loadError(e: Throwable) {
if (e.message?.contains("<!DOCTYPE html>") == true) {
@@ -178,7 +181,7 @@ class ImageActivity : KauBaseActivity() {
if (text.isNullOrBlank()) {
imageText.gone()
} else {
- imageText.setTextColor(if (prefs.blackMediaBg) Color.WHITE else prefs.textColor)
+ imageText.setTextColor(if (prefs.blackMediaBg) Color.WHITE else themeProvider.textColor)
imageText.setBackgroundColor(
baseBackgroundColor.colorToForeground(0.2f).withAlpha(255)
)
@@ -197,7 +200,7 @@ class ImageActivity : KauBaseActivity() {
imageText.bringToFront()
}
}
- val foregroundTint = if (prefs.blackMediaBg) Color.WHITE else prefs.accentColor
+ val foregroundTint = if (prefs.blackMediaBg) Color.WHITE else themeProvider.accentColor
fun ImageView.setState(state: FabStates) {
setIcon(state.iicon, color = foregroundTint, sizeDp = 24)
@@ -221,7 +224,7 @@ class ImageActivity : KauBaseActivity() {
loadError(e)
}
})
- setFrostColors(prefs) {
+ setFrostColors {
themeWindow = false
}
dragHelper = ViewDragHelper.create(imageDrag, ViewDragCallback()).apply {
@@ -352,7 +355,7 @@ class ImageActivity : KauBaseActivity() {
internal enum class FabStates(
val iicon: IIcon,
- val iconColorProvider: (Prefs) -> Int = { it.iconColor },
+ val iconColorProvider: (ThemeProvider) -> Int = { it.iconColor },
val backgroundTint: Int = Int.MAX_VALUE
) {
ERROR(GoogleMaterial.Icon.gmd_error, { Color.WHITE }, Color.RED) {
@@ -405,9 +408,9 @@ internal enum class FabStates(
* https://github.com/AllanWang/KAU/issues/184
*
*/
- fun update(fab: FloatingActionButton, prefs: Prefs) {
- val tint = if (backgroundTint != Int.MAX_VALUE) backgroundTint else prefs.accentColor
- val iconColor = iconColorProvider(prefs)
+ fun update(fab: FloatingActionButton, themeProvider: ThemeProvider) {
+ val tint = if (backgroundTint != Int.MAX_VALUE) backgroundTint else themeProvider.accentColor
+ val iconColor = iconColorProvider(themeProvider)
if (fab.isHidden) {
fab.setIcon(iicon, color = iconColor)
fab.backgroundTintList = ColorStateList.valueOf(tint)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
index 337c9678..f06c3a37 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
@@ -39,6 +39,7 @@ import ca.allanwang.kau.utils.statusBarColor
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.R
import com.pitchedapps.frost.databinding.ActivityIntroBinding
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.intro.BaseIntroFragment
import com.pitchedapps.frost.intro.IntroAccountFragment
import com.pitchedapps.frost.intro.IntroFragmentEnd
@@ -66,6 +67,7 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer,
ViewPager.OnPageChangeListener {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
lateinit var binding: ActivityIntroBinding
private var barHasNext = true
@@ -98,21 +100,21 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer,
else finish(next.x + next.pivotX, next.y + next.pivotY)
}
skip.setOnClickListener { finish() }
- ripple.set(prefs.bgColor)
+ ripple.set(themeProvider.bgColor)
theme()
}
fun theme() {
- statusBarColor = prefs.headerColor
- navigationBarColor = prefs.headerColor
+ statusBarColor = themeProvider.headerColor
+ navigationBarColor = themeProvider.headerColor
with(binding) {
- skip.setTextColor(prefs.textColor)
- next.imageTintList = ColorStateList.valueOf(prefs.textColor)
- indicator.setColour(prefs.textColor)
+ skip.setTextColor(themeProvider.textColor)
+ next.imageTintList = ColorStateList.valueOf(themeProvider.textColor)
+ indicator.setColour(themeProvider.textColor)
indicator.invalidate()
}
fragments.forEach { it.themeFragment() }
- setFrostTheme(prefs, true)
+ setFrostTheme(themeProvider, true)
}
/**
@@ -150,21 +152,21 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer,
).forEach {
it?.animate()?.alpha(0f)?.setDuration(600)?.start()
}
- if (prefs.textColor != Color.WHITE) {
+ if (themeProvider.textColor != Color.WHITE) {
val f = lastView?.findViewById<ImageView>(R.id.intro_image)?.drawable
if (f != null)
ValueAnimator.ofFloat(0f, 1f).apply {
addUpdateListener {
- f.setTint(prefs.textColor.blendWith(Color.WHITE, it.animatedValue as Float))
+ f.setTint(themeProvider.textColor.blendWith(Color.WHITE, it.animatedValue as Float))
}
duration = 600
start()
}
}
- if (prefs.headerColor != blue) {
+ if (themeProvider.headerColor != blue) {
ValueAnimator.ofFloat(0f, 1f).apply {
addUpdateListener {
- val c = prefs.headerColor.blendWith(blue, it.animatedValue as Float)
+ val c = themeProvider.headerColor.blendWith(blue, it.animatedValue as Float)
statusBarColor = c
navigationBarColor = c
}
@@ -176,7 +178,7 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer,
override fun finish() {
launch(NonCancellable) {
- loadAssets(prefs)
+ loadAssets(themeProvider)
NotificationWidget.forceUpdate(this@IntroActivity)
launchNewTask<MainActivity>(cookies(), false)
super.finish()
@@ -207,7 +209,7 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer,
binding.next.fadeScaleTransition {
setIcon(
if (barHasNext) GoogleMaterial.Icon.gmd_navigate_next else GoogleMaterial.Icon.gmd_done,
- color = prefs.textColor
+ color = themeProvider.textColor
)
}
binding.skip.animate().scaleXY(if (barHasNext) 1f else 0f)
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..5cbbfafe 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt
@@ -80,15 +80,13 @@ class LoginActivity : BaseActivity() {
setContentView(R.layout.activity_login)
setSupportActionBar(toolbar)
setTitle(R.string.kau_login)
- setFrostColors(prefs) {
+ setFrostColors {
toolbar(toolbar)
}
profileLoader = GlideApp.with(profile)
launch {
for (refreshing in refreshChannel.uniqueOnly(this)) {
- if (refreshing) swipeRefresh.isEnabled = true
swipeRefresh.isRefreshing = refreshing
- if (!refreshing) swipeRefresh.isEnabled = false
}
}
launch {
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 aac714ce..9ce16ec7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
@@ -39,6 +39,7 @@ import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.R
import com.pitchedapps.frost.db.NotificationDao
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
@@ -69,6 +70,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
@@ -132,8 +134,8 @@ class SettingsActivity : KPrefActivity() {
}
override fun kPrefCoreAttributes(): CoreAttributeContract.() -> Unit = {
- textColor = { prefs.textColor }
- accentColor = { prefs.accentColor }
+ textColor = { themeProvider.textColor }
+ accentColor = { themeProvider.accentColor }
}
override fun onCreateKPrefs(savedInstanceState: Bundle?): KPrefAdapterBuilder.() -> Unit = {
@@ -216,25 +218,25 @@ class SettingsActivity : KPrefActivity() {
@SuppressLint("MissingSuperCall")
override fun onCreate(savedInstanceState: Bundle?) {
- setFrostTheme(prefs, true)
+ setFrostTheme(themeProvider, true)
super.onCreate(savedInstanceState)
animate = prefs.animate
themeExterior(false)
}
fun themeExterior(animate: Boolean = true) {
- if (animate) bgCanvas.fade(prefs.bgColor)
- else bgCanvas.set(prefs.bgColor)
- if (animate) toolbarCanvas.ripple(prefs.headerColor, RippleCanvas.MIDDLE, RippleCanvas.END)
- else toolbarCanvas.set(prefs.headerColor)
- frostNavigationBar(prefs)
+ if (animate) bgCanvas.fade(themeProvider.bgColor)
+ else bgCanvas.set(themeProvider.bgColor)
+ if (animate) toolbarCanvas.ripple(themeProvider.headerColor, RippleCanvas.MIDDLE, RippleCanvas.END)
+ else toolbarCanvas.set(themeProvider.headerColor)
+ frostNavigationBar(prefs, themeProvider)
}
override fun onBackPressed() {
if (!super.backPress()) {
setResult(resultFlag)
launch(NonCancellable) {
- loadAssets(prefs)
+ loadAssets(themeProvider)
finishSlideOut()
}
}
@@ -242,9 +244,9 @@ class SettingsActivity : KPrefActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_settings, menu)
- toolbar.tint(prefs.iconColor)
+ toolbar.tint(themeProvider.iconColor)
setMenuIcons(
- menu, prefs.iconColor,
+ menu, themeProvider.iconColor,
R.id.action_github to CommunityMaterial.Icon2.cmd_github,
R.id.action_changelog to GoogleMaterial.Icon.gmd_info
)
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..f2827397 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt
@@ -69,15 +69,15 @@ class TabCustomizerActivity : BaseActivity() {
}
fun ActivityTabCustomizerBinding.init() {
- pseudoToolbar.setBackgroundColor(prefs.headerColor)
+ pseudoToolbar.setBackgroundColor(themeProvider.headerColor)
tabRecycler.layoutManager =
GridLayoutManager(this@TabCustomizerActivity, TAB_COUNT, RecyclerView.VERTICAL, false)
tabRecycler.adapter = adapter
tabRecycler.setHasFixedSize(true)
- divider.setBackgroundColor(prefs.textColor.withAlpha(30))
- instructions.setTextColor(prefs.textColor)
+ divider.setBackgroundColor(themeProvider.textColor.withAlpha(30))
+ instructions.setTextColor(themeProvider.textColor)
launch {
val tabs = genericDao.getTabs().toMutableList()
@@ -94,8 +94,8 @@ class TabCustomizerActivity : BaseActivity() {
setResult(Activity.RESULT_CANCELED)
- fabSave.setIcon(GoogleMaterial.Icon.gmd_check, prefs.iconColor)
- fabSave.backgroundTintList = ColorStateList.valueOf(prefs.accentColor)
+ fabSave.setIcon(GoogleMaterial.Icon.gmd_check, themeProvider.iconColor)
+ fabSave.backgroundTintList = ColorStateList.valueOf(themeProvider.accentColor)
fabSave.setOnClickListener {
launchMain(NonCancellable) {
val tabs = adapter.adapterItems.subList(0, TAB_COUNT).map(TabIItem::item)
@@ -104,10 +104,10 @@ class TabCustomizerActivity : BaseActivity() {
finish()
}
}
- fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, prefs.iconColor)
- fabCancel.backgroundTintList = ColorStateList.valueOf(prefs.accentColor)
+ fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, themeProvider.iconColor)
+ fabCancel.backgroundTintList = ColorStateList.valueOf(themeProvider.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..42d84eb7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
@@ -202,14 +202,14 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
- toolbar.navigationIcon = GoogleMaterial.Icon.gmd_close.toDrawable(this, 16, prefs.iconColor)
+ toolbar.navigationIcon = GoogleMaterial.Icon.gmd_close.toDrawable(this, 16, themeProvider.iconColor)
toolbar.setNavigationOnClickListener { finishSlideOut() }
- setFrostColors(prefs) {
+ setFrostColors {
toolbar(toolbar)
themeWindow = false
}
- coordinator.setBackgroundColor(prefs.bgColor.withAlpha(255))
+ coordinator.setBackgroundColor(themeProvider.bgColor.withAlpha(255))
content.bind(this)
@@ -268,13 +268,13 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
* Our theme for the overlay should be fully opaque
*/
fun theme() {
- val opaqueAccent = prefs.headerColor.withAlpha(255)
+ val opaqueAccent = themeProvider.headerColor.withAlpha(255)
statusBarColor = opaqueAccent.darken()
navigationBarColor = opaqueAccent
toolbar.setBackgroundColor(opaqueAccent)
- toolbar.setTitleTextColor(prefs.iconColor)
- coordinator.setBackgroundColor(prefs.bgColor.withAlpha(255))
- toolbar.overflowIcon?.setTint(prefs.iconColor)
+ toolbar.setTitleTextColor(themeProvider.iconColor)
+ coordinator.setBackgroundColor(themeProvider.bgColor.withAlpha(255))
+ toolbar.overflowIcon?.setTint(themeProvider.iconColor)
}
override fun onResume() {
@@ -309,7 +309,7 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_web, menu)
overlayContext?.onMenuCreate(this, menu)
- toolbar.tint(prefs.iconColor)
+ toolbar.tint(themeProvider.iconColor)
return true
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt
index 8a6e57af..b8d0d86f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt
@@ -73,11 +73,17 @@ interface FrostContentParent : DynamicUiContract {
var baseEnum: FbItem?
+ val swipeEnabled: Boolean get() = swipeAllowedByPage && !swipeDisabledByAction
+
+ /**
+ * Temporary disable swiping based on action
+ */
+ var swipeDisabledByAction: Boolean
+
/**
- * Toggle state for allowing swipes
- * Allowed on any thread
+ * Decides if swipe should be allowed for the current page
*/
- var swipeEnabled: Boolean
+ var swipeAllowedByPage: Boolean
/**
* Binds the container to self
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt
index 388edfe6..8c2e32a7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt
@@ -23,6 +23,8 @@ import androidx.room.Entity
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
import com.pitchedapps.frost.prefs.Prefs
import kotlinx.android.parcel.Parcelize
@@ -37,11 +39,13 @@ data class CookieEntity(
@ColumnInfo(name = "cookie_id")
val id: Long,
val name: String?,
- val cookie: String?
+ val cookie: String?,
+ val cookieMessenger: String? = null // Version 2
) : Parcelable {
override fun toString(): String = "CookieEntity(${hashCode()})"
- fun toSensitiveString(): String = "CookieEntity(id=$id, name=$name, cookie=$cookie)"
+ fun toSensitiveString(): String =
+ "CookieEntity(id=$id, name=$name, cookie=$cookie cookieMessenger=$cookieMessenger)"
}
@Dao
@@ -61,6 +65,9 @@ interface CookieDao {
@Query("DELETE FROM cookies WHERE cookie_id = :id")
fun _deleteById(id: Long)
+
+ @Query("UPDATE cookies SET cookieMessenger = :cookie WHERE cookie_id = :id")
+ fun _updateMessengerCookie(id: Long, cookie: String?)
}
suspend fun CookieDao.selectAll() = dao { _selectAll() }
@@ -69,3 +76,11 @@ suspend fun CookieDao.save(cookie: CookieEntity) = dao { _save(cookie) }
suspend fun CookieDao.save(cookies: List<CookieEntity>) = dao { _save(cookies) }
suspend fun CookieDao.deleteById(id: Long) = dao { _deleteById(id) }
suspend fun CookieDao.currentCookie(prefs: Prefs) = selectById(prefs.userId)
+suspend fun CookieDao.updateMessengerCookie(id: Long, cookie: String?) =
+ dao { _updateMessengerCookie(id, cookie) }
+
+val COOKIES_MIGRATION_1_2 = object : Migration(1, 2) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE cookies ADD COLUMN cookieMessenger TEXT")
+ }
+}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt
index 21a2f1dc..bd0b4ee0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt
@@ -31,7 +31,7 @@ interface FrostPrivateDao {
@Database(
entities = [CookieEntity::class, NotificationEntity::class, CacheEntity::class],
- version = 1,
+ version = 2,
exportSchema = true
)
abstract class FrostPrivateDatabase : RoomDatabase(), FrostPrivateDao {
@@ -84,7 +84,7 @@ class FrostDatabase(
val privateDb = Room.databaseBuilder(
context, FrostPrivateDatabase::class.java,
FrostPrivateDatabase.DATABASE_NAME
- ).frostBuild()
+ ).addMigrations(COOKIES_MIGRATION_1_2).frostBuild()
val publicDb = Room.databaseBuilder(
context, FrostPublicDatabase::class.java,
FrostPublicDatabase.DATABASE_NAME
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt
index 79a6f188..ec438df1 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt
@@ -17,15 +17,15 @@
package com.pitchedapps.frost.enums
import com.pitchedapps.frost.R
-import com.pitchedapps.frost.prefs.Prefs
+import com.pitchedapps.frost.injectors.ThemeProvider
/**
* Created by Allan Wang on 2017-08-19.
*/
enum class MainActivityLayout(
val titleRes: Int,
- val backgroundColor: (Prefs) -> Int,
- val iconColor: (Prefs) -> Int
+ val backgroundColor: (ThemeProvider) -> Int,
+ val iconColor: (ThemeProvider) -> Int
) {
TOP_BAR(R.string.top_bar,
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..1c9d6aa5 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,
+ "default",
{ 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/facebook/FbConst.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
index 61745b95..b0846864 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
@@ -21,8 +21,12 @@ package com.pitchedapps.frost.facebook
*/
const val FACEBOOK_COM = "facebook.com"
+const val MESSENGER_COM = "messenger.com"
const val FBCDN_NET = "fbcdn.net"
const val WWW_FACEBOOK_COM = "www.$FACEBOOK_COM"
+const val WWW_MESSENGER_COM = "www.$MESSENGER_COM"
+const val HTTPS_FACEBOOK_COM = "https://$WWW_FACEBOOK_COM"
+const val HTTPS_MESSENGER_COM = "https://$WWW_MESSENGER_COM"
const val FACEBOOK_BASE_COM = "m.$FACEBOOK_COM"
const val FB_URL_BASE = "https://$FACEBOOK_BASE_COM/"
const val FACEBOOK_MBASIC_COM = "mbasic.$FACEBOOK_COM"
@@ -30,6 +34,7 @@ const val FB_URL_MBASIC_BASE = "https://$FACEBOOK_MBASIC_COM/"
fun profilePictureUrl(id: Long) = "https://graph.facebook.com/$id/picture?type=large"
const val FB_LOGIN_URL = "${FB_URL_BASE}login"
const val FB_HOME_URL = "${FB_URL_BASE}home.php"
+const val MESSENGER_THREAD_PREFIX = "$HTTPS_MESSENGER_COM/t/"
/*
* User agent candidates.
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
index e66eaf27..4e932d09 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
@@ -30,6 +30,7 @@ import com.pitchedapps.frost.utils.cookies
import com.pitchedapps.frost.utils.launchLogin
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@@ -44,7 +45,8 @@ import org.koin.dsl.module
class FbCookie(private val prefs: Prefs, private val cookieDao: CookieDao) {
companion object {
- private const val COOKIE_DOMAIN = FB_URL_BASE
+ private const val FB_COOKIE_DOMAIN = HTTPS_FACEBOOK_COM
+ private const val MESSENGER_COOKIE_DOMAIN = HTTPS_MESSENGER_COM
fun module() = module {
single { FbCookie(get(), get()) }
@@ -56,36 +58,40 @@ class FbCookie(private val prefs: Prefs, private val cookieDao: CookieDao) {
* Note that this is a synchronized call
*/
val webCookie: String?
- get() = CookieManager.getInstance().getCookie(COOKIE_DOMAIN)
+ get() = CookieManager.getInstance().getCookie(FB_COOKIE_DOMAIN)
- private suspend fun CookieManager.suspendSetWebCookie(cookie: String?): Boolean {
+ val messengerCookie: String?
+ get() = CookieManager.getInstance().getCookie(HTTPS_MESSENGER_COM)
+
+ private suspend fun CookieManager.suspendSetWebCookie(
+ domain: String,
+ cookie: String?
+ ): Boolean {
cookie ?: return true
return withContext(NonCancellable) {
- removeAllCookies()
// Save all cookies regardless of result, then check if all succeeded
val result = cookie.split(";")
- .map { async { setSingleWebCookie(it) } }
+ .map { async { setSingleWebCookie(domain, it) } }
.awaitAll().all { it }
- flush()
L.d { "Cookies set" }
L._d { "Set $cookie\n\tResult $webCookie" }
result
}
}
+ private suspend fun CookieManager.setSingleWebCookie(domain: String, cookie: String): Boolean =
+ suspendCoroutine { cont ->
+ setCookie(domain, cookie.trim()) {
+ cont.resume(it)
+ }
+ }
+
private suspend fun CookieManager.removeAllCookies(): Boolean = suspendCoroutine { cont ->
removeAllCookies {
cont.resume(it)
}
}
- private suspend fun CookieManager.setSingleWebCookie(cookie: String): Boolean =
- suspendCoroutine { cont ->
- setCookie(COOKIE_DOMAIN, cookie.trim()) {
- cont.resume(it)
- }
- }
-
suspend fun save(id: Long) {
L.d { "New cookie found" }
prefs.userId = id
@@ -96,9 +102,11 @@ class FbCookie(private val prefs: Prefs, private val cookieDao: CookieDao) {
suspend fun reset() {
prefs.userId = -1L
- with(CookieManager.getInstance()) {
- removeAllCookies()
- flush()
+ withContext(Dispatchers.Main + NonCancellable) {
+ with(CookieManager.getInstance()) {
+ removeAllCookies()
+ flush()
+ }
}
}
@@ -108,14 +116,19 @@ class FbCookie(private val prefs: Prefs, private val cookieDao: CookieDao) {
}
suspend fun switchUser(cookie: CookieEntity?) {
- if (cookie == null) {
+ if (cookie?.cookie == null) {
L.d { "Switching User; null cookie" }
return
}
- withContext(NonCancellable) {
+ withContext(Dispatchers.Main + NonCancellable) {
L.d { "Switching User" }
prefs.userId = cookie.id
- CookieManager.getInstance().suspendSetWebCookie(cookie.cookie)
+ CookieManager.getInstance().apply {
+ removeAllCookies()
+ suspendSetWebCookie(FB_COOKIE_DOMAIN, cookie.cookie)
+ suspendSetWebCookie(MESSENGER_COOKIE_DOMAIN, cookie.cookieMessenger)
+ flush()
+ }
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt
index 4c33fe8d..9b08c775 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt
@@ -48,6 +48,7 @@ enum class FbItem(
MARKETPLACE(R.string.marketplace, GoogleMaterial.Icon.gmd_store, "marketplace"),
MENU(R.string.menu, GoogleMaterial.Icon.gmd_menu, "settings"),
MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "messages"),
+ MESSENGER(R.string.messenger, CommunityMaterial.Icon2.cmd_facebook_messenger, "", prefix = HTTPS_MESSENGER_COM),
NOTES(R.string.notes, CommunityMaterial.Icon3.cmd_note, "notes"),
NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "notifications"),
ON_THIS_DAY(R.string.on_this_day, GoogleMaterial.Icon.gmd_today, "onthisday"),
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt
index 0232694e..c07884bc 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt
@@ -34,6 +34,7 @@ import com.pitchedapps.frost.contracts.MainFabContract
import com.pitchedapps.frost.enums.FeedSort
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbItem
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.ARG_URL
import com.pitchedapps.frost.utils.L
@@ -49,6 +50,7 @@ import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
+import org.koin.core.component.inject
/**
* Created by Allan Wang on 2017-11-07.
@@ -84,6 +86,7 @@ abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract,
protected val fbCookie: FbCookie by inject()
protected val prefs: Prefs by inject()
+ protected val themeProvider: ThemeProvider by inject()
open lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = ContextHelper.dispatcher + job
@@ -201,10 +204,10 @@ abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract,
protected fun FloatingActionButton.update(iicon: IIcon, click: () -> Unit) {
if (isShown) {
fadeScaleTransition {
- setIcon(iicon, prefs.iconColor)
+ setIcon(iicon, themeProvider.iconColor)
}
} else {
- setIcon(iicon, prefs.iconColor)
+ setIcon(iicon, themeProvider.iconColor)
show()
}
setOnClickListener { click() }
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt
index 502c37fb..3cac92af 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt
@@ -26,6 +26,7 @@ import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.views.FrostWebView
import com.pitchedapps.frost.web.FrostWebViewClient
import com.pitchedapps.frost.web.FrostWebViewClientMenu
+import com.pitchedapps.frost.web.FrostWebViewClientMessenger
/**
* Created by Allan Wang on 27/12/17.
@@ -41,6 +42,7 @@ class WebFragment : BaseFragment() {
* Given a webview, output a client
*/
fun client(web: FrostWebView) = when (baseEnum) {
+ FbItem.MESSENGER -> FrostWebViewClientMessenger(web)
FbItem.MENU -> FrostWebViewClientMenu(web)
else -> FrostWebViewClient(web)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt
index 47a362b4..0c53a2b1 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt
@@ -28,6 +28,7 @@ import com.mikepenz.fastadapter.IAdapter
import com.mikepenz.fastadapter.select.selectExtension
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.launchWebOverlay
import org.koin.core.component.KoinComponent
@@ -79,14 +80,14 @@ open class HeaderIItem(
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<HeaderIItem>(itemView),
KoinComponent {
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
val text: TextView by bindView(R.id.item_header_text)
override fun bindView(item: HeaderIItem, payloads: List<Any>) {
- text.setTextColor(prefs.accentColor)
+ text.setTextColor(themeProvider.accentColor)
text.text = item.text
- text.setBackgroundColor(prefs.nativeBgColor)
+ text.setBackgroundColor(themeProvider.nativeBgColor)
}
override fun unbindView(item: HeaderIItem) {
@@ -108,14 +109,14 @@ open class TextIItem(
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TextIItem>(itemView), KoinComponent {
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
val text: TextView by bindView(R.id.item_text_view)
override fun bindView(item: TextIItem, payloads: List<Any>) {
- text.setTextColor(prefs.textColor)
+ text.setTextColor(themeProvider.textColor)
text.text = item.text
- text.background = createSimpleRippleDrawable(prefs.bgColor, prefs.nativeBgColor)
+ text.background = createSimpleRippleDrawable(themeProvider.bgColor, themeProvider.nativeBgColor)
}
override fun unbindView(item: TextIItem) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt
index 56e27ccd..8e0d5bec 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt
@@ -36,6 +36,7 @@ import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.parsers.FrostNotif
import com.pitchedapps.frost.glide.FrostGlide
import com.pitchedapps.frost.glide.GlideApp
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.isIndependent
import com.pitchedapps.frost.utils.launchWebOverlay
@@ -103,7 +104,7 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) :
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<NotificationIItem>(itemView),
KoinComponent {
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
private val frame: ViewGroup by bindView(R.id.item_frame)
private val avatar: ImageView by bindView(R.id.item_avatar)
@@ -117,11 +118,11 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) :
override fun bindView(item: NotificationIItem, payloads: List<Any>) {
val notif = item.notification
frame.background = createSimpleRippleDrawable(
- prefs.textColor,
- prefs.nativeBgColor(notif.unread)
+ themeProvider.textColor,
+ themeProvider.nativeBgColor(notif.unread)
)
- content.setTextColor(prefs.textColor)
- date.setTextColor(prefs.textColor.withAlpha(150))
+ content.setTextColor(themeProvider.textColor)
+ date.setTextColor(themeProvider.textColor.withAlpha(150))
val glide = glide
glide.load(notif.img)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt
index 6f278fe2..0fd39d5c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt
@@ -29,7 +29,7 @@ import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.drag.IDraggable
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.FbItem
-import com.pitchedapps.frost.prefs.Prefs
+import com.pitchedapps.frost.injectors.ThemeProvider
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -45,14 +45,14 @@ class TabIItem(val item: FbItem) : KauIItem<TabIItem.ViewHolder>(
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TabIItem>(itemView), KoinComponent {
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
val image: ImageView by bindView(R.id.image)
val text: TextView by bindView(R.id.text)
override fun bindView(item: TabIItem, payloads: List<Any>) {
val isInToolbar = adapterPosition < 4
- val color = if (isInToolbar) prefs.iconColor else prefs.textColor
+ val color = if (isInToolbar) themeProvider.iconColor else themeProvider.textColor
image.setIcon(item.item.icon, 20, color)
if (isInToolbar)
text.invisible()
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()) }
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt
index 6e735e5b..486b09a9 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt
@@ -66,7 +66,7 @@ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) {
setOnClickListener { v ->
prefs.theme = theme.ordinal
(activity as IntroActivity).apply {
- binding.ripple.ripple(prefs.bgColor, v.x + v.pivotX, v.y + v.pivotY)
+ binding.ripple.ripple(themeProvider.bgColor, v.x + v.pivotX, v.y + v.pivotY)
theme()
}
themeList.forEach { it.animate().scaleXY(if (it == this) 1.6f else 0.8f).start() }
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt
index 429171dd..e27d4fee 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt
@@ -57,10 +57,10 @@ abstract class BaseImageIntroFragment(
override fun themeFragmentImpl() {
super.themeFragmentImpl()
- title.setTextColor(prefs.textColor)
- desc.setTextColor(prefs.textColor)
- phone.tint(prefs.textColor)
- screen.tint(prefs.bgColor)
+ title.setTextColor(themeProvider.textColor)
+ desc.setTextColor(themeProvider.textColor)
+ phone.tint(themeProvider.textColor)
+ screen.tint(themeProvider.bgColor)
}
fun themeImageComponent(color: Int, vararg id: Int) {
@@ -96,9 +96,9 @@ class IntroAccountFragment : BaseImageIntroFragment(
override fun themeFragmentImpl() {
super.themeFragmentImpl()
- themeImageComponent(prefs.iconColor, R.id.intro_phone_avatar_1, R.id.intro_phone_avatar_2)
- themeImageComponent(prefs.bgColor.colorToForeground(), R.id.intro_phone_nav)
- themeImageComponent(prefs.headerColor, R.id.intro_phone_header)
+ themeImageComponent(themeProvider.iconColor, R.id.intro_phone_avatar_1, R.id.intro_phone_avatar_2)
+ themeImageComponent(themeProvider.bgColor.colorToForeground(), R.id.intro_phone_nav)
+ themeImageComponent(themeProvider.headerColor, R.id.intro_phone_header)
}
override fun onPageScrolledImpl(positionOffset: Float) {
@@ -122,14 +122,14 @@ class IntroTabTouchFragment : BaseImageIntroFragment(
override fun themeFragmentImpl() {
super.themeFragmentImpl()
themeImageComponent(
- prefs.iconColor,
+ themeProvider.iconColor,
R.id.intro_phone_icon_1,
R.id.intro_phone_icon_2,
R.id.intro_phone_icon_3,
R.id.intro_phone_icon_4
)
- themeImageComponent(prefs.headerColor, R.id.intro_phone_tab)
- themeImageComponent(prefs.textColor.withAlpha(80), R.id.intro_phone_icon_ripple)
+ themeImageComponent(themeProvider.headerColor, R.id.intro_phone_tab)
+ themeImageComponent(themeProvider.textColor.withAlpha(80), R.id.intro_phone_icon_ripple)
}
}
@@ -141,21 +141,21 @@ class IntroTabContextFragment : BaseImageIntroFragment(
override fun themeFragmentImpl() {
super.themeFragmentImpl()
- themeImageComponent(prefs.headerColor, R.id.intro_phone_toolbar)
- themeImageComponent(prefs.bgColor.colorToForeground(0.1f), R.id.intro_phone_image)
+ themeImageComponent(themeProvider.headerColor, R.id.intro_phone_toolbar)
+ themeImageComponent(themeProvider.bgColor.colorToForeground(0.1f), R.id.intro_phone_image)
themeImageComponent(
- prefs.bgColor.colorToForeground(0.2f),
+ themeProvider.bgColor.colorToForeground(0.2f),
R.id.intro_phone_like,
R.id.intro_phone_share
)
- themeImageComponent(prefs.bgColor.colorToForeground(0.3f), R.id.intro_phone_comment)
+ themeImageComponent(themeProvider.bgColor.colorToForeground(0.3f), R.id.intro_phone_comment)
themeImageComponent(
- prefs.bgColor.colorToForeground(0.1f),
+ themeProvider.bgColor.colorToForeground(0.1f),
R.id.intro_phone_card_1,
R.id.intro_phone_card_2
)
themeImageComponent(
- prefs.textColor,
+ themeProvider.textColor,
R.id.intro_phone_image_indicator,
R.id.intro_phone_comment_indicator,
R.id.intro_phone_card_indicator
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt
index d160bee4..8003cb2e 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt
@@ -33,9 +33,11 @@ import ca.allanwang.kau.utils.bindViewResettable
import ca.allanwang.kau.utils.setOnSingleTapListener
import com.pitchedapps.frost.R
import com.pitchedapps.frost.activities.IntroActivity
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import kotlin.math.abs
import org.koin.android.ext.android.inject
+import org.koin.core.component.inject
/**
* Created by Allan Wang on 2017-07-28.
@@ -49,6 +51,7 @@ import org.koin.android.ext.android.inject
abstract class BaseIntroFragment(val layoutRes: Int) : Fragment() {
protected val prefs: Prefs by inject()
+ protected val themeProvider: ThemeProvider by inject()
val screenWidth
get() = resources.displayMetrics.widthPixels
@@ -105,7 +108,7 @@ abstract class BaseIntroFragment(val layoutRes: Int) : Fragment() {
}
protected open fun themeFragmentImpl() {
- (view as? ViewGroup)?.children?.forEach { (it as? TextView)?.setTextColor(prefs.textColor) }
+ (view as? ViewGroup)?.children?.forEach { (it as? TextView)?.setTextColor(themeProvider.textColor) }
}
protected val viewArray: Array<Array<out View>> by lazyResettableRegistered { viewArray() }
@@ -134,7 +137,7 @@ class IntroFragmentWelcome : BaseIntroFragment(R.layout.intro_welcome) {
override fun themeFragmentImpl() {
super.themeFragmentImpl()
- image.imageTintList = ColorStateList.valueOf(prefs.textColor)
+ image.imageTintList = ColorStateList.valueOf(themeProvider.textColor)
}
}
@@ -146,7 +149,7 @@ class IntroFragmentEnd : BaseIntroFragment(R.layout.intro_end) {
override fun themeFragmentImpl() {
super.themeFragmentImpl()
- image.imageTintList = ColorStateList.valueOf(prefs.textColor)
+ image.imageTintList = ColorStateList.valueOf(themeProvider.textColor)
}
@SuppressLint("ClickableViewAccessibility")
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/prefs/Prefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/prefs/Prefs.kt
index 2714b930..d31be432 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/prefs/Prefs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/prefs/Prefs.kt
@@ -28,7 +28,7 @@ import com.pitchedapps.frost.prefs.sections.ShowcasePrefs
import com.pitchedapps.frost.prefs.sections.ShowcasePrefsImpl
import com.pitchedapps.frost.prefs.sections.ThemePrefs
import com.pitchedapps.frost.prefs.sections.ThemePrefsImpl
-import org.koin.core.context.KoinContextHandler
+import org.koin.core.context.GlobalContext
import org.koin.dsl.module
/**
@@ -48,7 +48,7 @@ interface Prefs :
ShowcasePrefs,
PrefsBase {
companion object {
- fun get(): Prefs = KoinContextHandler.get().get()
+ fun get(): Prefs = GlobalContext.get().get()
fun module() = module {
single<BehaviourPrefs> { BehaviourPrefsImpl(factory = get()) }
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..47496d6d 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
@@ -16,17 +16,10 @@
*/
package com.pitchedapps.frost.prefs.sections
-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
import com.pitchedapps.frost.BuildConfig
-import com.pitchedapps.frost.enums.FACEBOOK_BLUE
-import com.pitchedapps.frost.enums.Theme
-import com.pitchedapps.frost.injectors.InjectorContract
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.OldPrefs
import com.pitchedapps.frost.prefs.PrefsBase
import org.koin.core.component.KoinComponent
@@ -45,26 +38,6 @@ interface ThemePrefs : PrefsBase {
var customIconColor: Int
- val textColor: Int
-
- val accentColor: Int
-
- val accentColorForWhite: Int
-
- val nativeBgColor: Int
-
- fun nativeBgColor(unread: Boolean): Int
-
- val bgColor: Int
-
- val headerColor: Int
-
- val iconColor: Int
-
- val themeInjector: InjectorContract
-
- val isCustomTheme: Boolean
-
var tintNavBar: Boolean
}
@@ -74,9 +47,10 @@ class ThemePrefsImpl(
ThemePrefs, KoinComponent {
private val oldPrefs: OldPrefs by inject()
+ private val themeProvider: ThemeProvider by inject()
- override var theme: Int by kpref("theme", oldPrefs.theme /* 0 */) { _: Int ->
- loader.invalidate()
+ override var theme: Int by kpref("theme", oldPrefs.theme /* 0 */) {
+ themeProvider.setTheme(it)
}
override var customTextColor: Int by kpref(
@@ -104,44 +78,5 @@ class ThemePrefsImpl(
oldPrefs.customIconColor /* 0xffeceff1.toInt() */
)
- private val loader = lazyResettable { Theme.values[theme] }
-
- private val t: Theme by loader
-
- override val textColor: Int
- get() = t.textColorGetter(this)
-
- override val accentColor: Int
- get() = t.accentColorGetter(this)
-
- override val accentColorForWhite: Int
- get() = when {
- accentColor.isColorVisibleOn(Color.WHITE) -> accentColor
- textColor.isColorVisibleOn(Color.WHITE) -> textColor
- else -> FACEBOOK_BLUE
- }
-
- override val nativeBgColor: Int
- get() = bgColor.withAlpha(30)
-
- override fun nativeBgColor(unread: Boolean) = bgColor
- .colorToForeground(if (unread) 0.7f else 0.0f)
- .withAlpha(30)
-
- override val bgColor: Int
- get() = t.backgroundColorGetter(this)
-
- override val headerColor: Int
- get() = t.headerColorGetter(this)
-
- override val iconColor: Int
- get() = t.iconColorGetter(this)
-
- override val themeInjector: InjectorContract
- get() = t.injector
-
- override val isCustomTheme: Boolean
- get() = t == Theme.CUSTOM
-
override var tintNavBar: Boolean by kpref("tint_nav_bar", oldPrefs.tintNavBar /* true */)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt
index 0a90895e..0bb9d254 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt
@@ -31,6 +31,7 @@ import androidx.core.app.NotificationCompat
import ca.allanwang.kau.utils.color
import ca.allanwang.kau.utils.string
import com.pitchedapps.frost.R
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.frostUri
@@ -41,13 +42,13 @@ import com.pitchedapps.frost.utils.frostUri
const val NOTIF_CHANNEL_GENERAL = "general"
const val NOTIF_CHANNEL_MESSAGES = "messages"
-fun setupNotificationChannels(c: Context, prefs: Prefs) {
+fun setupNotificationChannels(c: Context, themeProvider: ThemeProvider) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val manager = c.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val appName = c.string(R.string.frost_name)
val msg = c.string(R.string.messages)
- manager.createNotificationChannel(NOTIF_CHANNEL_GENERAL, appName, prefs)
- manager.createNotificationChannel(NOTIF_CHANNEL_MESSAGES, "$appName: $msg", prefs)
+ manager.createNotificationChannel(NOTIF_CHANNEL_GENERAL, appName, themeProvider)
+ manager.createNotificationChannel(NOTIF_CHANNEL_MESSAGES, "$appName: $msg", themeProvider)
manager.notificationChannels
.filter {
it.id != NOTIF_CHANNEL_GENERAL &&
@@ -61,14 +62,14 @@ fun setupNotificationChannels(c: Context, prefs: Prefs) {
private fun NotificationManager.createNotificationChannel(
id: String,
name: String,
- prefs: Prefs
+ themeProvider: ThemeProvider
): NotificationChannel {
val channel = NotificationChannel(
id,
name, NotificationManager.IMPORTANCE_DEFAULT
)
channel.enableLights(true)
- channel.lightColor = prefs.accentColor
+ channel.lightColor = themeProvider.accentColor
channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
createNotificationChannel(channel)
return channel
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..64d9dba2 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,6 @@ 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.utils.REQUEST_NAV
import com.pitchedapps.frost.utils.REQUEST_TEXT_ZOOM
import com.pitchedapps.frost.utils.frostEvent
@@ -56,7 +55,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
item.pref = index
shouldRestartMain()
reload()
- setFrostTheme(prefs, true)
+ setFrostTheme(themeProvider, true)
themeExterior()
invalidateOptionsMenu()
frostEvent("Theme", "Count" to Theme(index).name)
@@ -70,13 +69,13 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
}
fun KPrefColorPicker.KPrefColorContract.dependsOnCustom() {
- enabler = prefs::isCustomTheme
+ enabler = themeProvider::isCustomTheme
onDisabledClick = { frostSnackbar(R.string.requires_custom_theme) }
allowCustom = true
}
fun invalidateCustomTheme() {
- CssAssets.CUSTOM.reset()
+ themeProvider.reset()
}
colorPicker(R.string.text_color, prefs::customTextColor, {
@@ -103,7 +102,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
prefs.customBackgroundColor = it
bgCanvas.ripple(it, duration = 500L)
invalidateCustomTheme()
- setFrostTheme(prefs, true)
+ setFrostTheme(themeProvider, true)
shouldRestartMain()
}) {
dependsOnCustom()
@@ -112,7 +111,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
colorPicker(R.string.header_color, prefs::customHeaderColor, {
prefs.customHeaderColor = it
- frostNavigationBar(prefs)
+ frostNavigationBar(prefs, themeProvider)
toolbarCanvas.ripple(it, RippleCanvas.MIDDLE, RippleCanvas.END, duration = 500L)
reload()
shouldRestartMain()
@@ -161,7 +160,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
checkbox(R.string.tint_nav, prefs::tintNavBar, {
prefs.tintNavBar = it
- frostNavigationBar(prefs)
+ frostNavigationBar(prefs, themeProvider)
setFrostResult(REQUEST_NAV)
}) {
descRes = R.string.tint_nav_desc
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 e7bc1542..13ce2920 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -35,6 +35,7 @@ import ca.allanwang.kau.email.sendEmail
import ca.allanwang.kau.mediapicker.createMediaFile
import ca.allanwang.kau.mediapicker.createPrivateMediaFile
import ca.allanwang.kau.utils.colorToForeground
+import ca.allanwang.kau.utils.ctxCoroutine
import ca.allanwang.kau.utils.darken
import ca.allanwang.kau.utils.isColorDark
import ca.allanwang.kau.utils.navigationBarColor
@@ -64,11 +65,12 @@ import com.pitchedapps.frost.facebook.FBCDN_NET
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.FbUrlFormatter.Companion.VIDEO_REDIRECT
+import com.pitchedapps.frost.facebook.MESSENGER_COM
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.JsAssets
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import java.io.File
import java.io.IOException
@@ -76,14 +78,14 @@ import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.util.ArrayList
import java.util.Locale
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
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.
@@ -95,14 +97,6 @@ const val ARG_IMAGE_URL = "arg_image_url"
const val ARG_TEXT = "arg_text"
const val ARG_COOKIE = "arg_cookie"
-/**
- * Most context items implement [CoroutineScope] by default.
- * We will add a fallback just in case.
- * It is expected that the scope returned always has the Android main dispatcher as part of the context.
- */
-internal inline val Context.ctxCoroutine: CoroutineScope
- get() = this as? CoroutineScope ?: GlobalScope
-
inline fun <reified T : Activity> Context.launchNewTask(
cookieList: ArrayList<CookieEntity> = arrayListOf(),
clearStack: Boolean = false
@@ -181,17 +175,22 @@ fun WebOverlayActivity.url(): String {
return intent.getStringExtra(ARG_URL) ?: FbItem.FEED.url
}
-fun Activity.setFrostTheme(prefs: Prefs, forceTransparent: Boolean = false) {
+fun Activity.setFrostTheme(themeProvider: ThemeProvider, forceTransparent: Boolean = false) {
val isTransparent =
- forceTransparent || (Color.alpha(prefs.bgColor) != 255) || (Color.alpha(prefs.headerColor) != 255)
- if (prefs.bgColor.isColorDark) {
+ forceTransparent || (Color.alpha(themeProvider.bgColor) != 255) || (Color.alpha(
+ themeProvider.headerColor
+ ) != 255)
+ if (themeProvider.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(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
@@ -217,21 +216,21 @@ class ActivityThemeUtils(val prefs: Prefs) {
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 = themeProvider.headerColor.darken(0.1f).withAlpha(255)
+ if (prefs.tintNavBar) navigationBarColor = themeProvider.headerColor
+ if (themeWindow) window.setBackgroundDrawable(ColorDrawable(themeProvider.bgColor))
+ toolbar?.setBackgroundColor(themeProvider.headerColor)
+ toolbar?.setTitleTextColor(themeProvider.iconColor)
+ toolbar?.overflowIcon?.setTint(themeProvider.iconColor)
+ texts.forEach { it.setTextColor(themeProvider.textColor) }
+ headers.forEach { it.setBackgroundColor(themeProvider.headerColor) }
+ backgrounds.forEach { it.setBackgroundColor(themeProvider.bgColor) }
}
}
}
-inline fun Activity.setFrostColors(prefs: Prefs, builder: ActivityThemeUtils.() -> Unit) {
- val themer = ActivityThemeUtils(prefs)
+inline fun Activity.setFrostColors(builder: ActivityThemeUtils.() -> Unit) {
+ val themer = ActivityThemeUtils()
themer.builder()
themer.theme(this)
}
@@ -258,19 +257,19 @@ 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()
+ val themeProvider = ThemeProvider.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(themeProvider.textColor)
+ actionView.setTextColor(themeProvider.accentColor)
// only set if previous text colors are set
- view.setBackgroundColor(prefs.bgColor.withAlpha(255).colorToForeground(0.1f))
+ view.setBackgroundColor(themeProvider.bgColor.withAlpha(255).colorToForeground(0.1f))
}
}
-fun Activity.frostNavigationBar(prefs: Prefs) {
- navigationBarColor = if (prefs.tintNavBar) prefs.headerColor else Color.BLACK
+fun Activity.frostNavigationBar(prefs: Prefs, themeProvider: ThemeProvider) {
+ navigationBarColor = if (prefs.tintNavBar) themeProvider.headerColor else Color.BLACK
}
@Throws(IOException::class)
@@ -306,6 +305,12 @@ fun Context.resolveActivityForUri(uri: Uri): Boolean {
inline val String?.isFacebookUrl
get() = this != null && (contains(FACEBOOK_COM) || contains(FBCDN_NET))
+inline val String?.isMessengerUrl
+ get() = this != null && contains(MESSENGER_COM)
+
+inline val String?.isFbCookie
+ get() = this != null && contains("c_user")
+
/**
* [true] if url is a video and can be accepted by VideoViewer
*/
@@ -453,7 +458,7 @@ fun String.unescapeHtml(): String =
.replace("\\u003C", "<")
.replace("\\\"", "\"")
-suspend fun Context.loadAssets(prefs: Prefs): Unit = coroutineScope {
- CssAssets.load(this@loadAssets, prefs)
+suspend fun Context.loadAssets(themeProvider: ThemeProvider): Unit = coroutineScope {
+ themeProvider.preload()
JsAssets.load(this@loadAssets)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt
index 6ba9ff4d..6eebd36f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt
@@ -37,7 +37,7 @@ import com.pitchedapps.frost.db.CookieEntity
import com.pitchedapps.frost.facebook.profilePictureUrl
import com.pitchedapps.frost.glide.FrostGlide
import com.pitchedapps.frost.glide.GlideApp
-import com.pitchedapps.frost.prefs.Prefs
+import com.pitchedapps.frost.injectors.ThemeProvider
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -48,13 +48,13 @@ class AccountItem(val cookie: CookieEntity?) :
KauIItem<AccountItem.ViewHolder>(R.layout.view_account, { ViewHolder(it) }, R.id.item_account),
KoinComponent {
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
override fun bindView(holder: ViewHolder, payloads: List<Any>) {
super.bindView(holder, payloads)
with(holder) {
text.invisible()
- text.setTextColor(prefs.textColor)
+ text.setTextColor(themeProvider.textColor)
if (cookie != null) {
text.text = cookie.name
GlideApp.with(itemView).load(profilePictureUrl(cookie.id))
@@ -86,7 +86,7 @@ class AccountItem(val cookie: CookieEntity?) :
GoogleMaterial.Icon.gmd_add_circle_outline.toDrawable(
itemView.context,
100,
- prefs.textColor
+ themeProvider.textColor
)
)
text.text = itemView.context.getString(R.string.kau_add_account)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt
index ed94b59f..78af4edf 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt
@@ -29,6 +29,7 @@ import ca.allanwang.kau.utils.visible
import ca.allanwang.kau.utils.withAlpha
import com.mikepenz.iconics.typeface.IIcon
import com.pitchedapps.frost.databinding.ViewBadgedIconBinding
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -43,6 +44,7 @@ class BadgedIcon @JvmOverloads constructor(
) : ConstraintLayout(context, attrs, defStyleAttr), KoinComponent {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
private val binding: ViewBadgedIconBinding =
ViewBadgedIconBinding.inflate(LayoutInflater.from(context), this, true)
@@ -52,7 +54,7 @@ class BadgedIcon @JvmOverloads constructor(
private fun ViewBadgedIconBinding.init() {
val badgeColor =
- prefs.mainActivityLayout.backgroundColor(prefs).withAlpha(255).colorToForeground(0.2f)
+ prefs.mainActivityLayout.backgroundColor(themeProvider).withAlpha(255).colorToForeground(0.2f)
val badgeBackground =
GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,
@@ -60,7 +62,7 @@ class BadgedIcon @JvmOverloads constructor(
)
badgeBackground.cornerRadius = 13.dpToPx.toFloat()
badgeText.background = badgeBackground
- badgeText.setTextColor(prefs.mainActivityLayout.iconColor(prefs))
+ badgeText.setTextColor(prefs.mainActivityLayout.iconColor(themeProvider))
}
var iicon: IIcon? = null
@@ -70,13 +72,13 @@ class BadgedIcon @JvmOverloads constructor(
value?.toDrawable(
context,
sizeDp = 20,
- color = prefs.mainActivityLayout.iconColor(prefs)
+ color = prefs.mainActivityLayout.iconColor(themeProvider)
)
)
}
fun setAllAlpha(alpha: Float) {
- // badgeTextView.setTextColor(prefs.textColor.withAlpha(alpha.toInt()))
+ // badgeTextView.setTextColor(themeProvider.textColor.withAlpha(alpha.toInt()))
binding.badgeImage.drawable.alpha = alpha.toInt()
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt
index 55f41807..177b8862 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt
@@ -22,7 +22,6 @@ import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import android.widget.ProgressBar
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import ca.allanwang.kau.utils.ContextHelper
import ca.allanwang.kau.utils.bindView
import ca.allanwang.kau.utils.circularReveal
@@ -39,6 +38,7 @@ import com.pitchedapps.frost.contracts.FrostContentCore
import com.pitchedapps.frost.contracts.FrostContentParent
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.WEB_LOAD_DELAY
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.kotlin.subscribeDuringJob
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
@@ -80,6 +80,7 @@ abstract class FrostContentView<out T> @JvmOverloads constructor(
FrostContentParent, KoinComponent where T : View, T : FrostContentCore {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
private val refresh: SwipeRefreshLayout by bindView(R.id.content_refresh)
private val progress: ProgressBar by bindView(R.id.content_progress)
val coreView: T by bindView(R.id.content_core)
@@ -102,14 +103,26 @@ abstract class FrostContentView<out T> @JvmOverloads constructor(
protected abstract val layoutRes: Int
- override var swipeEnabled = true
+ @Volatile
+ override var swipeDisabledByAction = false
set(value) {
- if (field == value)
- return
field = value
- refresh.post { refresh.isEnabled = value }
+ updateSwipeEnabler()
}
+ @Volatile
+ override var swipeAllowedByPage: Boolean = true
+ set(value) {
+ field = value
+ updateSwipeEnabler()
+ }
+
+ private fun updateSwipeEnabler() {
+ val swipeEnabled = swipeAllowedByPage && !swipeDisabledByAction
+ if (refresh.isEnabled == swipeEnabled) return
+ refresh.post { refresh.isEnabled = swipeEnabled }
+ }
+
/**
* Sets up everything
* Called by [bind]
@@ -134,7 +147,6 @@ abstract class FrostContentView<out T> @JvmOverloads constructor(
refreshChannel.subscribeDuringJob(scope, ContextHelper.coroutineContext) { r ->
refresh.isRefreshing = r
- refresh.isEnabled = true
}
progressChannel.subscribeDuringJob(scope, ContextHelper.coroutineContext) { p ->
@@ -156,9 +168,9 @@ abstract class FrostContentView<out T> @JvmOverloads constructor(
}
override fun reloadThemeSelf() {
- progress.tint(prefs.textColor.withAlpha(180))
- refresh.setColorSchemeColors(prefs.iconColor)
- refresh.setProgressBackgroundColorSchemeColor(prefs.headerColor.withAlpha(255))
+ progress.tint(themeProvider.textColor.withAlpha(180))
+ refresh.setColorSchemeColors(themeProvider.iconColor)
+ refresh.setProgressBackgroundColorSchemeColor(themeProvider.headerColor.withAlpha(255))
}
override fun reloadTextSizeSelf() {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt
index 09be1184..a76aeea0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt
@@ -25,6 +25,7 @@ import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.ViewTreeObserver
import android.widget.FrameLayout
+import ca.allanwang.kau.utils.ctxCoroutine
import ca.allanwang.kau.utils.fadeIn
import ca.allanwang.kau.utils.fadeOut
import ca.allanwang.kau.utils.gone
@@ -43,9 +44,9 @@ import com.pitchedapps.frost.R
import com.pitchedapps.frost.databinding.ViewVideoBinding
import com.pitchedapps.frost.db.CookieDao
import com.pitchedapps.frost.db.currentCookie
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
-import com.pitchedapps.frost.utils.ctxCoroutine
import com.pitchedapps.frost.utils.frostDownload
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -88,6 +89,7 @@ class FrostVideoViewer @JvmOverloads constructor(
}
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
private val cookieDao: CookieDao by inject()
private val binding: ViewVideoBinding =
@@ -100,8 +102,8 @@ class FrostVideoViewer @JvmOverloads constructor(
fun ViewVideoBinding.init() {
alpha = 0f
videoBackground.setBackgroundColor(
- if (!prefs.blackMediaBg && prefs.bgColor.isColorDark)
- prefs.bgColor.withMinAlpha(200)
+ if (!prefs.blackMediaBg && themeProvider.bgColor.isColorDark)
+ themeProvider.bgColor.withMinAlpha(200)
else
Color.BLACK
)
@@ -109,7 +111,7 @@ class FrostVideoViewer @JvmOverloads constructor(
video.pause()
videoToolbar.inflateMenu(R.menu.menu_video)
context.setMenuIcons(
- videoToolbar.menu, prefs.iconColor,
+ videoToolbar.menu, themeProvider.iconColor,
R.id.action_pip to GoogleMaterial.Icon.gmd_picture_in_picture_alt,
R.id.action_download to GoogleMaterial.Icon.gmd_file_download
)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt
index 34bb5204..ecd8c093 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt
@@ -24,6 +24,7 @@ import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import ca.allanwang.kau.utils.AnimHolder
+import ca.allanwang.kau.utils.ctxCoroutine
import ca.allanwang.kau.utils.launchMain
import com.pitchedapps.frost.contracts.FrostContentContainer
import com.pitchedapps.frost.contracts.FrostContentCore
@@ -34,9 +35,9 @@ import com.pitchedapps.frost.facebook.FB_HOME_URL
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.USER_AGENT
import com.pitchedapps.frost.fragments.WebFragment
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
-import com.pitchedapps.frost.utils.ctxCoroutine
import com.pitchedapps.frost.utils.frostDownload
import com.pitchedapps.frost.web.FrostChromeClient
import com.pitchedapps.frost.web.FrostJSI
@@ -62,6 +63,7 @@ class FrostWebView @JvmOverloads constructor(
val fbCookie: FbCookie by inject()
val prefs: Prefs by inject()
+ val themeProvider: ThemeProvider by inject()
val cookieDao: CookieDao by inject()
override fun reload(animate: Boolean) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt
index 0d53608b..c3d5a90e 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt
@@ -37,6 +37,7 @@ import com.mikepenz.fastadapter.listeners.ClickEventHook
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.R
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -51,6 +52,7 @@ class Keywords @JvmOverloads constructor(
) : ConstraintLayout(context, attrs, defStyleAttr), KoinComponent {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
val editText: AppCompatEditText by bindView(R.id.edit_text)
val addIcon: ImageView by bindView(R.id.add_icon)
val recycler: RecyclerView by bindView(R.id.recycler)
@@ -58,8 +60,8 @@ class Keywords @JvmOverloads constructor(
init {
inflate(context, R.layout.view_keywords, this)
- editText.tint(prefs.textColor)
- addIcon.setImageDrawable(GoogleMaterial.Icon.gmd_add.keywordDrawable(context, prefs))
+ editText.tint(themeProvider.textColor)
+ addIcon.setImageDrawable(GoogleMaterial.Icon.gmd_add.keywordDrawable(context, themeProvider))
addIcon.setOnClickListener {
if (editText.text.isNullOrEmpty()) editText.error =
context.string(R.string.empty_keyword)
@@ -91,8 +93,8 @@ class Keywords @JvmOverloads constructor(
}
}
-private fun IIcon.keywordDrawable(context: Context, prefs: Prefs): Drawable =
- toDrawable(context, 20, prefs.textColor)
+private fun IIcon.keywordDrawable(context: Context, themeProvider: ThemeProvider): Drawable =
+ toDrawable(context, 20, themeProvider.textColor)
class KeywordItem(val keyword: String) : AbstractItem<KeywordItem.ViewHolder>() {
@@ -116,16 +118,16 @@ class KeywordItem(val keyword: String) : AbstractItem<KeywordItem.ViewHolder>()
class ViewHolder(v: View) : RecyclerView.ViewHolder(v), KoinComponent {
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
val text: AppCompatTextView by bindView(R.id.keyword_text)
val delete: ImageView by bindView(R.id.keyword_delete)
init {
- text.setTextColor(prefs.textColor)
+ text.setTextColor(themeProvider.textColor)
delete.setImageDrawable(
GoogleMaterial.Icon.gmd_delete.keywordDrawable(
itemView.context,
- prefs
+ themeProvider
)
)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshLayout.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshLayout.kt
index 9e9c2340..f02adcf0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshLayout.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshLayout.kt
@@ -101,9 +101,4 @@ class SwipeRefreshLayout @JvmOverloads constructor(context: Context, attrs: Attr
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed)
}
}
-
- /**
- * Alias for adding on refresh listener
- */
- interface OnRefreshListener : SwipeRefreshLayout.OnRefreshListener
}
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..fe85ab9c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt
@@ -24,9 +24,11 @@ import android.util.AttributeSet
import android.view.View
import android.webkit.WebView
import ca.allanwang.kau.utils.withAlpha
+import com.pitchedapps.frost.enums.ThemeCategory
import com.pitchedapps.frost.facebook.USER_AGENT
+import com.pitchedapps.frost.injectors.CssAsset
import com.pitchedapps.frost.injectors.CssHider
-import com.pitchedapps.frost.injectors.CssSmallAssets
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.injectors.jsInject
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
@@ -50,6 +52,7 @@ class DebugWebView @JvmOverloads constructor(
) : WebView(context, attrs, defStyleAttr), KoinComponent {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
var onPageFinished: (String?) -> Unit = {}
init {
@@ -97,7 +100,7 @@ class DebugWebView @JvmOverloads constructor(
private fun injectBackgroundColor() {
setBackgroundColor(
- if (url.isFacebookUrl) prefs.bgColor.withAlpha(255)
+ if (url.isFacebookUrl) themeProvider.bgColor.withAlpha(255)
else Color.WHITE
)
}
@@ -112,12 +115,12 @@ class DebugWebView @JvmOverloads constructor(
CssHider.STORIES.maybe(!prefs.showStories),
CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!prefs.showSuggestedFriends),
CssHider.SUGGESTED_GROUPS.maybe(!prefs.showSuggestedGroups),
- prefs.themeInjector,
+ themeProvider.injector(ThemeCategory.FACEBOOK),
CssHider.NON_RECENT.maybe(
(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/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
index 40a048af..12e10e10 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
@@ -18,6 +18,7 @@ package com.pitchedapps.frost.web
import android.content.Context
import android.webkit.JavascriptInterface
+import ca.allanwang.kau.utils.ctxCoroutine
import com.pitchedapps.frost.activities.MainActivity
import com.pitchedapps.frost.activities.WebOverlayActivityBase
import com.pitchedapps.frost.contracts.MainActivityContract
@@ -28,7 +29,6 @@ import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.WebContext
import com.pitchedapps.frost.utils.cookies
-import com.pitchedapps.frost.utils.ctxCoroutine
import com.pitchedapps.frost.utils.isIndependent
import com.pitchedapps.frost.utils.launchImageActivity
import com.pitchedapps.frost.utils.showWebContextMenu
@@ -97,7 +97,7 @@ class FrostJSI(val web: FrostWebView) {
fun longClick(start: Boolean) {
activity?.contentBinding?.viewpager?.enableSwipe = !start
if (web.frostWebClient.urlSupportsRefresh) {
- web.parent.swipeEnabled = !start
+ web.parent.swipeDisabledByAction = start
}
}
@@ -109,7 +109,7 @@ class FrostJSI(val web: FrostWebView) {
if (!web.frostWebClient.urlSupportsRefresh) {
return
}
- web.parent.swipeEnabled = !disable
+ web.parent.swipeDisabledByAction = disable
if (disable) {
// locked onto an input field; ensure content is visible
(context as? MainActivityContract)?.collapseAppBar()
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..1495b2e0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
@@ -22,27 +22,38 @@ import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
+import ca.allanwang.kau.utils.ctxCoroutine
import ca.allanwang.kau.utils.withAlpha
+import com.pitchedapps.frost.db.CookieDao
+import com.pitchedapps.frost.db.currentCookie
+import com.pitchedapps.frost.db.updateMessengerCookie
+import com.pitchedapps.frost.enums.ThemeCategory
import com.pitchedapps.frost.facebook.FACEBOOK_BASE_COM
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbItem
+import com.pitchedapps.frost.facebook.HTTPS_MESSENGER_COM
+import com.pitchedapps.frost.facebook.MESSENGER_THREAD_PREFIX
import com.pitchedapps.frost.facebook.WWW_FACEBOOK_COM
import com.pitchedapps.frost.facebook.formattedFbUrl
+import com.pitchedapps.frost.injectors.CssAsset
import com.pitchedapps.frost.injectors.CssHider
-import com.pitchedapps.frost.injectors.CssSmallAssets
import com.pitchedapps.frost.injectors.JsActions
import com.pitchedapps.frost.injectors.JsAssets
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.injectors.jsInject
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.isExplicitIntent
import com.pitchedapps.frost.utils.isFacebookUrl
+import com.pitchedapps.frost.utils.isFbCookie
import com.pitchedapps.frost.utils.isImageUrl
import com.pitchedapps.frost.utils.isIndirectImageUrl
+import com.pitchedapps.frost.utils.isMessengerUrl
import com.pitchedapps.frost.utils.launchImageActivity
import com.pitchedapps.frost.utils.resolveActivityForUri
import com.pitchedapps.frost.views.FrostWebView
import kotlinx.coroutines.channels.SendChannel
+import kotlinx.coroutines.launch
/**
* Created by Allan Wang on 2017-05-31.
@@ -68,10 +79,11 @@ open class BaseWebViewClient : WebViewClient() {
*/
open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
- private val fbCookie: FbCookie get() = web.fbCookie
- private val prefs: Prefs get() = web.prefs
- private val refresh: SendChannel<Boolean> = web.parent.refreshChannel
- private val isMain = web.parent.baseEnum != null
+ protected val fbCookie: FbCookie get() = web.fbCookie
+ protected val prefs: Prefs get() = web.prefs
+ protected val themeProvider: ThemeProvider get() = web.themeProvider
+ protected val refresh: SendChannel<Boolean> = web.parent.refreshChannel
+ protected val isMain = web.parent.baseEnum != null
/**
* True if current url supports refresh. See [doUpdateVisitedHistory] for updates
@@ -81,7 +93,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
override fun doUpdateVisitedHistory(view: WebView, url: String?, isReload: Boolean) {
super.doUpdateVisitedHistory(view, url, isReload)
urlSupportsRefresh = urlSupportsRefresh(url)
- web.parent.swipeEnabled = urlSupportsRefresh
+ web.parent.swipeAllowedByPage = urlSupportsRefresh
view.jsInject(
JsAssets.AUTO_RESIZE_TEXTAREA.maybe(prefs.autoExpandTextBox),
prefs = prefs
@@ -91,6 +103,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
private fun urlSupportsRefresh(url: String?): Boolean {
if (url == null) return false
+ if (url.isMessengerUrl) return false
if (!url.isFacebookUrl) return true
if (url.contains("soft=composer")) return false
if (url.contains("sharer.php") || url.contains("sharer-dialog.php")) return false
@@ -110,7 +123,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
CssHider.STORIES.maybe(!prefs.showStories),
CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!prefs.showSuggestedFriends),
CssHider.SUGGESTED_GROUPS.maybe(!prefs.showSuggestedGroups),
- prefs.themeInjector,
+ themeProvider.injector(ThemeCategory.FACEBOOK),
CssHider.NON_RECENT.maybe(
(web.url?.contains("?sk=h_chr") ?: false) &&
prefs.aggressiveRecents
@@ -118,7 +131,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),
@@ -130,6 +143,13 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
)
}
+ private fun WebView.messengerJsInject() {
+ jsInject(
+ themeProvider.injector(ThemeCategory.MESSENGER),
+ prefs = prefs
+ )
+ }
+
override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
if (url == null) return
@@ -141,7 +161,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
web.setBackgroundColor(
when {
isMain -> Color.TRANSPARENT
- web.url.isFacebookUrl -> prefs.bgColor.withAlpha(255)
+ web.url.isFacebookUrl -> themeProvider.bgColor.withAlpha(255)
else -> Color.WHITE
}
)
@@ -150,18 +170,25 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
override fun onPageCommitVisible(view: WebView, url: String?) {
super.onPageCommitVisible(view, url)
injectBackgroundColor()
- if (url.isFacebookUrl) {
- v { "Page commit visible" }
- view.facebookJsInject()
- } else {
- refresh.offer(false)
+ when {
+ url.isFacebookUrl -> {
+ v { "FB Page commit visible" }
+ view.facebookJsInject()
+ }
+ url.isMessengerUrl -> {
+ v { "Messenger Page commit visible" }
+ view.messengerJsInject()
+ }
+ else -> {
+ refresh.offer(false)
+ }
}
}
override fun onPageFinished(view: WebView, url: String?) {
url ?: return
v { "finished $url" }
- if (!url.isFacebookUrl) {
+ if (!url.isFacebookUrl && !url.isMessengerUrl) {
refresh.offer(false)
return
}
@@ -179,13 +206,20 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
v { "page finished reveal" }
refresh.offer(false)
injectBackgroundColor()
- web.jsInject(
- JsActions.LOGIN_CHECK,
- JsAssets.TEXTAREA_LISTENER,
- JsAssets.HEADER_BADGES.maybe(isMain),
- prefs = prefs
- )
- web.facebookJsInject()
+ when {
+ web.url.isFacebookUrl -> {
+ web.jsInject(
+ JsActions.LOGIN_CHECK,
+ JsAssets.TEXTAREA_LISTENER,
+ JsAssets.HEADER_BADGES.maybe(isMain),
+ prefs = prefs
+ )
+ web.facebookJsInject()
+ }
+ web.url.isMessengerUrl -> {
+ web.messengerJsInject()
+ }
+ }
}
open fun handleHtml(html: String?) {
@@ -253,8 +287,6 @@ private const val EMIT_FINISH = 0
*/
class FrostWebViewClientMenu(web: FrostWebView) : FrostWebViewClient(web) {
- private val prefs: Prefs get() = web.prefs
-
override fun onPageFinished(view: WebView, url: String?) {
super.onPageFinished(view, url)
if (url == null) {
@@ -276,3 +308,38 @@ class FrostWebViewClientMenu(web: FrostWebView) : FrostWebViewClient(web) {
// Skip
}
}
+
+class FrostWebViewClientMessenger(web: FrostWebView) : FrostWebViewClient(web) {
+
+ override fun onPageFinished(view: WebView, url: String?) {
+ super.onPageFinished(view, url)
+ messengerCookieCheck(url!!)
+ }
+
+ private val cookieDao: CookieDao get() = web.cookieDao
+ private var hasCookie = fbCookie.messengerCookie.isFbCookie
+
+ /**
+ * Check cookie changes. Unlike fb checks, we will continuously poll for cookie changes during loading.
+ * There is no lifecycle association between messenger login and facebook login,
+ * so we'll try to be smart about when to check for state changes.
+ *
+ * From testing, it looks like this is called after redirects.
+ * We can therefore classify no login as pointing to messenger.com,
+ * and login as pointing to messenger.com/t/[thread id]
+ */
+ private fun messengerCookieCheck(url: String?) {
+ if (url?.startsWith(HTTPS_MESSENGER_COM) != true) return
+ val shouldHaveCookie = url.startsWith(MESSENGER_THREAD_PREFIX)
+ L._d { "Messenger client: $url $shouldHaveCookie" }
+ if (shouldHaveCookie == hasCookie) return
+ hasCookie = shouldHaveCookie
+ web.context.ctxCoroutine.launch {
+ cookieDao.updateMessengerCookie(
+ prefs.userId,
+ if (shouldHaveCookie) fbCookie.messengerCookie else null
+ )
+ L._d { "New cookie ${cookieDao.currentCookie(prefs)?.toSensitiveString()}" }
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
index 1a081d2e..fadbadf9 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
@@ -30,12 +30,14 @@ import ca.allanwang.kau.utils.fadeIn
import ca.allanwang.kau.utils.isVisible
import ca.allanwang.kau.utils.launchMain
import com.pitchedapps.frost.db.CookieEntity
+import com.pitchedapps.frost.enums.ThemeCategory
import com.pitchedapps.frost.facebook.FB_LOGIN_URL
import com.pitchedapps.frost.facebook.FB_USER_MATCHER
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.USER_AGENT
import com.pitchedapps.frost.facebook.get
import com.pitchedapps.frost.injectors.CssHider
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.injectors.jsInject
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
@@ -56,6 +58,7 @@ class LoginWebView @JvmOverloads constructor(
private val fbCookie: FbCookie by inject()
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
private val completable: CompletableDeferred<CookieEntity> = CompletableDeferred()
private lateinit var progressCallback: (Int) -> Unit
@@ -105,7 +108,7 @@ class LoginWebView @JvmOverloads constructor(
if (url.isFacebookUrl)
view.jsInject(
CssHider.CORE,
- prefs.themeInjector,
+ themeProvider.injector(ThemeCategory.FACEBOOK),
prefs = prefs
)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt b/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt
index aef3fada..3bf37f7d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt
@@ -43,6 +43,7 @@ import com.pitchedapps.frost.db.NotificationDao
import com.pitchedapps.frost.db.selectNotificationsSync
import com.pitchedapps.frost.glide.FrostGlide
import com.pitchedapps.frost.glide.GlideApp
+import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.services.NotificationContent
import com.pitchedapps.frost.services.NotificationType
@@ -53,6 +54,7 @@ import org.koin.core.component.inject
class NotificationWidget : AppWidgetProvider(), KoinComponent {
private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
override fun onUpdate(
context: Context,
@@ -66,14 +68,14 @@ class NotificationWidget : AppWidgetProvider(), KoinComponent {
for (id in appWidgetIds) {
val views = RemoteViews(context.packageName, R.layout.widget_notifications)
- views.setBackgroundColor(R.id.widget_layout_toolbar, prefs.headerColor)
- views.setIcon(R.id.img_frost, context, R.drawable.frost_f_24, prefs.iconColor)
+ views.setBackgroundColor(R.id.widget_layout_toolbar, themeProvider.headerColor)
+ views.setIcon(R.id.img_frost, context, R.drawable.frost_f_24, themeProvider.iconColor)
views.setOnClickPendingIntent(
R.id.img_frost,
PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0)
)
- views.setBackgroundColor(R.id.widget_notification_list, prefs.bgColor)
+ views.setBackgroundColor(R.id.widget_notification_list, themeProvider.bgColor)
views.setRemoteAdapter(R.id.widget_notification_list, intent)
val pendingIntentTemplate = PendingIntent.getActivity(
@@ -156,7 +158,7 @@ class NotificationWidgetDataProvider(val context: Context, val intent: Intent) :
RemoteViewsService.RemoteViewsFactory,
KoinComponent {
- private val prefs: Prefs by inject()
+ private val themeProvider: ThemeProvider by inject()
private val notifDao: NotificationDao by inject()
@@ -192,10 +194,10 @@ class NotificationWidgetDataProvider(val context: Context, val intent: Intent) :
val views = RemoteViews(context.packageName, R.layout.widget_notification_item)
try {
val notif = content[position]
- views.setBackgroundColor(R.id.item_frame, prefs.nativeBgColor(notif.unread))
- views.setTextColor(R.id.item_content, prefs.textColor)
+ views.setBackgroundColor(R.id.item_frame, themeProvider.nativeBgColor(notif.unread))
+ views.setTextColor(R.id.item_content, themeProvider.textColor)
views.setTextViewText(R.id.item_content, notif.text)
- views.setTextColor(R.id.item_date, prefs.textColor.withAlpha(150))
+ views.setTextColor(R.id.item_date, themeProvider.textColor.withAlpha(150))
views.setTextViewText(R.id.item_date, notif.timestamp.toReadableTime(context))
val avatar = glide.load(notif.profileUrl).transform(FrostGlide.circleCrop)
diff --git a/app/src/main/play/en-US/whatsnew b/app/src/main/play/en-US/whatsnew
index 5e14d894..dc12e80e 100644
--- a/app/src/main/play/en-US/whatsnew
+++ b/app/src/main/play/en-US/whatsnew
@@ -1,4 +1,5 @@
-v2.4.7
+v3.0.0
-* Fix theme not always sticking on refresh
-* Disable long press menu from appearing immediately after scrolling \ No newline at end of file
+* Removed email support. Please use GitHub for all inquiries as I no longer have time to look through all emails
+* Added initial support for messenger.com (settings > appearance > main activity tabs)
+* Fix swipe to refresh not disabling for certain pages \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ee79b811..860895e5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -7,6 +7,7 @@
<string name="events">Events</string>
<string name="friends">Friends</string>
<string name="messages">Messages</string>
+ <string name="messenger">Messenger</string>
<string name="notifications">Notifications</string>
<string name="activity_log">Activity Log</string>
<string name="pages">Pages</string>
diff --git a/app/src/main/res/xml/frost_changelog.xml b/app/src/main/res/xml/frost_changelog.xml
index 6a526ccb..bdece3ae 100644
--- a/app/src/main/res/xml/frost_changelog.xml
+++ b/app/src/main/res/xml/frost_changelog.xml
@@ -6,13 +6,18 @@
<item text="" />
-->
- <version title="v2.4.7" />
- <item text="Fix theme not always sticking on refresh" />
- <item text="Disable long press menu from appearing immediately after scrolling" />
+ <version title="v3.0.0" />
+ <item text="Removed email support. Please use GitHub for all inquiries as I no longer have time to look through all emails" />
+ <item text="Added initial support for messenger.com (settings > appearance > main activity tabs)" />
+ <item text="Fix swipe to refresh not disabling for certain pages" />
<item text="" />
<item text="" />
<item text="" />
+ <version title="v2.4.7" />
+ <item text="Fix theme not always sticking on refresh" />
+ <item text="Disable long press menu from appearing immediately after scrolling" />
+
<version title="v2.4.6" />
<item text="Add option to hide likes and action bar in newsfeed" />
<item text="Fix textbox scroll position when typing multiple lines" />
diff --git a/app/src/schemas/com.pitchedapps.frost.db.FrostPrivateDatabase/2.json b/app/src/schemas/com.pitchedapps.frost.db.FrostPrivateDatabase/2.json
new file mode 100644
index 00000000..066f4478
--- /dev/null
+++ b/app/src/schemas/com.pitchedapps.frost.db.FrostPrivateDatabase/2.json
@@ -0,0 +1,201 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 2,
+ "identityHash": "c7625cc0226e291f14c14f528a11e739",
+ "entities": [
+ {
+ "tableName": "cookies",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cookie_id` INTEGER NOT NULL, `name` TEXT, `cookie` TEXT, `cookieMessenger` TEXT, PRIMARY KEY(`cookie_id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "cookie_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cookie",
+ "columnName": "cookie",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cookieMessenger",
+ "columnName": "cookieMessenger",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "cookie_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`notif_id` INTEGER NOT NULL, `userId` INTEGER NOT NULL, `href` TEXT NOT NULL, `title` TEXT, `text` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `profileUrl` TEXT, `type` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`notif_id`, `userId`), FOREIGN KEY(`userId`) REFERENCES `cookies`(`cookie_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "notif_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "href",
+ "columnName": "href",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timestamp",
+ "columnName": "timestamp",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "profileUrl",
+ "columnName": "profileUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "notif_id",
+ "userId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notifications_notif_id",
+ "unique": false,
+ "columnNames": [
+ "notif_id"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notifications_notif_id` ON `${TABLE_NAME}` (`notif_id`)"
+ },
+ {
+ "name": "index_notifications_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notifications_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "cookies",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "cookie_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "frost_cache",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, `contents` TEXT NOT NULL, PRIMARY KEY(`id`, `type`), FOREIGN KEY(`id`) REFERENCES `cookies`(`cookie_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastUpdated",
+ "columnName": "lastUpdated",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contents",
+ "columnName": "contents",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id",
+ "type"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "cookies",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "id"
+ ],
+ "referencedColumns": [
+ "cookie_id"
+ ]
+ }
+ ]
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c7625cc0226e291f14c14f528a11e739')"
+ ]
+ }
+} \ No newline at end of file
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbConstTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbConstTest.kt
new file mode 100644
index 00000000..83bce973
--- /dev/null
+++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbConstTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 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.facebook
+
+import kotlin.test.Test
+import kotlin.test.assertFalse
+
+class FbConstTest {
+
+ private val constants = listOf(
+ FACEBOOK_COM,
+ MESSENGER_COM,
+ FBCDN_NET,
+ WWW_FACEBOOK_COM,
+ WWW_MESSENGER_COM,
+ HTTPS_FACEBOOK_COM,
+ HTTPS_MESSENGER_COM,
+ FACEBOOK_BASE_COM,
+ FB_URL_BASE,
+ FACEBOOK_MBASIC_COM,
+ FB_URL_MBASIC_BASE,
+ FB_LOGIN_URL,
+ FB_HOME_URL,
+ MESSENGER_THREAD_PREFIX
+ )
+
+ /**
+ * Make sure we don't have accidental double forward slashes after appending
+ */
+ @Test
+ fun doubleForwardSlashTest() {
+ constants.forEach {
+ assertFalse(
+ it.replace("https://", "").contains("//"),
+ "Accidental forward slash for $it"
+ )
+ }
+ }
+}
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/injectors/CssAssetsTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/injectors/ThemeProviderTest.kt
index 8894e5b6..e1ef6225 100644
--- a/app/src/test/kotlin/com/pitchedapps/frost/injectors/CssAssetsTest.kt
+++ b/app/src/test/kotlin/com/pitchedapps/frost/injectors/ThemeProviderTest.kt
@@ -16,17 +16,21 @@
*/
package com.pitchedapps.frost.injectors
+import com.pitchedapps.frost.enums.Theme
+import com.pitchedapps.frost.enums.ThemeCategory
import java.io.File
import kotlin.test.Test
import kotlin.test.assertTrue
-class CssAssetsTest {
+class ThemeProviderTest {
@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}")
+ ThemeCategory.values().forEach { category ->
+ Theme.values.filter { it != Theme.DEFAULT }.forEach { theme ->
+ val file = File("src/web/assets/css/${category.folder}/themes/${theme.file}").absoluteFile
+ assertTrue(file.exists(), "${theme.name} not found at ${file.path}")
+ }
}
}
}
diff --git a/app/src/web/scss/core/_base.scss b/app/src/web/scss/core/_base.scss
index 472319fe..f6b5c903 100644
--- a/app/src/web/scss/core/_base.scss
+++ b/app/src/web/scss/core/_base.scss
@@ -1,4 +1,8 @@
@mixin placeholder {
+ ::placeholder {
+ @content;
+ }
+
::-webkit-input-placeholder {
@content;
}
@@ -14,6 +18,17 @@
:-ms-input-placeholder {
@content;
}
+
+ ::-ms-input-placeholder {
+ @content;
+ }
+}
+
+@mixin fill-available {
+ width: 100%;
+ max-width: -webkit-fill-available;
+ max-width: -moz-available;
+ max-width: fill-available;
}
@mixin keyframes($name) {
@@ -38,7 +53,12 @@
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
- @return if($index, str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace), $string);
+ @return if(
+ $index,
+ str-slice($string, 1, $index - 1) + $replace +
+ str-replace(str-slice($string, $index + str-length($search)), $search, $replace),
+ $string
+ );
}
// https://css-tricks.com/probably-dont-base64-svg/
diff --git a/app/src/web/scss/core/_colors.scss b/app/src/web/scss/core/_colors.scss
index 7610572c..ea75cc15 100644
--- a/app/src/web/scss/core/_colors.scss
+++ b/app/src/web/scss/core/_colors.scss
@@ -4,6 +4,7 @@ $bg_transparent: rgba(#f0f, 0.02) !default;
//Our default colors are test colors; production files should always import the actual colors
$text: #d7b0d7 !default;
+$text_disabled: rgba($text, 0.6) !default;
// must be visible with accent as the background
$accent_text: #76d7c2 !default;
$link: #9266d5 !default;
diff --git a/app/src/web/scss/core/_core_bg.scss b/app/src/web/scss/facebook/core/_core_bg.scss
index c5269ccf..c5269ccf 100644
--- a/app/src/web/scss/core/_core_bg.scss
+++ b/app/src/web/scss/facebook/core/_core_bg.scss
diff --git a/app/src/web/scss/core/_core_border.scss b/app/src/web/scss/facebook/core/_core_border.scss
index 1929e546..1929e546 100644
--- a/app/src/web/scss/core/_core_border.scss
+++ b/app/src/web/scss/facebook/core/_core_border.scss
diff --git a/app/src/web/scss/facebook/core/_core_hider.scss b/app/src/web/scss/facebook/core/_core_hider.scss
new file mode 100644
index 00000000..a166db3b
--- /dev/null
+++ b/app/src/web/scss/facebook/core/_core_hider.scss
@@ -0,0 +1,4 @@
+[data-sigil=m_login_upsell],
+[data-sigil="m-loading-indicator-animate m-loading-indicator-root"] {
+ display: none !important;
+} \ No newline at end of file
diff --git a/app/src/web/scss/core/_core_messenger.scss b/app/src/web/scss/facebook/core/_core_messages.scss
index 608fc23d..aa3c04eb 100644
--- a/app/src/web/scss/core/_core_messenger.scss
+++ b/app/src/web/scss/facebook/core/_core_messages.scss
@@ -1,4 +1,4 @@
-// Not all messenger related components are here; only the main ones.
+// Not all message related components are here; only the main ones.
// Borders for instance are merged into core_border
// Other person's message bubble
diff --git a/app/src/web/scss/core/_core_text.scss b/app/src/web/scss/facebook/core/_core_text.scss
index 8ac66758..8ac66758 100644
--- a/app/src/web/scss/core/_core_text.scss
+++ b/app/src/web/scss/facebook/core/_core_text.scss
diff --git a/app/src/web/scss/core/_main.scss b/app/src/web/scss/facebook/core/_main.scss
index 3e972f93..3e972f93 100644
--- a/app/src/web/scss/core/_main.scss
+++ b/app/src/web/scss/facebook/core/_main.scss
diff --git a/app/src/web/scss/core/_svg.scss b/app/src/web/scss/facebook/core/_svg.scss
index 9ed25433..9ed25433 100644
--- a/app/src/web/scss/core/_svg.scss
+++ b/app/src/web/scss/facebook/core/_svg.scss
diff --git a/app/src/web/scss/core/core.scss b/app/src/web/scss/facebook/core/core.scss
index 38086529..d7e790d1 100644
--- a/app/src/web/scss/core/core.scss
+++ b/app/src/web/scss/facebook/core/core.scss
@@ -1,9 +1,10 @@
-@import "colors";
-@import "base";
+@import "../../core/colors";
+@import "../../core/base";
@import "core_text";
@import "core_bg";
@import "core_border";
-@import "core_messenger";
+@import "core_messages";
+@import "core_hider";
//GLOBAL overrides; use with caution
*, *::after, *::before {
@@ -15,13 +16,8 @@
// box-shadow: none !important;
// }
-[data-sigil=m_login_upsell],
-[data-sigil="m-loading-indicator-animate m-loading-indicator-root"] {
- display: none !important;
-}
-
@include placeholder {
- color: $text !important;
+ color: $text_disabled !important;
}
.excessItem {
diff --git a/app/src/web/scss/themes/.gitignore b/app/src/web/scss/facebook/themes/.gitignore
index 4c46adff..4c46adff 100644
--- a/app/src/web/scss/themes/.gitignore
+++ b/app/src/web/scss/facebook/themes/.gitignore
diff --git a/app/src/web/scss/facebook/themes/custom.scss b/app/src/web/scss/facebook/themes/custom.scss
new file mode 100644
index 00000000..ab3d0f34
--- /dev/null
+++ b/app/src/web/scss/facebook/themes/custom.scss
@@ -0,0 +1,2 @@
+@import "../../palette/custom";
+@import "../core/main";
diff --git a/app/src/web/scss/facebook/themes/default.scss b/app/src/web/scss/facebook/themes/default.scss
new file mode 100644
index 00000000..92e352a7
--- /dev/null
+++ b/app/src/web/scss/facebook/themes/default.scss
@@ -0,0 +1 @@
+@import "../core/core_hider";
diff --git a/app/src/web/scss/facebook/themes/material_amoled.scss b/app/src/web/scss/facebook/themes/material_amoled.scss
new file mode 100644
index 00000000..4b1b5d17
--- /dev/null
+++ b/app/src/web/scss/facebook/themes/material_amoled.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_amoled";
+@import "../core/main";
diff --git a/app/src/web/scss/facebook/themes/material_dark.scss b/app/src/web/scss/facebook/themes/material_dark.scss
new file mode 100644
index 00000000..badec66d
--- /dev/null
+++ b/app/src/web/scss/facebook/themes/material_dark.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_dark";
+@import "../core/main";
diff --git a/app/src/web/scss/facebook/themes/material_glass.scss b/app/src/web/scss/facebook/themes/material_glass.scss
new file mode 100644
index 00000000..480def7f
--- /dev/null
+++ b/app/src/web/scss/facebook/themes/material_glass.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_glass";
+@import "../core/main";
diff --git a/app/src/web/scss/facebook/themes/material_light.scss b/app/src/web/scss/facebook/themes/material_light.scss
new file mode 100644
index 00000000..2a84f449
--- /dev/null
+++ b/app/src/web/scss/facebook/themes/material_light.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_light";
+@import "../core/main"; \ No newline at end of file
diff --git a/app/src/web/scss/messenger/core/_core_bg.scss b/app/src/web/scss/messenger/core/_core_bg.scss
new file mode 100644
index 00000000..92d3dd85
--- /dev/null
+++ b/app/src/web/scss/messenger/core/_core_bg.scss
@@ -0,0 +1,4 @@
+html, body, :root, #root,
+[style*="background-color: #FFFFFF"], [style*="background-color: #E4E6EB"] {
+ background: $bg_transparent !important;
+}
diff --git a/app/src/web/scss/messenger/core/_core_border.scss b/app/src/web/scss/messenger/core/_core_border.scss
new file mode 100644
index 00000000..10495a02
--- /dev/null
+++ b/app/src/web/scss/messenger/core/_core_border.scss
@@ -0,0 +1,3 @@
+[role="navigation"] {
+ border-right: 2px solid $bg_opaque2 !important;
+} \ No newline at end of file
diff --git a/app/src/web/scss/messenger/core/_core_hider.scss b/app/src/web/scss/messenger/core/_core_hider.scss
new file mode 100644
index 00000000..a2dbeb48
--- /dev/null
+++ b/app/src/web/scss/messenger/core/_core_hider.scss
@@ -0,0 +1,15 @@
+// Sizing adjustments
+[role="navigation"] {
+ .rq0escxv.l9j0dhe7.du4w35lb.j83agx80.g5gj957u.rj1gh0hx.buofh1pr.hpfvmrgz.i1fnvgqd.bp9cbjyn.owycx6da.btwxx1t3.dflh9lhu.scb9dxdr.sj5x9vvc.cxgpxx05.sn0e7ne5.f6rbj1fe.l3ldwz01 /* New! Messenger app for windows */,
+ .rq0escxv.l9j0dhe7.du4w35lb.n851cfcs.aahdfvyu /* Search messenger */,
+ .wkznzc2l /* Top left chat + menu entry */ {
+ display: none !important;
+ }
+}
+
+header[role="banner"] /* login banner */,
+._90px._9gb7 /* login bottom banner */,
+.rq0escxv.l9j0dhe7.du4w35lb.j83agx80.cbu4d94t.pfnyh3mw.d2edcug0.hpfvmrgz.p8fzw8mz.pcp91wgn.iuny7tx3.ipjc6fyt /* Top bar call video info icons */,
+.kuivcneq /* Right sidebar */ {
+ display: none !important;
+}
diff --git a/app/src/web/scss/messenger/core/_core_text.scss b/app/src/web/scss/messenger/core/_core_text.scss
new file mode 100644
index 00000000..7409cc4e
--- /dev/null
+++ b/app/src/web/scss/messenger/core/_core_text.scss
@@ -0,0 +1,3 @@
+html, body, input {
+ color: $text !important;
+} \ No newline at end of file
diff --git a/app/src/web/scss/messenger/core/_core_vars.scss b/app/src/web/scss/messenger/core/_core_vars.scss
new file mode 100644
index 00000000..66795299
--- /dev/null
+++ b/app/src/web/scss/messenger/core/_core_vars.scss
@@ -0,0 +1,34 @@
+:root, .__fb-light-mode {
+ --attachment-footer-background: #{$bg_opaque} !important;
+ --card-background-flat: #{$bg_opaque} !important;
+ --card-background: #{$bg_opaque} !important;
+ --comment-background: #{$bg_opaque2} !important;
+ --comment-footer-background: #{$bg_opaque} !important;
+ --disabled-button-background: #{$bg_opaque} !important;
+ --disabled-icon: #{$text_disabled} !important;
+ --disabled-text: #{$text_disabled} !important;
+ --divider: #{$divider} !important;
+ --hero-banner-background: #{$bg_opaque} !important;
+ --highlight-bg: #{$bg_opaque2} !important;
+ --media-outer-border: #{$bg_opaque} !important;
+ --messenger-card-background: #{$bg_opaque} !important;
+ --messenger-card-background: #{$bg_opaque} !important; // Main background; needs to be opaque to hide gradient used for sender card
+ --messenger-reply-background: #{$bg_opaque2} !important;
+ --nav-bar-background-gradient-wash: #{$bg_opaque} !important;
+ --nav-bar-background-gradient: #{$bg_opaque} !important;
+ --nav-bar-background: #{$bg_opaque} !important;
+ --new-notification-background: #{$bg_opaque2} !important;
+ --placeholder-text: #{$text} !important; // Date
+ --primary-icon: #{$text} !important;
+ --primary-text: #{$text} !important;
+ --secondary-icon: #{$text} !important;
+ --secondary-text: #{$text} !important;
+ --surface-background: #{$bg_opaque2} !important; // Emoji background
+ --toggle-active-background: #{$bg_opaque2} !important;
+ --wash: #{$bg_opaque2} !important;
+ --web-wash: #{$bg_opaque2} !important;
+
+ [role="navigation"] {
+ --surface-background: #{$bg_opaque} !important; // Nav background
+ }
+}
diff --git a/app/src/web/scss/messenger/core/_main.scss b/app/src/web/scss/messenger/core/_main.scss
new file mode 100644
index 00000000..e5da5377
--- /dev/null
+++ b/app/src/web/scss/messenger/core/_main.scss
@@ -0,0 +1,3 @@
+@import "core";
+
+//this file is used as the base for all messenger themes
diff --git a/app/src/web/scss/messenger/core/core.scss b/app/src/web/scss/messenger/core/core.scss
new file mode 100644
index 00000000..89199222
--- /dev/null
+++ b/app/src/web/scss/messenger/core/core.scss
@@ -0,0 +1,11 @@
+@import "../../core/colors";
+@import "../../core/base";
+@import "core_vars";
+@import "core_text";
+@import "core_bg";
+@import "core_border";
+@import "core_hider";
+
+@include placeholder {
+ color: $text_disabled !important;
+} \ No newline at end of file
diff --git a/app/src/web/scss/messenger/themes/.gitignore b/app/src/web/scss/messenger/themes/.gitignore
new file mode 100644
index 00000000..4c46adff
--- /dev/null
+++ b/app/src/web/scss/messenger/themes/.gitignore
@@ -0,0 +1 @@
+test.scss
diff --git a/app/src/web/scss/messenger/themes/custom.scss b/app/src/web/scss/messenger/themes/custom.scss
new file mode 100644
index 00000000..ab3d0f34
--- /dev/null
+++ b/app/src/web/scss/messenger/themes/custom.scss
@@ -0,0 +1,2 @@
+@import "../../palette/custom";
+@import "../core/main";
diff --git a/app/src/web/scss/messenger/themes/default.scss b/app/src/web/scss/messenger/themes/default.scss
new file mode 100644
index 00000000..92e352a7
--- /dev/null
+++ b/app/src/web/scss/messenger/themes/default.scss
@@ -0,0 +1 @@
+@import "../core/core_hider";
diff --git a/app/src/web/scss/messenger/themes/material_amoled.scss b/app/src/web/scss/messenger/themes/material_amoled.scss
new file mode 100644
index 00000000..4b1b5d17
--- /dev/null
+++ b/app/src/web/scss/messenger/themes/material_amoled.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_amoled";
+@import "../core/main";
diff --git a/app/src/web/scss/messenger/themes/material_dark.scss b/app/src/web/scss/messenger/themes/material_dark.scss
new file mode 100644
index 00000000..badec66d
--- /dev/null
+++ b/app/src/web/scss/messenger/themes/material_dark.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_dark";
+@import "../core/main";
diff --git a/app/src/web/scss/messenger/themes/material_glass.scss b/app/src/web/scss/messenger/themes/material_glass.scss
new file mode 100644
index 00000000..480def7f
--- /dev/null
+++ b/app/src/web/scss/messenger/themes/material_glass.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_glass";
+@import "../core/main";
diff --git a/app/src/web/scss/messenger/themes/material_light.scss b/app/src/web/scss/messenger/themes/material_light.scss
new file mode 100644
index 00000000..2a84f449
--- /dev/null
+++ b/app/src/web/scss/messenger/themes/material_light.scss
@@ -0,0 +1,2 @@
+@import "../../palette/material_light";
+@import "../core/main"; \ No newline at end of file
diff --git a/app/src/web/scss/themes/custom.scss b/app/src/web/scss/palette/_custom.scss
index 50c029fb..0adb7768 100644
--- a/app/src/web/scss/themes/custom.scss
+++ b/app/src/web/scss/palette/_custom.scss
@@ -1,5 +1,6 @@
$bg_transparent: unquote('$BT$');
$text: unquote('$T$');
+$text_disabled: unquote('$TD$');
$link: unquote('$TT$');
$accent: unquote('$A$');
$accent_text: unquote('$AT$');
@@ -10,5 +11,3 @@ $bg_opaque2: unquote('$OO$');
$divider: unquote('$D$');
$card: unquote('$C$');
$tint: unquote('$TI$');
-
-@import "../core/main";
diff --git a/app/src/web/scss/themes/material_amoled.scss b/app/src/web/scss/palette/_material_amoled.scss
index 19190126..3eca36bc 100644
--- a/app/src/web/scss/themes/material_amoled.scss
+++ b/app/src/web/scss/palette/_material_amoled.scss
@@ -7,5 +7,3 @@ $background2: rgba($background, 0.35);
$bg_transparent: $background;
$card: $background2;
$tint: rgba(#fff, 0.2);
-
-@import "../core/main";
diff --git a/app/src/web/scss/themes/material_dark.scss b/app/src/web/scss/palette/_material_dark.scss
index 18b8b461..a27627c0 100644
--- a/app/src/web/scss/themes/material_dark.scss
+++ b/app/src/web/scss/palette/_material_dark.scss
@@ -6,5 +6,3 @@ $background: #303030;
$bg_transparent: $background;
$card: #353535;
$tint: rgba(#fff, 0.2);
-
-@import "../core/main";
diff --git a/app/src/web/scss/themes/material_glass.scss b/app/src/web/scss/palette/_material_glass.scss
index 0c61a38c..c9e399e7 100644
--- a/app/src/web/scss/themes/material_glass.scss
+++ b/app/src/web/scss/palette/_material_glass.scss
@@ -5,6 +5,4 @@ $accent: #5d86dd;
$background: rgba(#000, 0.1);
$bg_transparent: transparent;
$card: rgba(#000, 0.25);
-$tint: rgba(#fff, 0.15);
-
-@import "../core/main";
+$tint: rgba(#fff, 0.15); \ No newline at end of file
diff --git a/app/src/web/scss/themes/material_light.scss b/app/src/web/scss/palette/_material_light.scss
index 7ec58463..2a799180 100644
--- a/app/src/web/scss/themes/material_light.scss
+++ b/app/src/web/scss/palette/_material_light.scss
@@ -10,6 +10,4 @@ $background2: rgba(darken($background, 8%), 0.35);
$bg_transparent: $background;
$card: #fff;
-$tint: #ddd;
-
-@import "../core/main"; \ No newline at end of file
+$tint: #ddd; \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt
index 6ed9d7b9..fc6aae95 100644
--- a/buildSrc/src/main/kotlin/Versions.kt
+++ b/buildSrc/src/main/kotlin/Versions.kt
@@ -16,7 +16,7 @@ object Versions {
// https://square.github.io/okhttp/changelog/
const val okhttp = "4.9.0"
// https://developer.android.com/jetpack/androidx/releases/room
- const val room = "2.2.5"
+ const val room = "2.2.6"
// http://robolectric.org/getting-started/
const val roboelectric = "4.4"
// https://github.com/davemorrissey/subsampling-scale-image-view#quick-start
diff --git a/docs/Changelog.md b/docs/Changelog.md
index caf30a00..9f4712c5 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -1,5 +1,10 @@
# Changelog
+## v3.0.0
+* Removed email support. Please use GitHub for all inquiries as I no longer have time to look through all emails
+* Added initial support for messenger.com (settings > appearance > main activity tabs)
+* Fix swipe to refresh not disabling for certain pages
+
## v2.4.7
* Fix theme not always sticking on refresh
* Disable long press menu from appearing immediately after scrolling