1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-08 12:02:33 +01:00

Move prefs to service locator

This commit is contained in:
Allan Wang 2020-02-23 16:06:45 -08:00
parent 4d5aaf541d
commit c8b54fd10a
No known key found for this signature in database
GPG Key ID: C93E3F9C679D7A56
62 changed files with 660 additions and 468 deletions

View File

@ -19,6 +19,8 @@ package com.pitchedapps.frost
import android.app.Activity
import android.app.Application
import android.os.Bundle
import ca.allanwang.kau.kpref.KPrefFactory
import ca.allanwang.kau.kpref.KPrefFactoryAndroid
import ca.allanwang.kau.logging.KL
import ca.allanwang.kau.utils.buildIsLollipopAndUp
import com.bugsnag.android.Bugsnag
@ -31,21 +33,42 @@ import com.pitchedapps.frost.utils.FrostPglAdBlock
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.Showcase
import java.util.Random
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.KoinComponent
import org.koin.core.context.startKoin
import org.koin.core.get
import org.koin.core.module.Module
import org.koin.dsl.module
import java.util.Random
/**
* Created by Allan Wang on 2017-05-28.
*/
class FrostApp : Application() {
class FrostApp : Application(), KoinComponent {
private lateinit var showcasePrefs: Showcase
private lateinit var prefs: Prefs
override fun onCreate() {
startKoin {
if (BuildConfig.DEBUG) {
androidLogger()
}
androidContext(this@FrostApp)
modules(listOf(
FrostDatabase.module(),
prefFactoryModule(),
Prefs.module(),
Showcase.module()
))
}
if (!buildIsLollipopAndUp) { // not supported
super.onCreate()
return
}
prefs = get()
showcasePrefs = get()
initPrefs()
initBugsnag()
@ -54,9 +77,9 @@ class FrostApp : Application() {
super.onCreate()
setupNotificationChannels(applicationContext)
setupNotificationChannels(this, prefs)
scheduleNotificationsFromPrefs()
scheduleNotificationsFromPrefs(prefs)
if (BuildConfig.DEBUG) {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
@ -77,27 +100,20 @@ class FrostApp : Application() {
}
})
}
startKoin {
if (BuildConfig.DEBUG) {
androidLogger()
}
androidContext(this@FrostApp)
modules(FrostDatabase.module(this@FrostApp))
}
}
private fun initPrefs() {
Showcase.initialize(this, "${BuildConfig.APPLICATION_ID}.showcase")
Prefs.initialize(this, "${BuildConfig.APPLICATION_ID}.prefs")
prefs.deleteKeys("search_bar")
showcasePrefs.deleteKeys("shown_release", "experimental_by_default")
KL.shouldLog = { BuildConfig.DEBUG }
Prefs.verboseLogging = false
if (Prefs.installDate == -1L) {
Prefs.installDate = System.currentTimeMillis()
prefs.verboseLogging = false
if (prefs.installDate == -1L) {
prefs.installDate = System.currentTimeMillis()
}
if (Prefs.identifier == -1) {
Prefs.identifier = Random().nextInt(Int.MAX_VALUE)
if (prefs.identifier == -1) {
prefs.identifier = Random().nextInt(Int.MAX_VALUE)
}
Prefs.lastLaunch = System.currentTimeMillis()
prefs.lastLaunch = System.currentTimeMillis()
}
private fun initBugsnag() {
@ -113,12 +129,12 @@ class FrostApp : Application() {
appVersion = version.versionName
releaseStage = BuildUtils.getStage(BuildConfig.BUILD_TYPE)
notifyReleaseStages = BuildUtils.getAllStages()
autoCaptureSessions = Prefs.analytics
enableExceptionHandler = Prefs.analytics
autoCaptureSessions = prefs.analytics
enableExceptionHandler = prefs.analytics
}
Bugsnag.init(this, config)
L.bugsnagInit = true
Bugsnag.setUserId(Prefs.frostId)
Bugsnag.setUserId(prefs.frostId)
Bugsnag.addToTab("Build", "Application", BuildConfig.APPLICATION_ID)
Bugsnag.addToTab("Build", "Version", BuildConfig.VERSION_NAME)
@ -129,4 +145,12 @@ class FrostApp : Application() {
}
}
}
companion object {
fun prefFactoryModule(): Module = module {
single<KPrefFactory> {
KPrefFactoryAndroid(get())
}
}
}
}

View File

@ -52,6 +52,7 @@ import org.koin.android.ext.android.inject
*/
class StartActivity : KauBaseActivity() {
private val prefs: Prefs by inject()
private val cookieDao: CookieDao by inject()
private val genericDao: GenericDao by inject()
@ -82,12 +83,12 @@ class StartActivity : KauBaseActivity() {
transform = CookieEntity::toSensitiveString
)}"
}
loadAssets()
loadAssets(prefs)
authDefer.await()
when {
cookies.isEmpty() -> launchNewTask<LoginActivity>()
// Has cookies but no selected account
Prefs.userId == -1L -> launchNewTask<SelectorActivity>(cookies)
prefs.userId == -1L -> launchNewTask<SelectorActivity>(cookies)
else -> startActivity<MainActivity>(intentBuilder = {
putParcelableArrayListExtra(EXTRA_COOKIES, cookies)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or

View File

@ -49,20 +49,25 @@ import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import org.koin.android.ext.android.inject
/**
* Created by Allan Wang on 2017-06-26.
*/
class AboutActivity : AboutActivityBase(null, {
textColor = Prefs.textColor
accentColor = Prefs.accentColor
backgroundColor = Prefs.bgColor.withMinAlpha(200)
cutoutForeground = Prefs.accentColor
cutoutDrawableRes = R.drawable.frost_f_200
faqPageTitleRes = R.string.faq_title
faqXmlRes = R.xml.frost_faq
faqParseNewLine = false
}) {
class AboutActivity : AboutActivityBase(null) {
private val prefs: Prefs by inject()
override fun Configs.buildConfigs() {
textColor = prefs.textColor
accentColor = prefs.accentColor
backgroundColor = prefs.bgColor.withMinAlpha(200)
cutoutForeground = prefs.accentColor
cutoutDrawableRes = R.drawable.frost_f_200
faqPageTitleRes = R.string.faq_title
faqXmlRes = R.xml.frost_faq
faqParseNewLine = false
}
override fun getLibraries(libs: Libs): List<Library> {
val include = arrayOf(
@ -121,8 +126,8 @@ class AboutActivity : AboutActivityBase(null, {
clickCount++
lastClick = now
if (clickCount == 8) {
if (!Prefs.debugSettings) {
Prefs.debugSettings = true
if (!prefs.debugSettings) {
prefs.debugSettings = true
L.d { "Debugging section enabled" }
toast(R.string.debug_toast_enabled)
} else {

View File

@ -21,13 +21,17 @@ import android.os.Bundle
import ca.allanwang.kau.internal.KauBaseActivity
import ca.allanwang.kau.searchview.SearchViewHolder
import com.pitchedapps.frost.contracts.VideoViewHolder
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.setFrostTheme
import org.koin.android.ext.android.inject
/**
* Created by Allan Wang on 2017-06-12.
*/
abstract class BaseActivity : KauBaseActivity() {
val prefs: Prefs by inject()
/**
* Inherited consumer to customize back press
*/

View File

@ -177,7 +177,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
val start = System.currentTimeMillis()
drawerWrapperBinding = ActivityMainDrawerWrapperBinding.inflate(layoutInflater)
setContentView(drawerWrapperBinding.root)
contentBinding = when (Prefs.mainActivityLayout) {
contentBinding = when (prefs.mainActivityLayout) {
MainActivityLayout.TOP_BAR -> {
val binding = ActivityMainBinding.inflate(layoutInflater)
object : ActivityMainContentBinding {
@ -211,7 +211,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
setSupportActionBar(toolbar)
viewpager.adapter = adapter
tabs.setBackgroundColor(Prefs.mainActivityLayout.backgroundColor())
tabs.setBackgroundColor(prefs.mainActivityLayout.backgroundColor(prefs))
}
onNestedCreate(savedInstanceState)
L.i { "Main finished loading UI in ${System.currentTimeMillis() - start} ms" }
@ -219,18 +219,18 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
adapter.setPages(genericDao.getTabs())
}
controlWebview = WebView(this)
if (BuildConfig.VERSION_CODE > Prefs.versionCode) {
Prefs.prevVersionCode = Prefs.versionCode
Prefs.versionCode = BuildConfig.VERSION_CODE
if (BuildConfig.VERSION_CODE > prefs.versionCode) {
prefs.prevVersionCode = prefs.versionCode
prefs.versionCode = BuildConfig.VERSION_CODE
if (!BuildConfig.DEBUG) {
frostChangelog()
frostEvent(
"Version",
"Version code" to BuildConfig.VERSION_CODE,
"Prev version code" to Prefs.prevVersionCode,
"Prev version code" to prefs.prevVersionCode,
"Version name" to BuildConfig.VERSION_NAME,
"Build type" to BuildConfig.BUILD_TYPE,
"Frost id" to Prefs.frostId
"Frost id" to prefs.frostId
)
}
}
@ -289,7 +289,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
drawer.addDrawerListener(toggle)
toggle.syncState()
val foregroundColor = ColorStateList.valueOf(Prefs.textColor)
val foregroundColor = ColorStateList.valueOf(prefs.textColor)
with(navigation) {
FrostMenuBuilder(this@BaseMainActivity, menu).apply {
@ -318,9 +318,9 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
launchWebOverlay(item.url)
false
}
val navBg = Prefs.bgColor.withMinAlpha(200)
val navBg = prefs.bgColor.withMinAlpha(200)
setBackgroundColor(navBg)
itemBackground = createNavDrawable(Prefs.accentColor, navBg)
itemBackground = createNavDrawable(prefs.accentColor, navBg)
itemTextColor = foregroundColor
itemIconTintList = foregroundColor
@ -332,7 +332,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(prefs.headerColor.withMinAlpha(200))
fab.hide()
appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
if (!hasFab) return@OnOffsetChangedListener
@ -352,12 +352,12 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
if (shouldShow) {
if (fab.isShown) {
fab.fadeScaleTransition {
setIcon(iicon, color = Prefs.iconColor)
setIcon(iicon, color = prefs.iconColor)
}
return
}
}
fab.setIcon(iicon, color = Prefs.iconColor)
fab.setIcon(iicon, color = prefs.iconColor)
fab.showIf(shouldShow)
}
}
@ -384,12 +384,12 @@ 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 = prefs.bgColor.withMinAlpha(200).colorToForeground(
0.1f
)
init {
setPrimary(Prefs.userId)
setPrimary(prefs.userId)
binding.updateAccounts()
with(drawerWrapperBinding) {
drawer.addDrawerListener(object : DrawerLayout.SimpleDrawerListener() {
@ -449,7 +449,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
animator.start()
}
val textColor = Prefs.textColor
val textColor = prefs.textColor
fun TextView.setOptionsIcon(iicon: IIcon) {
setCompoundDrawablesRelativeWithIntrinsicBounds(
@ -459,7 +459,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
null
)
setTextColor(textColor)
background = createNavDrawable(Prefs.accentColor, optionsBackground)
background = createNavDrawable(prefs.accentColor, optionsBackground)
}
with(optionsLogout) {
@ -478,7 +478,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
text =
String.format(
string(R.string.kau_logout_confirm_as_x),
currentCookie.name ?: Prefs.userId.toString()
currentCookie.name ?: prefs.userId.toString()
)
)
positiveButton(R.string.kau_yes) {
@ -507,7 +507,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
arrow.setImageDrawable(
GoogleMaterial.Icon.gmd_arrow_drop_down.toDrawable(
this@BaseMainActivity,
color = Prefs.textColor
color = prefs.textColor
)
)
}
@ -532,10 +532,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(prefs.textColor)
val glide = Glide.with(root)
val accountSize = dimenPixelSize(R.dimen.drawer_account_avatar_size)
val textColor = Prefs.textColor
val textColor = prefs.textColor
orderedAccounts.forEach { cookie ->
val tv =
TextView(
@ -569,7 +569,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
})
tv.text = cookie.name
tv.setTextColor(textColor)
tv.background = createNavDrawable(Prefs.accentColor, optionsBackground)
tv.background = createNavDrawable(prefs.accentColor, optionsBackground)
tv.setOnClickListener {
switchAccount(cookie.id)
}
@ -608,7 +608,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
private fun switchAccount(id: Long) {
if (Prefs.userId == id) return
if (prefs.userId == id) return
setPrimary(id)
pendingUpdate = true
closeDrawer()
@ -627,9 +627,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(prefs.iconColor)
setMenuIcons(
menu, Prefs.iconColor,
menu, prefs.iconColor,
R.id.action_settings to GoogleMaterial.Icon.gmd_settings,
R.id.action_search to GoogleMaterial.Icon.gmd_search
)
@ -639,7 +639,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, prefs.iconColor) {
textCallback = { query, searchView ->
val results = searchViewCache[query]
if (results != null)
@ -665,8 +665,8 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
searchCallback =
{ query, _ -> launchWebOverlay("${FbItem._SEARCH.url}/?q=$query"); true }
closeListener = { _ -> searchViewCache.clear() }
foregroundColor = Prefs.textColor
backgroundColor = Prefs.bgColor.withMinAlpha(200)
foregroundColor = prefs.textColor
backgroundColor = prefs.bgColor.withMinAlpha(200)
onItemClick = { _, key, _, _ -> launchWebOverlay(key) }
}
}
@ -737,7 +737,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
fragmentChannel.offer(lastPosition)
}
if (hasRequest(REQUEST_NOTIFICATION)) {
scheduleNotificationsFromPrefs()
scheduleNotificationsFromPrefs(prefs)
}
}
}
@ -761,7 +761,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
val authDefer = BiometricUtils.authenticate(this@BaseMainActivity)
FbCookie.switchBackUser()
authDefer.await()
if (shouldReload && Prefs.autoRefreshFeed) {
if (shouldReload && prefs.autoRefreshFeed) {
refreshAll()
}
}
@ -794,14 +794,14 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
}
if (currentFragment.onBackPressed()) return true
if (Prefs.exitConfirmation) {
if (prefs.exitConfirmation) {
materialDialog {
title(R.string.kau_exit)
message(R.string.kau_exit_confirmation)
positiveButton(R.string.kau_yes) { finish() }
negativeButton(R.string.kau_no)
checkBoxPrompt(R.string.kau_do_not_show_again, isCheckedDefault = false) {
Prefs.exitConfirmation = !it
prefs.exitConfirmation = !it
}
}
return true
@ -879,6 +879,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
val item = pages[position]
return BaseFragment(
item.fragmentCreator,
prefs,
forcedFallbacks.contains(item.name),
item,
position
@ -901,7 +902,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
override val lowerVideoPadding: PointF
get() {
if (Prefs.mainActivityLayout == MainActivityLayout.BOTTOM_BAR)
if (prefs.mainActivityLayout == MainActivityLayout.BOTTOM_BAR)
lowerVideoPaddingPointF.set(0f, contentBinding.toolbar.height.toFloat())
else
lowerVideoPaddingPointF.set(0f, 0f)

View File

@ -38,11 +38,13 @@ import java.io.File
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineExceptionHandler
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 05/01/18.
*/
class DebugActivity : KauBaseActivity() {
class DebugActivity : KauBaseActivity(), KoinComponent {
companion object {
const val RESULT_URL = "extra_result_url"
@ -51,6 +53,8 @@ class DebugActivity : KauBaseActivity() {
fun baseDir(context: Context) = File(context.externalCacheDir, "offline_debug")
}
private val prefs: Prefs by inject()
lateinit var binding: ActivityDebugBinding
override fun onCreate(savedInstanceState: Bundle?) {
@ -76,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, prefs.iconColor)
fab.backgroundTintList = ColorStateList.valueOf(prefs.accentColor)
fab.setOnClickListener { _ ->
fab.hide()

View File

@ -67,6 +67,14 @@ import com.pitchedapps.frost.utils.isIndirectImageUrl
import com.pitchedapps.frost.utils.logFrostEvent
import com.pitchedapps.frost.utils.sendFrostEmail
import com.pitchedapps.frost.utils.setFrostColors
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.inject
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
@ -75,17 +83,13 @@ import java.util.Date
import java.util.Locale
import kotlin.math.abs
import kotlin.math.max
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* Created by Allan Wang on 2017-07-15.
*/
class ImageActivity : KauBaseActivity() {
class ImageActivity : KauBaseActivity(), KoinComponent {
private val prefs: Prefs by inject()
@Volatile
internal var errorRef: Throwable? = null
@ -106,7 +110,7 @@ class ImageActivity : KauBaseActivity() {
set(value) {
if (field == value) return
field = value
value.update(binding.imageFab)
value.update(binding.imageFab, prefs)
}
private lateinit var dragHelper: ViewDragHelper
@ -144,8 +148,8 @@ class ImageActivity : KauBaseActivity() {
private lateinit var binding: ActivityImageBinding
private var bottomBehavior: BottomSheetBehavior<View>? = null
private val baseBackgroundColor = if (Prefs.blackMediaBg) Color.BLACK
else Prefs.bgColor.withMinAlpha(235)
private val baseBackgroundColor = if (prefs.blackMediaBg) Color.BLACK
else prefs.bgColor.withMinAlpha(235)
private fun loadError(e: Throwable) {
if (e.message?.contains("<!DOCTYPE html>") == true) {
@ -195,9 +199,9 @@ 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 prefs.textColor)
imageText.setBackgroundColor(
(if (Prefs.blackMediaBg) Color.BLACK else Prefs.bgColor)
(if (prefs.blackMediaBg) Color.BLACK else prefs.bgColor)
.colorToForeground(0.2f).withAlpha(255)
)
imageText.text = text
@ -217,7 +221,7 @@ class ImageActivity : KauBaseActivity() {
imageText.bringToFront()
}
}
imageProgress.tint(if (Prefs.blackMediaBg) Color.WHITE else Prefs.accentColor)
imageProgress.tint(if (prefs.blackMediaBg) Color.WHITE else prefs.accentColor)
imageFab.setOnClickListener { fabAction.onClick(this@ImageActivity) }
imagePhoto.setOnImageEventListener(object :
SubsamplingScaleImageView.DefaultOnImageEventListener() {
@ -405,10 +409,10 @@ class ImageActivity : KauBaseActivity() {
internal enum class FabStates(
val iicon: IIcon,
val iconColor: Int = Prefs.iconColor,
val iconColorProvider: (Prefs) -> Int = { it.iconColor },
val backgroundTint: Int = Int.MAX_VALUE
) {
ERROR(GoogleMaterial.Icon.gmd_error, Color.WHITE, Color.RED) {
ERROR(GoogleMaterial.Icon.gmd_error, { Color.WHITE }, Color.RED) {
override fun onClick(activity: ImageActivity) {
val err =
activity.errorRef?.takeIf { it !is FileNotFoundException && it.message != "Image failed to decode using JPEG decoder" }
@ -460,8 +464,9 @@ internal enum class FabStates(
* https://github.com/AllanWang/KAU/issues/184
*
*/
fun update(fab: FloatingActionButton) {
val tint = if (backgroundTint != Int.MAX_VALUE) backgroundTint else Prefs.accentColor
fun update(fab: FloatingActionButton, prefs: Prefs) {
val tint = if (backgroundTint != Int.MAX_VALUE) backgroundTint else prefs.accentColor
val iconColor = iconColorProvider(prefs)
if (fab.isHidden) {
fab.setIcon(iicon, color = iconColor)
fab.backgroundTintList = ColorStateList.valueOf(tint)

View File

@ -55,6 +55,8 @@ import com.pitchedapps.frost.utils.setFrostTheme
import com.pitchedapps.frost.widgets.NotificationWidget
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-07-25.
@ -62,8 +64,10 @@ import kotlinx.coroutines.launch
* A beautiful intro activity
* Phone showcases are drawn via layers
*/
class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.OnPageChangeListener {
class IntroActivity : KauBaseActivity(), KoinComponent, ViewPager.PageTransformer,
ViewPager.OnPageChangeListener {
private val prefs: Prefs by inject()
lateinit var binding: ActivityIntroBinding
private var barHasNext = true
@ -97,17 +101,17 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On
else finish(next.x + next.pivotX, next.y + next.pivotY)
}
skip.setOnClickListener { finish() }
ripple.set(Prefs.bgColor)
ripple.set(prefs.bgColor)
theme()
}
fun theme() {
statusBarColor = Prefs.headerColor
navigationBarColor = Prefs.headerColor
statusBarColor = prefs.headerColor
navigationBarColor = prefs.headerColor
with(binding) {
skip.setTextColor(Prefs.textColor)
next.imageTintList = ColorStateList.valueOf(Prefs.textColor)
indicator.setColour(Prefs.textColor)
skip.setTextColor(prefs.textColor)
next.imageTintList = ColorStateList.valueOf(prefs.textColor)
indicator.setColour(prefs.textColor)
indicator.invalidate()
}
fragments.forEach { it.themeFragment() }
@ -149,21 +153,21 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On
).forEach {
it?.animate()?.alpha(0f)?.setDuration(600)?.start()
}
if (Prefs.textColor != Color.WHITE) {
if (prefs.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(prefs.textColor.blendWith(Color.WHITE, it.animatedValue as Float))
}
duration = 600
start()
}
}
if (Prefs.headerColor != blue) {
if (prefs.headerColor != blue) {
ValueAnimator.ofFloat(0f, 1f).apply {
addUpdateListener {
val c = Prefs.headerColor.blendWith(blue, it.animatedValue as Float)
val c = prefs.headerColor.blendWith(blue, it.animatedValue as Float)
statusBarColor = c
navigationBarColor = c
}
@ -175,7 +179,7 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On
override fun finish() {
launch(NonCancellable) {
loadAssets()
loadAssets(prefs)
NotificationWidget.forceUpdate(this@IntroActivity)
launchNewTask<MainActivity>(cookies(), false)
super.finish()
@ -206,7 +210,7 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On
binding.next.fadeScaleTransition {
setIcon(
if (barHasNext) GoogleMaterial.Icon.gmd_navigate_next else GoogleMaterial.Icon.gmd_done,
color = Prefs.textColor
color = prefs.textColor
)
}
binding.skip.animate().scaleXY(if (barHasNext) 1f else 0f)

View File

@ -73,6 +73,7 @@ class LoginActivity : BaseActivity() {
private val textview: AppCompatTextView by bindView(R.id.textview)
private val profile: ImageView by bindView(R.id.profile)
private val cookieDao: CookieDao by inject()
private val showcasePrefs: Showcase by inject()
private lateinit var profileLoader: RequestManager
private val refreshChannel = Channel<Boolean>(10)
@ -138,7 +139,7 @@ class LoginActivity : BaseActivity() {
*/
val cookies = ArrayList(cookieDao.selectAll())
delay(1000)
if (Showcase.intro)
if (showcasePrefs.intro)
launchNewTask<IntroActivity>(cookies, true)
else
launchNewTask<MainActivity>(cookies, true)

View File

@ -61,12 +61,15 @@ import com.pitchedapps.frost.utils.loadAssets
import com.pitchedapps.frost.utils.setFrostTheme
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
/**
* Created by Allan Wang on 2017-06-06.
*/
class SettingsActivity : KPrefActivity() {
val prefs: Prefs by inject()
private var resultFlag = Activity.RESULT_CANCELED
companion object {
@ -117,11 +120,11 @@ class SettingsActivity : KPrefActivity() {
}
when (requestCode) {
REQUEST_NOTIFICATION_RINGTONE -> {
Prefs.notificationRingtone = uriString
prefs.notificationRingtone = uriString
reloadByTitle(R.string.notification_ringtone)
}
REQUEST_MESSAGE_RINGTONE -> {
Prefs.messageRingtone = uriString
prefs.messageRingtone = uriString
reloadByTitle(R.string.message_ringtone)
}
}
@ -129,8 +132,8 @@ class SettingsActivity : KPrefActivity() {
}
override fun kPrefCoreAttributes(): CoreAttributeContract.() -> Unit = {
textColor = { Prefs.textColor }
accentColor = { Prefs.accentColor }
textColor = { prefs.textColor }
accentColor = { prefs.accentColor }
}
override fun onCreateKPrefs(savedInstanceState: Bundle?): KPrefAdapterBuilder.() -> Unit = {
@ -195,7 +198,7 @@ class SettingsActivity : KPrefActivity() {
subItems(R.string.debug_frost, getDebugPrefs()) {
descRes = R.string.debug_frost_desc
iicon = CommunityMaterial.Icon.cmd_android_debug_bridge
visible = { Prefs.debugSettings }
visible = { prefs.debugSettings }
}
}
@ -215,15 +218,15 @@ class SettingsActivity : KPrefActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setFrostTheme(true)
super.onCreate(savedInstanceState)
animate = Prefs.animate
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)
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()
}
@ -231,7 +234,7 @@ class SettingsActivity : KPrefActivity() {
if (!super.backPress()) {
setResult(resultFlag)
launch(NonCancellable) {
loadAssets()
loadAssets(prefs)
finishSlideOut()
}
}
@ -239,9 +242,9 @@ class SettingsActivity : KPrefActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_settings, menu)
toolbar.tint(Prefs.iconColor)
toolbar.tint(prefs.iconColor)
setMenuIcons(
menu, Prefs.iconColor,
menu, prefs.iconColor,
R.id.action_email to GoogleMaterial.Icon.gmd_email,
R.id.action_changelog to GoogleMaterial.Icon.gmd_info
)

View File

@ -42,12 +42,11 @@ import com.pitchedapps.frost.db.saveTabs
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.iitems.TabIItem
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.setFrostColors
import java.util.Collections
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import java.util.Collections
/**
* Created by Allan Wang on 26/11/17.
@ -70,15 +69,15 @@ class TabCustomizerActivity : BaseActivity() {
}
fun ActivityTabCustomizerBinding.init() {
pseudoToolbar.setBackgroundColor(Prefs.headerColor)
pseudoToolbar.setBackgroundColor(prefs.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(prefs.textColor.withAlpha(30))
instructions.setTextColor(prefs.textColor)
launch {
val tabs = genericDao.getTabs().toMutableList()
@ -95,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, prefs.iconColor)
fabSave.backgroundTintList = ColorStateList.valueOf(prefs.accentColor)
fabSave.setOnClickListener {
launchMain(NonCancellable) {
val tabs = adapter.adapterItems.subList(0, TAB_COUNT).map(TabIItem::item)
@ -105,8 +104,8 @@ class TabCustomizerActivity : BaseActivity() {
finish()
}
}
fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, Prefs.iconColor)
fabCancel.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor)
fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, prefs.iconColor)
fabCancel.backgroundTintList = ColorStateList.valueOf(prefs.accentColor)
fabCancel.setOnClickListener { finish() }
setFrostColors {
themeWindow = true

View File

@ -78,6 +78,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.koin.android.ext.android.inject
/**
* Created by Allan Wang on 2017-06-01.
@ -170,6 +171,8 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
get() = content.coreView
private val coordinator: CoordinatorLayout by bindView(R.id.overlay_main_content)
private val showcasePrefs: Showcase by inject()
private inline val urlTest: String?
get() = intent.getStringExtra(ARG_URL) ?: intent.dataString
@ -184,7 +187,7 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
override val baseEnum: FbItem? = null
private inline val userId: Long
get() = intent.getLongExtra(ARG_USER_ID, Prefs.userId)
get() = intent.getLongExtra(ARG_USER_ID, prefs.userId)
private val overlayContext: OverlayContext?
get() = OverlayContext[intent.extras]
@ -205,14 +208,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, prefs.iconColor)
toolbar.setNavigationOnClickListener { finishSlideOut() }
setFrostColors {
toolbar(toolbar)
themeWindow = false
}
coordinator.setBackgroundColor(Prefs.bgColor.withAlpha(255))
coordinator.setBackgroundColor(prefs.bgColor.withAlpha(255))
content.bind(this)
@ -222,15 +225,15 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
with(web) {
userAgentString = userAgent
Prefs.prevId = Prefs.userId
prefs.prevId = prefs.userId
launch {
val authDefer = BiometricUtils.authenticate(this@WebOverlayActivityBase)
if (userId != Prefs.userId) {
if (userId != prefs.userId) {
FbCookie.switchUser(userId)
}
authDefer.await()
reloadBase(true)
if (Showcase.firstWebOverlay) {
if (showcasePrefs.firstWebOverlay) {
coordinator.frostSnackbar(R.string.web_overlay_swipe_hint) {
duration = BaseTransientBottomBar.LENGTH_INDEFINITE
setAction(R.string.kau_got_it) { dismiss() }
@ -240,7 +243,7 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
}
swipeBack = kauSwipeOnCreate {
if (!Prefs.overlayFullScreenSwipe) edgeSize = 20.dpToPx
if (!prefs.overlayFullScreenSwipe) edgeSize = 20.dpToPx
transitionSystemBars = false
}
}
@ -271,13 +274,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 = prefs.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(prefs.iconColor)
coordinator.setBackgroundColor(prefs.bgColor.withAlpha(255))
toolbar.overflowIcon?.setTint(prefs.iconColor)
}
override fun onResume() {
@ -312,7 +315,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(prefs.iconColor)
return true
}

View File

@ -68,4 +68,4 @@ suspend fun CookieDao.selectById(id: Long) = dao { _selectById(id) }
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() = selectById(Prefs.userId)
suspend fun CookieDao.currentCookie() = selectById(Prefs.get().userId)

View File

@ -93,8 +93,8 @@ class FrostDatabase(
return FrostDatabase(privateDb, publicDb)
}
fun module(context: Context) = module {
single { create(context) }
fun module() = module {
single { create(get()) }
single { get<FrostDatabase>().cookieDao() }
single { get<FrostDatabase>().cacheDao() }
single { get<FrostDatabase>().notifDao() }

View File

@ -24,17 +24,17 @@ import com.pitchedapps.frost.utils.Prefs
*/
enum class MainActivityLayout(
val titleRes: Int,
val backgroundColor: () -> Int,
val iconColor: () -> Int
val backgroundColor: (Prefs) -> Int,
val iconColor: (Prefs) -> Int
) {
TOP_BAR(R.string.top_bar,
{ Prefs.headerColor },
{ Prefs.iconColor }),
{ it.headerColor },
{ it.iconColor }),
BOTTOM_BAR(R.string.bottom_bar,
{ Prefs.bgColor },
{ Prefs.textColor });
{ it.bgColor },
{ it.textColor });
companion object {
val values = values() // save one instance

View File

@ -23,6 +23,8 @@ import com.pitchedapps.frost.injectors.CssAssets
import com.pitchedapps.frost.injectors.InjectorContract
import com.pitchedapps.frost.injectors.JsActions
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-06-14.
@ -82,11 +84,11 @@ enum class Theme(
CUSTOM(R.string.kau_custom,
CssAssets.CUSTOM,
{ Prefs.customTextColor },
{ Prefs.customAccentColor },
{ Prefs.customBackgroundColor },
{ Prefs.customHeaderColor },
{ Prefs.customIconColor });
{ prefs.customTextColor },
{ prefs.customAccentColor },
{ prefs.customBackgroundColor },
{ prefs.customHeaderColor },
{ prefs.customIconColor });
val textColor: Int
get() = textColorGetter()
@ -103,7 +105,8 @@ enum class Theme(
val iconColor: Int
get() = iconColorGetter()
companion object {
companion object:KoinComponent {
private val prefs: Prefs by inject()
val values = values() // save one instance
operator fun invoke(index: Int) = values[index]
}

View File

@ -35,13 +35,15 @@ import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-05-30.
*
* The following component manages all cookie transfers.
*/
object FbCookie {
object FbCookie :KoinComponent {
const val COOKIE_DOMAIN = FB_URL_BASE
@ -52,9 +54,8 @@ object FbCookie {
inline val webCookie: String?
get() = CookieManager.getInstance().getCookie(COOKIE_DOMAIN)
private val cookieDao: CookieDao by lazy {
FrostDatabase.get().cookieDao()
}
private val prefs: Prefs by inject()
private val cookieDao: CookieDao by inject()
private suspend fun CookieManager.suspendSetWebCookie(cookie: String?): Boolean {
cookie ?: return true
@ -86,14 +87,14 @@ object FbCookie {
suspend fun save(id: Long) {
L.d { "New cookie found" }
Prefs.userId = id
prefs.userId = id
CookieManager.getInstance().flush()
val cookie = CookieEntity(Prefs.userId, null, webCookie)
val cookie = CookieEntity(prefs.userId, null, webCookie)
cookieDao.save(cookie)
}
suspend fun reset() {
Prefs.userId = -1L
prefs.userId = -1L
with(CookieManager.getInstance()) {
removeAllCookies()
flush()
@ -112,7 +113,7 @@ object FbCookie {
}
withContext(NonCancellable) {
L.d { "Switching User" }
Prefs.userId = cookie.id
prefs.userId = cookie.id
CookieManager.getInstance().suspendSetWebCookie(cookie.cookie)
}
}
@ -124,8 +125,8 @@ object FbCookie {
suspend fun logout(context: Context) {
val cookies = arrayListOf<CookieEntity>()
if (context is Activity)
cookies.addAll(context.cookies().filter { it.id != Prefs.userId })
logout(Prefs.userId)
cookies.addAll(context.cookies().filter { it.id != prefs.userId })
logout(prefs.userId)
context.launchLogin(cookies, true)
}
@ -145,13 +146,13 @@ object FbCookie {
* When coming back to the main app, switch back to our original account before continuing
*/
suspend fun switchBackUser() {
if (Prefs.prevId == -1L) return
val prevId = Prefs.prevId
Prefs.prevId = -1L
if (prevId != Prefs.userId) {
if (prefs.prevId == -1L) return
val prevId = prefs.prevId
prefs.prevId = -1L
if (prevId != prefs.userId) {
switchUser(prevId)
L.d { "Switch back user" }
L._d { "${Prefs.userId} to $prevId" }
L._d { "${prefs.userId} to $prevId" }
}
}
}

View File

@ -39,7 +39,6 @@ import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.REQUEST_REFRESH
import com.pitchedapps.frost.utils.REQUEST_TEXT_ZOOM
import com.pitchedapps.frost.utils.frostEvent
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
@ -47,6 +46,9 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.koin.core.KoinComponent
import org.koin.core.inject
import kotlin.coroutines.CoroutineContext
/**
* Created by Allan Wang on 2017-11-07.
@ -55,7 +57,8 @@ import kotlinx.coroutines.launch
* Must be attached to activities implementing [MainActivityContract]
*/
@UseExperimental(ExperimentalCoroutinesApi::class)
abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract, DynamicUiContract {
abstract class BaseFragment : Fragment(), CoroutineScope, KoinComponent, FragmentContract,
DynamicUiContract {
companion object {
private const val ARG_POSITION = "arg_position"
@ -63,12 +66,13 @@ abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract, Dyna
internal operator fun invoke(
base: () -> BaseFragment,
prefs: Prefs,
useFallback: Boolean,
data: FbItem,
position: Int
): BaseFragment {
val fragment = if (useFallback) WebFragment() else base()
val d = if (data == FbItem.FEED) FeedSort(Prefs.feedSort).item else data
val d = if (data == FbItem.FEED) FeedSort(prefs.feedSort).item else data
fragment.withArguments(
ARG_URL to d.url,
ARG_POSITION to position
@ -78,6 +82,7 @@ abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract, Dyna
}
}
protected val prefs: Prefs by inject()
open lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = ContextHelper.dispatcher + job
@ -195,10 +200,10 @@ abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract, Dyna
protected fun FloatingActionButton.update(iicon: IIcon, click: () -> Unit) {
if (isShown) {
fadeScaleTransition {
setIcon(iicon, Prefs.iconColor)
setIcon(iicon, prefs.iconColor)
}
} else {
setIcon(iicon, Prefs.iconColor)
setIcon(iicon, prefs.iconColor)
show()
}
setOnClickListener { click() }

View File

@ -52,9 +52,9 @@ class WebFragment : BaseFragment() {
L.e { "Webview not found in fragment $baseEnum" }
return super.updateFab(contract)
}
if (baseEnum.isFeed && Prefs.showCreateFab) {
if (baseEnum.isFeed && prefs.showCreateFab) {
contract.showFab(GoogleMaterial.Icon.gmd_edit) {
JsActions.CREATE_POST.inject(web)
JsActions.CREATE_POST.inject(web, prefs)
}
return
}

View File

@ -29,6 +29,8 @@ import com.mikepenz.fastadapter.select.selectExtension
import com.pitchedapps.frost.R
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.launchWebOverlay
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 30/12/17.
@ -73,14 +75,16 @@ open class HeaderIItem(
itemId: Int = R.layout.iitem_header
) : KauIItem<HeaderIItem.ViewHolder>(R.layout.iitem_header, ::ViewHolder, itemId) {
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<HeaderIItem>(itemView) {
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<HeaderIItem>(itemView), KoinComponent {
private val prefs: Prefs by inject()
val text: TextView by bindView(R.id.item_header_text)
override fun bindView(item: HeaderIItem, payloads: MutableList<Any>) {
text.setTextColor(Prefs.accentColor)
text.setTextColor(prefs.accentColor)
text.text = item.text
text.setBackgroundColor(Prefs.nativeBgColor)
text.setBackgroundColor(prefs.nativeBgColor)
}
override fun unbindView(item: HeaderIItem) {
@ -100,14 +104,16 @@ open class TextIItem(
) : KauIItem<TextIItem.ViewHolder>(R.layout.iitem_text, ::ViewHolder, itemId),
ClickableIItemContract {
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TextIItem>(itemView) {
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TextIItem>(itemView),KoinComponent {
private val prefs: Prefs by inject()
val text: TextView by bindView(R.id.item_text_view)
override fun bindView(item: TextIItem, payloads: MutableList<Any>) {
text.setTextColor(Prefs.textColor)
text.setTextColor(prefs.textColor)
text.text = item.text
text.background = createSimpleRippleDrawable(Prefs.bgColor, Prefs.nativeBgColor)
text.background = createSimpleRippleDrawable(prefs.bgColor, prefs.nativeBgColor)
}
override fun unbindView(item: TextIItem) {

View File

@ -38,6 +38,8 @@ import com.pitchedapps.frost.glide.GlideApp
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.isIndependent
import com.pitchedapps.frost.utils.launchWebOverlay
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 27/12/17.
@ -93,7 +95,9 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) :
}
}
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<NotificationIItem>(itemView) {
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<NotificationIItem>(itemView), KoinComponent {
private val prefs: Prefs by inject()
private val frame: ViewGroup by bindView(R.id.item_frame)
private val avatar: ImageView by bindView(R.id.item_avatar)
@ -107,11 +111,11 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) :
override fun bindView(item: NotificationIItem, payloads: MutableList<Any>) {
val notif = item.notification
frame.background = createSimpleRippleDrawable(
Prefs.textColor,
Prefs.nativeBgColor(notif.unread)
prefs.textColor,
prefs.nativeBgColor(notif.unread)
)
content.setTextColor(Prefs.textColor)
date.setTextColor(Prefs.textColor.withAlpha(150))
content.setTextColor(prefs.textColor)
date.setTextColor(prefs.textColor.withAlpha(150))
val glide = glide
glide.load(notif.img)

View File

@ -30,6 +30,8 @@ import com.mikepenz.fastadapter.drag.IDraggable
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 26/11/17.
@ -41,14 +43,16 @@ class TabIItem(val item: FbItem) : KauIItem<TabIItem.ViewHolder>(
override val isDraggable: Boolean = true
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TabIItem>(itemView) {
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TabIItem>(itemView), KoinComponent {
private val prefs: Prefs by inject()
val image: ImageView by bindView(R.id.image)
val text: TextView by bindView(R.id.text)
override fun bindView(item: TabIItem, payloads: MutableList<Any>) {
val isInToolbar = adapterPosition < 4
val color = if (isInToolbar) Prefs.iconColor else Prefs.textColor
val color = if (isInToolbar) prefs.iconColor else prefs.textColor
image.setIcon(item.item.icon, 20, color)
if (isInToolbar)
text.invisible()

View File

@ -20,7 +20,6 @@ import android.content.Context
import android.graphics.Color
import android.webkit.WebView
import androidx.annotation.VisibleForTesting
import ca.allanwang.kau.kotlin.lazyContext
import ca.allanwang.kau.utils.adjustAlpha
import ca.allanwang.kau.utils.colorToBackground
import ca.allanwang.kau.utils.colorToForeground
@ -29,11 +28,11 @@ import ca.allanwang.kau.utils.use
import ca.allanwang.kau.utils.withAlpha
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
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.
@ -50,29 +49,38 @@ enum class CssAssets(val folder: String = THEME_FOLDER) : InjectorContract {
/**
* Note that while this can be loaded from any thread, it is typically done through [load]
*/
private val injector = lazyContext {
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 =
it.assets.open("css/$folder/$file").bufferedReader().use(BufferedReader::readText)
context.assets.open("css/$folder/$file").bufferedReader()
.use(BufferedReader::readText)
if (this == CUSTOM) {
val bt = if (Color.alpha(Prefs.bgColor) == 255)
Prefs.bgColor.toRgbaString()
val bt = if (Color.alpha(prefs.bgColor) == 255)
prefs.bgColor.toRgbaString()
else
"transparent"
val bb = Prefs.bgColor.colorToForeground(0.35f)
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("\$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("\$O\$", prefs.bgColor.withAlpha(255).toRgbaString())
.replace("\$OO\$", bb.withAlpha(255).toRgbaString())
.replace("\$D\$", Prefs.textColor.adjustAlpha(0.3f).toRgbaString())
.replace("\$D\$", prefs.textColor.adjustAlpha(0.3f).toRgbaString())
.replace("\$TI\$", bb.withAlpha(60).toRgbaString())
.replace("\$C\$", bt)
}
@ -81,24 +89,24 @@ enum class CssAssets(val folder: String = THEME_FOLDER) : InjectorContract {
L.e(e) { "CssAssets file not found" }
JsInjector(JsActions.EMPTY.function)
}
}
override fun inject(webView: WebView) =
injector(webView.context).inject(webView)
override fun inject(webView: WebView, prefs: Prefs) =
injector(webView.context, prefs).inject(webView, prefs)
fun reset() {
injector.invalidate()
injector = null
}
companion object {
// Ensures that all non themes and the selected theme are loaded
suspend fun load(context: Context) {
suspend fun load(context: Context, prefs: Prefs) {
withContext(Dispatchers.IO) {
val currentTheme = Prefs.t.injector as? CssAssets
val currentTheme = prefs.t.injector as? CssAssets
val (themes, others) = CssAssets.values().partition { it.folder == THEME_FOLDER }
themes.filter { it != currentTheme }.forEach { it.reset() }
currentTheme?.injector?.invoke(context)
others.forEach { it.injector.invoke(context) }
currentTheme?.injector(context, prefs)
others.forEach { it.injector(context, prefs) }
}
}
}

View File

@ -17,6 +17,7 @@
package com.pitchedapps.frost.injectors
import android.webkit.WebView
import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-05-31.
@ -53,6 +54,6 @@ enum class CssHider(vararg val items: String) : InjectorContract {
.single(name).build()
}
override fun inject(webView: WebView) =
injector.inject(webView)
override fun inject(webView: WebView, prefs: Prefs) =
injector.inject(webView, prefs)
}

View File

@ -18,6 +18,7 @@ package com.pitchedapps.frost.injectors
import android.webkit.WebView
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-05-31.
@ -42,8 +43,8 @@ enum class JsActions(body: String) : InjectorContract {
val function = "(function(){$body})();"
override fun inject(webView: WebView) =
JsInjector(function).inject(webView)
override fun inject(webView: WebView, prefs: Prefs) =
JsInjector(function).inject(webView, prefs)
}
@Suppress("NOTHING_TO_INLINE")

View File

@ -21,6 +21,7 @@ import android.webkit.WebView
import androidx.annotation.VisibleForTesting
import ca.allanwang.kau.kotlin.lazyContext
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import java.io.BufferedReader
import java.io.FileNotFoundException
import java.util.Locale
@ -49,14 +50,14 @@ enum class JsAssets : InjectorContract {
}
}
override fun inject(webView: WebView) =
injector(webView.context).inject(webView)
override fun inject(webView: WebView, prefs: Prefs) =
injector(webView.context).inject(webView, prefs)
companion object {
// Ensures that all non themes and the selected theme are loaded
suspend fun load(context: Context) {
withContext(Dispatchers.IO) {
JsAssets.values().forEach { it.injector.invoke(context) }
values().forEach { it.injector.invoke(context) }
}
}
}

View File

@ -19,6 +19,7 @@ package com.pitchedapps.frost.injectors
import android.webkit.WebView
import androidx.annotation.VisibleForTesting
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.web.FrostWebViewClient
import kotlin.random.Random
import org.apache.commons.text.StringEscapeUtils
@ -83,7 +84,7 @@ class JsBuilder {
* Contract for all injectors to allow it to interact properly with a webview
*/
interface InjectorContract {
fun inject(webView: WebView)
fun inject(webView: WebView, prefs: Prefs)
/**
* Toggle the injector (usually through Prefs
* If false, will fallback to an empty action
@ -94,19 +95,19 @@ interface InjectorContract {
/**
* Helper method to inject multiple functions simultaneously with a single callback
*/
fun WebView.jsInject(vararg injectors: InjectorContract) {
fun WebView.jsInject(vararg injectors: InjectorContract, prefs: Prefs) {
injectors.filter { it != JsActions.EMPTY }.forEach {
it.inject(this)
it.inject(this,prefs)
}
}
fun FrostWebViewClient.jsInject(vararg injectors: InjectorContract) = web.jsInject(*injectors)
fun FrostWebViewClient.jsInject(vararg injectors: InjectorContract, prefs: Prefs) = web.jsInject(*injectors, prefs = prefs)
/**
* Wrapper class to convert a function into an injector
*/
class JsInjector(val function: String) : InjectorContract {
override fun inject(webView: WebView) =
override fun inject(webView: WebView, prefs: Prefs) =
webView.evaluateJavascript(function, null)
}

View File

@ -56,7 +56,7 @@ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) {
introThemeDark.setThemeClick(Theme.DARK)
introThemeAmoled.setThemeClick(Theme.AMOLED)
introThemeGlass.setThemeClick(Theme.GLASS)
val currentTheme = Prefs.theme - 1
val currentTheme = prefs.theme - 1
if (currentTheme in 0..3)
themeList.forEachIndexed { index, v ->
v.scaleXY = if (index == currentTheme) 1.6f else 0.8f
@ -65,9 +65,9 @@ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) {
private fun View.setThemeClick(theme: Theme) {
setOnClickListener { v ->
Prefs.theme = theme.ordinal
prefs.theme = theme.ordinal
(activity as IntroActivity).apply {
binding.ripple.ripple(Prefs.bgColor, v.x + v.pivotX, v.y + v.pivotY)
binding.ripple.ripple(prefs.bgColor, v.x + v.pivotX, v.y + v.pivotY)
theme()
}
themeList.forEach { it.animate().scaleXY(if (it == this) 1.6f else 0.8f).start() }

View File

@ -58,10 +58,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(prefs.textColor)
desc.setTextColor(prefs.textColor)
phone.tint(prefs.textColor)
screen.tint(prefs.bgColor)
}
fun themeImageComponent(color: Int, vararg id: Int) {
@ -97,9 +97,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(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)
}
override fun onPageScrolledImpl(positionOffset: Float) {
@ -123,14 +123,14 @@ class IntroTabTouchFragment : BaseImageIntroFragment(
override fun themeFragmentImpl() {
super.themeFragmentImpl()
themeImageComponent(
Prefs.iconColor,
prefs.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(prefs.headerColor, R.id.intro_phone_tab)
themeImageComponent(prefs.textColor.withAlpha(80), R.id.intro_phone_icon_ripple)
}
}
@ -142,21 +142,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(prefs.headerColor, R.id.intro_phone_toolbar)
themeImageComponent(prefs.bgColor.colorToForeground(0.1f), R.id.intro_phone_image)
themeImageComponent(
Prefs.bgColor.colorToForeground(0.2f),
prefs.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(prefs.bgColor.colorToForeground(0.3f), R.id.intro_phone_comment)
themeImageComponent(
Prefs.bgColor.colorToForeground(0.1f),
prefs.bgColor.colorToForeground(0.1f),
R.id.intro_phone_card_1,
R.id.intro_phone_card_2
)
themeImageComponent(
Prefs.textColor,
prefs.textColor,
R.id.intro_phone_image_indicator,
R.id.intro_phone_comment_indicator,
R.id.intro_phone_card_indicator

View File

@ -37,6 +37,8 @@ import com.pitchedapps.frost.R
import com.pitchedapps.frost.activities.IntroActivity
import com.pitchedapps.frost.databinding.IntroAnalyticsBinding
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
import kotlin.math.abs
/**
@ -48,7 +50,9 @@ import kotlin.math.abs
/**
* The core intro fragment for all other fragments
*/
abstract class BaseIntroFragment(val layoutRes: Int) : Fragment() {
abstract class BaseIntroFragment(val layoutRes: Int) : Fragment(), KoinComponent {
protected val prefs: Prefs by inject()
val screenWidth
get() = resources.displayMetrics.widthPixels
@ -105,7 +109,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(prefs.textColor) }
}
protected val viewArray: Array<Array<out View>> by lazyResettableRegistered { viewArray() }
@ -134,7 +138,7 @@ class IntroFragmentWelcome : BaseIntroFragment(R.layout.intro_welcome) {
override fun themeFragmentImpl() {
super.themeFragmentImpl()
image.imageTintList = ColorStateList.valueOf(Prefs.textColor)
image.imageTintList = ColorStateList.valueOf(prefs.textColor)
}
}
@ -153,7 +157,7 @@ class IntroFragmentAnalytics : BaseIntroFragment(R.layout.intro_analytics) {
override fun themeFragmentImpl() {
super.themeFragmentImpl()
image.imageTintList = ColorStateList.valueOf(Prefs.textColor)
image.imageTintList = ColorStateList.valueOf(prefs.textColor)
}
@SuppressLint("ClickableViewAccessibility")
@ -165,9 +169,9 @@ class IntroFragmentAnalytics : BaseIntroFragment(R.layout.intro_analytics) {
private fun IntroAnalyticsBinding.init() {
image.setIcon(GoogleMaterial.Icon.gmd_bug_report, 120)
introSwitch.isSelected = Prefs.analytics
introSwitch.isSelected = prefs.analytics
introSwitch.setOnCheckedChangeListener { _, isChecked ->
Prefs.analytics = isChecked
prefs.analytics = isChecked
}
}
}
@ -180,7 +184,7 @@ class IntroFragmentEnd : BaseIntroFragment(R.layout.intro_end) {
override fun themeFragmentImpl() {
super.themeFragmentImpl()
image.imageTintList = ColorStateList.valueOf(Prefs.textColor)
image.imageTintList = ColorStateList.valueOf(prefs.textColor)
}
@SuppressLint("ClickableViewAccessibility")

View File

@ -20,9 +20,9 @@ import android.app.job.JobParameters
import android.app.job.JobService
import androidx.annotation.CallSuper
import ca.allanwang.kau.utils.ContextHelper
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
abstract class BaseJobService : JobService(), CoroutineScope {

View File

@ -67,7 +67,7 @@ enum class NotificationType(
private val overlayContext: OverlayContext,
private val fbItem: FbItem,
private val parser: FrostParser<ParseNotification>,
private val ringtone: () -> String
private val ringtoneProvider: (Prefs) -> String
) {
GENERAL(
@ -75,7 +75,7 @@ enum class NotificationType(
OverlayContext.NOTIFICATION,
FbItem.NOTIFICATIONS,
NotifParser,
Prefs::notificationRingtone
{ it.notificationRingtone }
),
MESSAGE(
@ -83,7 +83,7 @@ enum class NotificationType(
OverlayContext.MESSAGE,
FbItem.MESSAGES,
MessageParser,
Prefs::messageRingtone
{ it.messageRingtone }
);
private val groupPrefix = "frost_${name.toLowerCase(Locale.CANADA)}"
@ -112,7 +112,7 @@ enum class NotificationType(
* Returns the number of notifications generated,
* or -1 if an error occurred
*/
suspend fun fetch(context: Context, data: CookieEntity): Int {
suspend fun fetch(context: Context, data: CookieEntity, prefs: Prefs): Int {
val notifDao = FrostDatabase.get().notifDao()
val response = try {
parser.parse(data.cookie)
@ -129,7 +129,7 @@ enum class NotificationType(
*/
fun validText(text: String?): Boolean {
val t = text ?: return true
return Prefs.notificationKeywords.none {
return prefs.notificationKeywords.none {
t.contains(it, true)
}
}
@ -167,7 +167,7 @@ enum class NotificationType(
frostEvent("Notifications", "Type" to name, "Count" to notifs.size)
if (notifs.size > 1)
summaryNotification(context, userId, notifs.size).notify(context)
val ringtone = ringtone()
val ringtone = ringtoneProvider(prefs)
notifs.forEachIndexed { i, notif ->
// Ring at most twice
notif.withAlert(context, i < 2, ringtone).notify(context)
@ -316,9 +316,9 @@ data class FrostNotification(
NotificationManagerCompat.from(context).notify(tag, id, notif.build())
}
fun Context.scheduleNotificationsFromPrefs(): Boolean {
val shouldSchedule = Prefs.hasNotifications
return if (shouldSchedule) scheduleNotifications(Prefs.notificationFreq)
fun Context.scheduleNotificationsFromPrefs(prefs: Prefs): Boolean {
val shouldSchedule = prefs.hasNotifications
return if (shouldSchedule) scheduleNotifications(prefs.notificationFreq)
else scheduleNotifications(-1)
}

View File

@ -34,6 +34,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.koin.android.ext.android.inject
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-06-14.
@ -45,7 +46,8 @@ import org.koin.android.ext.android.inject
*/
class NotificationService : BaseJobService() {
val cookieDao: CookieDao by inject()
private val prefs: Prefs by inject()
private val cookieDao: CookieDao by inject()
override fun onStopJob(params: JobParameters?): Boolean {
super.onStopJob(params)
@ -64,7 +66,7 @@ class NotificationService : BaseJobService() {
frostEvent(
"NotificationTime",
"Type" to (if (abrupt) "Service force stop" else "Service"),
"IM Included" to Prefs.notificationsInstantMessages,
"IM Included" to prefs.notificationsInstantMessages,
"Duration" to time
)
}
@ -86,7 +88,7 @@ class NotificationService : BaseJobService() {
private suspend fun sendNotifications(params: JobParameters?): Unit =
withContext(Dispatchers.Default) {
val currentId = Prefs.userId
val currentId = prefs.userId
val cookies = cookieDao.selectAll()
yield()
val jobId = params?.extras?.getInt(NOTIFICATION_PARAM_ID, -1) ?: -1
@ -94,12 +96,12 @@ class NotificationService : BaseJobService() {
for (cookie in cookies) {
yield()
val current = cookie.id == currentId
if (Prefs.notificationsGeneral &&
(current || Prefs.notificationAllAccounts)
if (prefs.notificationsGeneral &&
(current || prefs.notificationAllAccounts)
)
notifCount += fetch(jobId, NotificationType.GENERAL, cookie)
if (Prefs.notificationsInstantMessages &&
(current || Prefs.notificationsImAllAccounts)
if (prefs.notificationsInstantMessages &&
(current || prefs.notificationsImAllAccounts)
)
notifCount += fetch(jobId, NotificationType.MESSAGE, cookie)
}
@ -117,7 +119,7 @@ class NotificationService : BaseJobService() {
* Also normalized the output to return the number of notifications received
*/
private suspend fun fetch(jobId: Int, type: NotificationType, cookie: CookieEntity): Int {
val count = type.fetch(this, cookie)
val count = type.fetch(this, cookie, prefs)
if (count < 0) {
if (jobId == NOTIFICATION_JOB_NOW)
generalNotification(666, R.string.error_notification, BuildConfig.DEBUG)
@ -133,7 +135,7 @@ class NotificationService : BaseJobService() {
private fun generalNotification(id: Int, textRes: Int, withDefaults: Boolean) {
val notifBuilder = frostNotification(NOTIF_CHANNEL_GENERAL)
.setFrostAlert(this, withDefaults, Prefs.notificationRingtone)
.setFrostAlert(this, withDefaults, prefs.notificationRingtone)
.setContentTitle(string(R.string.frost_name))
.setContentText(string(textRes))
NotificationManagerCompat.from(this).notify(id, notifBuilder.build())

View File

@ -41,13 +41,13 @@ import com.pitchedapps.frost.utils.frostUri
const val NOTIF_CHANNEL_GENERAL = "general"
const val NOTIF_CHANNEL_MESSAGES = "messages"
fun setupNotificationChannels(c: Context) {
fun setupNotificationChannels(c: Context, prefs: Prefs) {
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)
manager.createNotificationChannel(NOTIF_CHANNEL_MESSAGES, "$appName: $msg")
manager.createNotificationChannel(NOTIF_CHANNEL_GENERAL, appName, prefs)
manager.createNotificationChannel(NOTIF_CHANNEL_MESSAGES, "$appName: $msg", prefs)
manager.notificationChannels
.filter {
it.id != NOTIF_CHANNEL_GENERAL &&
@ -60,14 +60,15 @@ fun setupNotificationChannels(c: Context) {
@RequiresApi(Build.VERSION_CODES.O)
private fun NotificationManager.createNotificationChannel(
id: String,
name: String
name: String,
prefs: Prefs
): NotificationChannel {
val channel = NotificationChannel(
id,
name, NotificationManager.IMPORTANCE_DEFAULT
)
channel.enableLights(true)
channel.lightColor = Prefs.accentColor
channel.lightColor = prefs.accentColor
channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
createNotificationChannel(channel)
return channel
@ -93,6 +94,8 @@ fun NotificationCompat.Builder.setFrostAlert(
enable: Boolean,
ringtone: String
): NotificationCompat.Builder {
val prefs = Prefs.get()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setGroupAlertBehavior(
if (enable) NotificationCompat.GROUP_ALERT_CHILDREN
@ -102,12 +105,12 @@ fun NotificationCompat.Builder.setFrostAlert(
setDefaults(0)
} else {
var defaults = 0
if (Prefs.notificationVibrate) defaults = defaults or Notification.DEFAULT_VIBRATE
if (Prefs.notificationSound) {
if (prefs.notificationVibrate) defaults = defaults or Notification.DEFAULT_VIBRATE
if (prefs.notificationSound) {
if (ringtone.isNotBlank()) setSound(context.frostUri(ringtone))
else defaults = defaults or Notification.DEFAULT_SOUND
}
if (Prefs.notificationLights) defaults = defaults or Notification.DEFAULT_LIGHTS
if (prefs.notificationLights) defaults = defaults or Notification.DEFAULT_LIGHTS
setDefaults(defaults)
}
return this

View File

@ -21,17 +21,21 @@ import android.content.Context
import android.content.Intent
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-05-31.
*
* Receiver that is triggered whenever the app updates so it can bind the notifications again
*/
class UpdateReceiver : BroadcastReceiver() {
class UpdateReceiver : BroadcastReceiver(), KoinComponent {
private val prefs: Prefs by inject()
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_MY_PACKAGE_REPLACED) return
L.d { "Frost has updated" }
context.scheduleNotifications(Prefs.notificationFreq) // Update notifications
context.scheduleNotifications(prefs.notificationFreq) // Update notifications
}
}

View File

@ -45,7 +45,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
header(R.string.theme_customization)
text(R.string.theme, Prefs::theme, { Prefs.theme = it }) {
text(R.string.theme, prefs::theme, { prefs.theme = it }) {
onClick = {
materialDialog {
title(R.string.theme)
@ -71,7 +71,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
}
fun KPrefColorPicker.KPrefColorContract.dependsOnCustom() {
enabler = Prefs::isCustomTheme
enabler = prefs::isCustomTheme
onDisabledClick = { frostSnackbar(R.string.requires_custom_theme) }
allowCustom = true
}
@ -80,8 +80,8 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
CssAssets.CUSTOM.reset()
}
colorPicker(R.string.text_color, Prefs::customTextColor, {
Prefs.customTextColor = it
colorPicker(R.string.text_color, prefs::customTextColor, {
prefs.customTextColor = it
reload()
invalidateCustomTheme()
shouldRestartMain()
@ -90,8 +90,8 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
allowCustomAlpha = false
}
colorPicker(R.string.accent_color, Prefs::customAccentColor, {
Prefs.customAccentColor = it
colorPicker(R.string.accent_color, prefs::customAccentColor, {
prefs.customAccentColor = it
reload()
invalidateCustomTheme()
shouldRestartMain()
@ -100,8 +100,8 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
allowCustomAlpha = false
}
colorPicker(R.string.background_color, Prefs::customBackgroundColor, {
Prefs.customBackgroundColor = it
colorPicker(R.string.background_color, prefs::customBackgroundColor, {
prefs.customBackgroundColor = it
bgCanvas.ripple(it, duration = 500L)
invalidateCustomTheme()
setFrostTheme(true)
@ -111,8 +111,8 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
allowCustomAlpha = true
}
colorPicker(R.string.header_color, Prefs::customHeaderColor, {
Prefs.customHeaderColor = it
colorPicker(R.string.header_color, prefs::customHeaderColor, {
prefs.customHeaderColor = it
frostNavigationBar()
toolbarCanvas.ripple(it, RippleCanvas.MIDDLE, RippleCanvas.END, duration = 500L)
reload()
@ -122,8 +122,8 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
allowCustomAlpha = true
}
colorPicker(R.string.icon_color, Prefs::customIconColor, {
Prefs.customIconColor = it
colorPicker(R.string.icon_color, prefs::customIconColor, {
prefs.customIconColor = it
invalidateOptionsMenu()
shouldRestartMain()
}) {
@ -135,9 +135,9 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
text(
R.string.main_activity_layout,
Prefs::mainActivityLayoutType,
{ Prefs.mainActivityLayoutType = it }) {
textGetter = { string(Prefs.mainActivityLayout.titleRes) }
prefs::mainActivityLayoutType,
{ prefs.mainActivityLayoutType = it }) {
textGetter = { string(prefs.mainActivityLayout.titleRes) }
onClick = {
materialDialog {
title(R.string.main_activity_layout_desc)
@ -160,8 +160,8 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
onClick = { launchTabCustomizerActivity() }
}
checkbox(R.string.tint_nav, Prefs::tintNavBar, {
Prefs.tintNavBar = it
checkbox(R.string.tint_nav, prefs::tintNavBar, {
prefs.tintNavBar = it
frostNavigationBar()
setFrostResult(REQUEST_NAV)
}) {
@ -172,15 +172,15 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
KPrefTextSeekbar(
KPrefSeekbar.KPrefSeekbarBuilder(
globalOptions,
R.string.web_text_scaling, Prefs::webTextScaling
R.string.web_text_scaling, prefs::webTextScaling
) {
Prefs.webTextScaling = it
prefs.webTextScaling = it
setFrostResult(REQUEST_TEXT_ZOOM)
})
)
checkbox(R.string.enforce_black_media_bg, Prefs::blackMediaBg, {
Prefs.blackMediaBg = it
checkbox(R.string.enforce_black_media_bg, prefs::blackMediaBg, {
prefs.blackMediaBg = it
}) {
descRes = R.string.enforce_black_media_bg_desc
}

View File

@ -26,47 +26,47 @@ import com.pitchedapps.frost.utils.Prefs
*/
fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = {
checkbox(R.string.auto_refresh_feed, Prefs::autoRefreshFeed, { Prefs.autoRefreshFeed = it }) {
checkbox(R.string.auto_refresh_feed, prefs::autoRefreshFeed, { prefs.autoRefreshFeed = it }) {
descRes = R.string.auto_refresh_feed_desc
}
checkbox(R.string.fancy_animations, Prefs::animate, { Prefs.animate = it; animate = it }) {
checkbox(R.string.fancy_animations, prefs::animate, { prefs.animate = it; animate = it }) {
descRes = R.string.fancy_animations_desc
}
checkbox(
R.string.overlay_swipe,
Prefs::overlayEnabled,
{ Prefs.overlayEnabled = it; shouldRefreshMain() }) {
prefs::overlayEnabled,
{ prefs.overlayEnabled = it; shouldRefreshMain() }) {
descRes = R.string.overlay_swipe_desc
}
checkbox(
R.string.overlay_full_screen_swipe,
Prefs::overlayFullScreenSwipe,
{ Prefs.overlayFullScreenSwipe = it }) {
prefs::overlayFullScreenSwipe,
{ prefs.overlayFullScreenSwipe = it }) {
descRes = R.string.overlay_full_screen_swipe_desc
}
checkbox(
R.string.open_links_in_default,
Prefs::linksInDefaultApp,
{ Prefs.linksInDefaultApp = it }) {
prefs::linksInDefaultApp,
{ prefs.linksInDefaultApp = it }) {
descRes = R.string.open_links_in_default_desc
}
checkbox(R.string.viewpager_swipe, Prefs::viewpagerSwipe, { Prefs.viewpagerSwipe = it }) {
checkbox(R.string.viewpager_swipe, prefs::viewpagerSwipe, { prefs.viewpagerSwipe = it }) {
descRes = R.string.viewpager_swipe_desc
}
checkbox(
R.string.force_message_bottom,
Prefs::messageScrollToBottom,
{ Prefs.messageScrollToBottom = it }) {
prefs::messageScrollToBottom,
{ prefs.messageScrollToBottom = it }) {
descRes = R.string.force_message_bottom_desc
}
checkbox(R.string.enable_pip, Prefs::enablePip, { Prefs.enablePip = it }) {
checkbox(R.string.enable_pip, prefs::enablePip, { prefs.enablePip = it }) {
descRes = R.string.enable_pip_desc
}
@ -78,11 +78,11 @@ fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = {
// }
// }
checkbox(R.string.exit_confirmation, Prefs::exitConfirmation, { Prefs.exitConfirmation = it }) {
checkbox(R.string.exit_confirmation, prefs::exitConfirmation, { prefs.exitConfirmation = it }) {
descRes = R.string.exit_confirmation_desc
}
checkbox(R.string.analytics, Prefs::analytics, { Prefs.analytics = it }) {
checkbox(R.string.analytics, prefs::analytics, { prefs.analytics = it }) {
descRes = R.string.analytics_desc
}
}

View File

@ -37,8 +37,8 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = {
// Experimental content ends here --------------------
checkbox(R.string.verbose_logging, Prefs::verboseLogging, {
Prefs.verboseLogging = it
checkbox(R.string.verbose_logging, prefs::verboseLogging, {
prefs.verboseLogging = it
KL.shouldLog = { it != Log.VERBOSE }
}) {
descRes = R.string.verbose_logging_desc

View File

@ -31,7 +31,7 @@ import com.pitchedapps.frost.utils.REQUEST_FAB
*/
fun SettingsActivity.getFeedPrefs(): KPrefAdapterBuilder.() -> Unit = {
text(R.string.newsfeed_sort, Prefs::feedSort, { Prefs.feedSort = it }) {
text(R.string.newsfeed_sort, prefs::feedSort, { prefs.feedSort = it }) {
descRes = R.string.newsfeed_sort_desc
onClick = {
materialDialog {
@ -50,50 +50,50 @@ fun SettingsActivity.getFeedPrefs(): KPrefAdapterBuilder.() -> Unit = {
textGetter = { string(FeedSort(it).textRes) }
}
checkbox(R.string.aggressive_recents, Prefs::aggressiveRecents, {
Prefs.aggressiveRecents = it
checkbox(R.string.aggressive_recents, prefs::aggressiveRecents, {
prefs.aggressiveRecents = it
shouldRefreshMain()
}) {
descRes = R.string.aggressive_recents_desc
}
checkbox(R.string.composer, Prefs::showComposer, {
Prefs.showComposer = it
checkbox(R.string.composer, prefs::showComposer, {
prefs.showComposer = it
shouldRefreshMain()
}) {
descRes = R.string.composer_desc
}
checkbox(R.string.create_fab, Prefs::showCreateFab, {
Prefs.showCreateFab = it
checkbox(R.string.create_fab, prefs::showCreateFab, {
prefs.showCreateFab = it
setFrostResult(REQUEST_FAB)
}) {
descRes = R.string.create_fab_desc
}
checkbox(R.string.suggested_friends, Prefs::showSuggestedFriends, {
Prefs.showSuggestedFriends = it
checkbox(R.string.suggested_friends, prefs::showSuggestedFriends, {
prefs.showSuggestedFriends = it
shouldRefreshMain()
}) {
descRes = R.string.suggested_friends_desc
}
checkbox(R.string.suggested_groups, Prefs::showSuggestedGroups, {
Prefs.showSuggestedGroups = it
checkbox(R.string.suggested_groups, prefs::showSuggestedGroups, {
prefs.showSuggestedGroups = it
shouldRefreshMain()
}) {
descRes = R.string.suggested_groups_desc
}
checkbox(R.string.show_stories, Prefs::showStories, {
Prefs.showStories = it
checkbox(R.string.show_stories, prefs::showStories, {
prefs.showStories = it
shouldRefreshMain()
}) {
descRes = R.string.show_stories_desc
}
checkbox(R.string.facebook_ads, Prefs::showFacebookAds, {
Prefs.showFacebookAds = it
checkbox(R.string.facebook_ads, prefs::showFacebookAds, {
prefs.showFacebookAds = it
shouldRefreshMain()
}) {
descRes = R.string.facebook_ads_desc

View File

@ -19,7 +19,6 @@ package com.pitchedapps.frost.settings
import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
import com.pitchedapps.frost.R
import com.pitchedapps.frost.activities.SettingsActivity
import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-08-08.
@ -28,8 +27,8 @@ fun SettingsActivity.getNetworkPrefs(): KPrefAdapterBuilder.() -> Unit = {
checkbox(
R.string.network_media_on_metered,
{ !Prefs.loadMediaOnMeteredNetwork },
{ Prefs.loadMediaOnMeteredNetwork = !it }) {
{ !prefs.loadMediaOnMeteredNetwork },
{ prefs.loadMediaOnMeteredNetwork = !it }) {
descRes = R.string.network_media_on_metered_desc
}
}

View File

@ -41,6 +41,7 @@ import com.pitchedapps.frost.utils.frostSnackbar
import com.pitchedapps.frost.utils.frostUri
import com.pitchedapps.frost.views.Keywords
import kotlinx.coroutines.launch
import org.koin.android.ext.android.get
/**
* Created by Allan Wang on 2017-06-29.
@ -54,8 +55,8 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
text(
R.string.notification_frequency,
Prefs::notificationFreq,
{ Prefs.notificationFreq = it }) {
prefs::notificationFreq,
{ prefs.notificationFreq = it }) {
val options = longArrayOf(15, 30, 60, 120, 180, 300, 1440, 2880)
val texts =
options.map { if (it <= 0) string(R.string.no_notifications) else minuteToText(it) }
@ -71,7 +72,7 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
}
}
}
enabler = { Prefs.hasNotifications }
enabler = { prefs.hasNotifications }
textGetter = { minuteToText(it) }
}
@ -88,36 +89,36 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
}
}
checkbox(R.string.notification_general, Prefs::notificationsGeneral,
checkbox(R.string.notification_general, prefs::notificationsGeneral,
{
Prefs.notificationsGeneral = it
prefs.notificationsGeneral = it
reloadByTitle(R.string.notification_general_all_accounts)
if (!Prefs.notificationsInstantMessages)
if (!prefs.notificationsInstantMessages)
reloadByTitle(R.string.notification_frequency)
}) {
descRes = R.string.notification_general_desc
}
checkbox(R.string.notification_general_all_accounts, Prefs::notificationAllAccounts,
{ Prefs.notificationAllAccounts = it }) {
checkbox(R.string.notification_general_all_accounts, prefs::notificationAllAccounts,
{ prefs.notificationAllAccounts = it }) {
descRes = R.string.notification_general_all_accounts_desc
enabler = { Prefs.notificationsGeneral }
enabler = { prefs.notificationsGeneral }
}
checkbox(R.string.notification_messages, Prefs::notificationsInstantMessages,
checkbox(R.string.notification_messages, prefs::notificationsInstantMessages,
{
Prefs.notificationsInstantMessages = it
prefs.notificationsInstantMessages = it
reloadByTitle(R.string.notification_messages_all_accounts)
if (!Prefs.notificationsGeneral)
if (!prefs.notificationsGeneral)
reloadByTitle(R.string.notification_frequency)
}) {
descRes = R.string.notification_messages_desc
}
checkbox(R.string.notification_messages_all_accounts, Prefs::notificationsImAllAccounts,
{ Prefs.notificationsImAllAccounts = it }) {
checkbox(R.string.notification_messages_all_accounts, prefs::notificationsImAllAccounts,
{ prefs.notificationsImAllAccounts = it }) {
descRes = R.string.notification_messages_all_accounts_desc
enabler = { Prefs.notificationsInstantMessages }
enabler = { prefs.notificationsInstantMessages }
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -130,8 +131,8 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
}
}
} else {
checkbox(R.string.notification_sound, Prefs::notificationSound, {
Prefs.notificationSound = it
checkbox(R.string.notification_sound, prefs::notificationSound, {
prefs.notificationSound = it
reloadByTitle(
R.string.notification_ringtone,
R.string.message_ringtone
@ -139,7 +140,7 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
})
fun KPrefText.KPrefTextContract<String>.ringtone(code: Int) {
enabler = Prefs::notificationSound
enabler = prefs::notificationSound
textGetter = {
if (it.isBlank()) string(R.string.kau_default)
else RingtoneManager.getRingtone(this@getNotificationPrefs, frostUri(it))
@ -163,21 +164,21 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
}
}
text(R.string.notification_ringtone, Prefs::notificationRingtone,
{ Prefs.notificationRingtone = it }) {
text(R.string.notification_ringtone, prefs::notificationRingtone,
{ prefs.notificationRingtone = it }) {
ringtone(SettingsActivity.REQUEST_NOTIFICATION_RINGTONE)
}
text(R.string.message_ringtone, Prefs::messageRingtone,
{ Prefs.messageRingtone = it }) {
text(R.string.message_ringtone, prefs::messageRingtone,
{ prefs.messageRingtone = it }) {
ringtone(SettingsActivity.REQUEST_MESSAGE_RINGTONE)
}
checkbox(R.string.notification_vibrate, Prefs::notificationVibrate,
{ Prefs.notificationVibrate = it })
checkbox(R.string.notification_vibrate, prefs::notificationVibrate,
{ prefs.notificationVibrate = it })
checkbox(R.string.notification_lights, Prefs::notificationLights,
{ Prefs.notificationLights = it })
checkbox(R.string.notification_lights, prefs::notificationLights,
{ prefs.notificationLights = it })
}
if (BuildConfig.DEBUG) {

View File

@ -32,7 +32,7 @@ fun SettingsActivity.getSecurityPrefs(): KPrefAdapterBuilder.() -> Unit = {
descRes = R.string.security_disclaimer_info
}
checkbox(R.string.enable_biometrics, Prefs::biometricsEnabled, {
checkbox(R.string.enable_biometrics, prefs::biometricsEnabled, {
launch {
/*
* For security, we should request authentication when:
@ -40,7 +40,7 @@ fun SettingsActivity.getSecurityPrefs(): KPrefAdapterBuilder.() -> Unit = {
* - disabling to ensure that it is permitted
*/
BiometricUtils.authenticate(this@getSecurityPrefs, force = true).await()
Prefs.biometricsEnabled = it
prefs.biometricsEnabled = it
reloadByTitle(R.string.enable_biometrics)
}
}) {

View File

@ -30,6 +30,8 @@ import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlinx.coroutines.CompletableDeferred
import org.koin.core.KoinComponent
import org.koin.core.inject
typealias BiometricDeferred = CompletableDeferred<BiometricPrompt.CryptoObject?>
@ -37,11 +39,13 @@ typealias BiometricDeferred = CompletableDeferred<BiometricPrompt.CryptoObject?>
* Container for [BiometricPrompt]
* Inspired by coroutine's CommonPool
*/
object BiometricUtils {
object BiometricUtils : KoinComponent {
private val executor: Executor
get() = pool ?: getOrCreatePoolSync()
private val prefs: Prefs by inject()
@Volatile
private var pool: ExecutorService? = null
@ -65,7 +69,7 @@ object BiometricUtils {
pool ?: Executors.newSingleThreadExecutor().also { pool = it }
private fun shouldPrompt(context: Context): Boolean {
return Prefs.biometricsEnabled && System.currentTimeMillis() - lastUnlockTime > UNLOCK_TIME_INTERVAL
return prefs.biometricsEnabled && System.currentTimeMillis() - lastUnlockTime > UNLOCK_TIME_INTERVAL
}
/**

View File

@ -21,6 +21,8 @@ import ca.allanwang.kau.logging.KauLogger
import ca.allanwang.kau.logging.KauLoggerExtension
import com.bugsnag.android.Bugsnag
import com.pitchedapps.frost.BuildConfig
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-05-28.
@ -31,9 +33,11 @@ object L : KauLogger("Frost", {
when (it) {
Log.VERBOSE -> BuildConfig.DEBUG
Log.INFO, Log.ERROR -> true
else -> BuildConfig.DEBUG || Prefs.verboseLogging
else -> BuildConfig.DEBUG || L.prefs.verboseLogging
}
}) {
}), KoinComponent {
private val prefs: Prefs by inject()
inline fun test(message: () -> Any?) {
_d {
@ -67,7 +71,7 @@ object L : KauLogger("Frost", {
* bugsnagInit is changed per application and helps prevent crashes (if calling pre init)
* analytics is changed by the user, and may be toggled throughout the app
*/
if (BuildConfig.DEBUG || !bugsnagInit || !Prefs.analytics) {
if (BuildConfig.DEBUG || !bugsnagInit || !prefs.analytics) {
super.logImpl(priority, message, t)
} else {
if (message != null) {

View File

@ -19,6 +19,7 @@ package com.pitchedapps.frost.utils
import android.graphics.Color
import ca.allanwang.kau.kotlin.lazyResettable
import ca.allanwang.kau.kpref.KPref
import ca.allanwang.kau.kpref.KPrefFactory
import ca.allanwang.kau.utils.colorToForeground
import ca.allanwang.kau.utils.isColorVisibleOn
import ca.allanwang.kau.utils.withAlpha
@ -29,13 +30,15 @@ import com.pitchedapps.frost.enums.FeedSort
import com.pitchedapps.frost.enums.MainActivityLayout
import com.pitchedapps.frost.enums.Theme
import com.pitchedapps.frost.injectors.InjectorContract
import org.koin.core.context.GlobalContext
import org.koin.dsl.module
/**
* Created by Allan Wang on 2017-05-28.
*
* Shared Preference object with lazy cached retrievals
*/
object Prefs : KPref() {
class Prefs(factory: KPrefFactory) : KPref("${BuildConfig.APPLICATION_ID}.prefs", factory) {
var lastLaunch: Long by kpref("last_launch", -1L)
@ -69,7 +72,7 @@ object Prefs : KPref() {
var identifier: Int by kpref("identifier", -1)
private val loader = lazyResettable { Theme.values[Prefs.theme] }
private val loader = lazyResettable { Theme.values[theme] }
val t: Theme by loader
@ -87,9 +90,9 @@ object Prefs : KPref() {
}
inline val nativeBgColor: Int
get() = Prefs.bgColor.withAlpha(30)
get() = bgColor.withAlpha(30)
fun nativeBgColor(unread: Boolean) = Prefs.bgColor
fun nativeBgColor(unread: Boolean) = bgColor
.colorToForeground(if (unread) 0.7f else 0.0f)
.withAlpha(30)
@ -194,5 +197,11 @@ object Prefs : KPref() {
inline val mainActivityLayout: MainActivityLayout
get() = MainActivityLayout(mainActivityLayoutType)
override fun deleteKeys() = arrayOf("search_bar")
companion object {
fun get(): Prefs = GlobalContext.get().koin.get()
fun module() = module {
single { Prefs(get()) }
}
}
}

View File

@ -17,18 +17,25 @@
package com.pitchedapps.frost.utils
import ca.allanwang.kau.kpref.KPref
import ca.allanwang.kau.kpref.KPrefFactory
import com.pitchedapps.frost.BuildConfig
import org.koin.dsl.module
/**
* Created by Allan Wang on 2017-07-03.
*
* Showcase prefs that offer one time helpers to guide new users
*/
object Showcase : KPref() {
class Showcase(factory: KPrefFactory) : KPref("${BuildConfig.APPLICATION_ID}.showcase", factory) {
// check if this is the first time launching the web overlay; show snackbar if true
val firstWebOverlay: Boolean by kprefSingle("first_web_overlay")
val intro: Boolean by kprefSingle("intro_pages")
override fun deleteKeys() = arrayOf("shown_release", "experimental_by_default")
companion object {
fun module() = module {
single { Showcase(get()) }
}
}
}

View File

@ -50,6 +50,7 @@ import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.SnackbarContentLayout
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
import com.pitchedapps.frost.activities.BaseActivity
import com.pitchedapps.frost.activities.ImageActivity
import com.pitchedapps.frost.activities.LoginActivity
import com.pitchedapps.frost.activities.SelectorActivity
@ -69,10 +70,6 @@ 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 java.io.File
import java.io.IOException
import java.util.ArrayList
import java.util.Locale
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.coroutineScope
@ -81,6 +78,13 @@ import org.apache.commons.text.StringEscapeUtils
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koin.core.KoinComponent
import org.koin.core.context.GlobalContext
import org.koin.core.inject
import java.io.File
import java.io.IOException
import java.util.ArrayList
import java.util.Locale
/**
* Created by Allan Wang on 2017-06-03.
@ -124,6 +128,7 @@ fun Activity.cookies(): ArrayList<CookieEntity> {
* See [requestWebOverlay] to verify the launch
*/
private inline fun <reified T : WebOverlayActivityBase> Context.launchWebOverlayImpl(url: String) {
val prefs = Prefs.get()
val argUrl = url.formattedFbUrl
L.v { "Launch received: $url\nLaunch web overlay: $argUrl" }
if (argUrl.isFacebookUrl && argUrl.contains("/logout.php")) {
@ -131,10 +136,11 @@ private inline fun <reified T : WebOverlayActivityBase> Context.launchWebOverlay
ctxCoroutine.launch {
FbCookie.logout(this@launchWebOverlayImpl)
}
} else if (!(Prefs.linksInDefaultApp && resolveActivityForUri(Uri.parse(argUrl))))
} else if (!(prefs.linksInDefaultApp && resolveActivityForUri(Uri.parse(argUrl)))) {
startActivity<T>(false, intentBuilder = {
putExtra(ARG_URL, argUrl)
})
}
}
fun Context.launchWebOverlay(url: String) = launchWebOverlayImpl<WebOverlayActivity>(url)
@ -172,22 +178,24 @@ fun WebOverlayActivity.url(): String {
}
fun Activity.setFrostTheme(forceTransparent: Boolean = false) {
val prefs = Prefs.get()
val isTransparent =
forceTransparent || (Color.alpha(Prefs.bgColor) != 255) || (Color.alpha(Prefs.headerColor) != 255)
if (Prefs.bgColor.isColorDark) {
forceTransparent || (Color.alpha(prefs.bgColor) != 255) || (Color.alpha(prefs.headerColor) != 255)
if (prefs.bgColor.isColorDark) {
setTheme(if (isTransparent) R.style.FrostTheme_Transparent else R.style.FrostTheme)
} else {
setTheme(if (isTransparent) R.style.FrostTheme_Light_Transparent else R.style.FrostTheme_Light)
}
}
class ActivityThemeUtils {
class ActivityThemeUtils : KoinComponent {
private var toolbar: Toolbar? = null
var themeWindow = true
private var texts = mutableListOf<TextView>()
private var headers = mutableListOf<View>()
private var backgrounds = mutableListOf<View>()
private val prefs: Prefs by inject()
fun toolbar(toolbar: Toolbar) {
this.toolbar = toolbar
@ -207,15 +215,15 @@ class ActivityThemeUtils {
fun theme(activity: Activity) {
with(activity) {
statusBarColor = Prefs.headerColor.darken(0.1f).withAlpha(255)
if (Prefs.tintNavBar) navigationBarColor = Prefs.headerColor
if (themeWindow) window.setBackgroundDrawable(ColorDrawable(Prefs.bgColor))
toolbar?.setBackgroundColor(Prefs.headerColor)
toolbar?.setTitleTextColor(Prefs.iconColor)
toolbar?.overflowIcon?.setTint(Prefs.iconColor)
texts.forEach { it.setTextColor(Prefs.textColor) }
headers.forEach { it.setBackgroundColor(Prefs.headerColor) }
backgrounds.forEach { it.setBackgroundColor(Prefs.bgColor) }
statusBarColor = prefs.headerColor.darken(0.1f).withAlpha(255)
if (prefs.tintNavBar) navigationBarColor = prefs.headerColor
if (themeWindow) window.setBackgroundDrawable(ColorDrawable(prefs.bgColor))
toolbar?.setBackgroundColor(prefs.headerColor)
toolbar?.setTitleTextColor(prefs.iconColor)
toolbar?.overflowIcon?.setTint(prefs.iconColor)
texts.forEach { it.setTextColor(prefs.textColor) }
headers.forEach { it.setBackgroundColor(prefs.headerColor) }
backgrounds.forEach { it.setBackgroundColor(prefs.bgColor) }
}
}
}
@ -248,18 +256,20 @@ fun View.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {})
@SuppressLint("RestrictedApi")
private inline fun frostSnackbar(crossinline builder: Snackbar.() -> Unit): Snackbar.() -> Unit = {
val prefs = Prefs.get()
builder()
// hacky workaround, but it has proper checks and shouldn't crash
((view as? FrameLayout)?.getChildAt(0) as? SnackbarContentLayout)?.apply {
messageView.setTextColor(Prefs.textColor)
actionView.setTextColor(Prefs.accentColor)
messageView.setTextColor(prefs.textColor)
actionView.setTextColor(prefs.accentColor)
// only set if previous text colors are set
view.setBackgroundColor(Prefs.bgColor.withAlpha(255).colorToForeground(0.1f))
view.setBackgroundColor(prefs.bgColor.withAlpha(255).colorToForeground(0.1f))
}
}
fun Activity.frostNavigationBar() {
navigationBarColor = if (Prefs.tintNavBar) Prefs.headerColor else Color.BLACK
val prefs = Prefs.get()
navigationBarColor = if (prefs.tintNavBar) prefs.headerColor else Color.BLACK
}
@Throws(IOException::class)
@ -393,10 +403,11 @@ inline fun Context.sendFrostEmail(subjectId: String, crossinline builder: EmailB
}
fun EmailBuilder.addFrostDetails() {
addItem("Prev version", Prefs.prevVersionCode.toString())
val prefs = Prefs.get()
addItem("Prev version", prefs.prevVersionCode.toString())
val proTag = "FO"
// if (IS_FROST_PRO) "TY" else "FP"
addItem("Random Frost ID", "${Prefs.frostId}-$proTag")
addItem("Random Frost ID", "${prefs.frostId}-$proTag")
addItem("Locale", Locale.getDefault().displayName)
}
@ -438,7 +449,7 @@ fun String.unescapeHtml(): String =
.replace("\\u003C", "<")
.replace("\\\"", "\"")
suspend fun Context.loadAssets(): Unit = coroutineScope {
CssAssets.load(this@loadAssets)
suspend fun Context.loadAssets(prefs: Prefs): Unit = coroutineScope {
CssAssets.load(this@loadAssets, prefs)
JsAssets.load(this@loadAssets)
}

View File

@ -38,18 +38,23 @@ import com.pitchedapps.frost.facebook.profilePictureUrl
import com.pitchedapps.frost.glide.FrostGlide
import com.pitchedapps.frost.glide.GlideApp
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-06-05.
*/
class AccountItem(val cookie: CookieEntity?) : KauIItem<AccountItem.ViewHolder>
(R.layout.view_account, { ViewHolder(it) }, R.id.item_account) {
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()
override fun bindView(holder: ViewHolder, payloads: MutableList<Any>) {
super.bindView(holder, payloads)
with(holder) {
text.invisible()
text.setTextColor(Prefs.textColor)
text.setTextColor(prefs.textColor)
if (cookie != null) {
text.text = cookie.name
GlideApp.with(itemView).load(profilePictureUrl(cookie.id))
@ -81,7 +86,7 @@ class AccountItem(val cookie: CookieEntity?) : KauIItem<AccountItem.ViewHolder>
GoogleMaterial.Icon.gmd_add_circle_outline.toDrawable(
itemView.context,
100,
Prefs.textColor
prefs.textColor
)
)
text.text = itemView.context.getString(R.string.kau_add_account)

View File

@ -30,6 +30,8 @@ import ca.allanwang.kau.utils.withAlpha
import com.mikepenz.iconics.typeface.IIcon
import com.pitchedapps.frost.databinding.ViewBadgedIconBinding
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-06-19.
@ -38,8 +40,10 @@ class BadgedIcon @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
) : ConstraintLayout(context, attrs, defStyleAttr), KoinComponent {
private val prefs: Prefs by inject()
private val binding: ViewBadgedIconBinding =
ViewBadgedIconBinding.inflate(LayoutInflater.from(context), this, true)
@ -49,7 +53,7 @@ class BadgedIcon @JvmOverloads constructor(
fun ViewBadgedIconBinding.init() {
val badgeColor =
Prefs.mainActivityLayout.backgroundColor().withAlpha(255).colorToForeground(0.2f)
prefs.mainActivityLayout.backgroundColor(prefs).withAlpha(255).colorToForeground(0.2f)
val badgeBackground =
GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,
@ -57,7 +61,7 @@ class BadgedIcon @JvmOverloads constructor(
)
badgeBackground.cornerRadius = 13.dpToPx.toFloat()
badgeText.background = badgeBackground
badgeText.setTextColor(Prefs.mainActivityLayout.iconColor())
badgeText.setTextColor(prefs.mainActivityLayout.iconColor(prefs))
}
var iicon: IIcon? = null
@ -67,13 +71,13 @@ class BadgedIcon @JvmOverloads constructor(
value?.toDrawable(
context,
sizeDp = 20,
color = Prefs.mainActivityLayout.iconColor()
color = prefs.mainActivityLayout.iconColor(prefs)
)
)
}
fun setAllAlpha(alpha: Float) {
// badgeTextView.setTextColor(Prefs.textColor.withAlpha(alpha.toInt()))
// badgeTextView.setTextColor(prefs.textColor.withAlpha(alpha.toInt()))
binding.badgeImage.drawable.alpha = alpha.toInt()
}

View File

@ -47,6 +47,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
import kotlinx.coroutines.channels.ReceiveChannel
import org.koin.core.KoinComponent
import org.koin.core.inject
class FrostContentWeb @JvmOverloads constructor(
context: Context,
@ -75,8 +77,9 @@ abstract class FrostContentView<out T> @JvmOverloads constructor(
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes),
FrostContentParent where T : View, T : FrostContentCore {
FrostContentParent, KoinComponent where T : View, T : FrostContentCore {
private val prefs: Prefs 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)
@ -153,9 +156,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(prefs.textColor.withAlpha(180))
refresh.setColorSchemeColors(prefs.iconColor)
refresh.setProgressBackgroundColorSchemeColor(prefs.headerColor.withAlpha(255))
}
override fun reloadTextSizeSelf() {
@ -192,7 +195,7 @@ abstract class FrostContentView<out T> @JvmOverloads constructor(
if (isVisible)
fadeOut(duration = 200L)
} else if (loading) {
if (animate && Prefs.animate) circularReveal(offset = WEB_LOAD_DELAY)
if (animate && prefs.animate) circularReveal(offset = WEB_LOAD_DELAY)
else fadeIn(duration = 200L, offset = WEB_LOAD_DELAY)
L.v { "Transition loaded in ${System.currentTimeMillis() - transitionStart} ms" }
receiver.cancel()

View File

@ -30,6 +30,8 @@ import com.pitchedapps.frost.fragments.RecyclerContentContract
import com.pitchedapps.frost.utils.Prefs
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-05-29.
@ -41,8 +43,11 @@ class FrostRecyclerView @JvmOverloads constructor(
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr),
KoinComponent,
FrostContentCore {
private val prefs: Prefs by inject()
override fun reload(animate: Boolean) = reloadBase(animate)
override lateinit var parent: FrostContentParent
@ -71,13 +76,13 @@ class FrostRecyclerView @JvmOverloads constructor(
var onReloadClear: () -> Unit = {}
override fun reloadBase(animate: Boolean) {
if (Prefs.animate) fadeOut(onFinish = onReloadClear)
if (prefs.animate) fadeOut(onFinish = onReloadClear)
scope.launch {
parent.refreshChannel.offer(true)
recyclerContract.reload { parent.progressChannel.offer(it) }
parent.progressChannel.offer(100)
parent.refreshChannel.offer(false)
if (Prefs.animate) circularReveal()
if (prefs.animate) circularReveal()
}
}

View File

@ -47,6 +47,8 @@ import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.ctxCoroutine
import com.pitchedapps.frost.utils.frostDownload
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-10-13.
@ -55,7 +57,7 @@ class FrostVideoViewer @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr), FrostVideoViewerContract {
) : FrameLayout(context, attrs, defStyleAttr), FrostVideoViewerContract , KoinComponent {
companion object {
/**
@ -85,6 +87,8 @@ class FrostVideoViewer @JvmOverloads constructor(
}
}
private val prefs: Prefs by inject()
private val binding: ViewVideoBinding =
ViewVideoBinding.inflate(LayoutInflater.from(context), this, true)
@ -95,8 +99,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 && prefs.bgColor.isColorDark)
prefs.bgColor.withMinAlpha(200)
else
Color.BLACK
)
@ -104,7 +108,7 @@ class FrostVideoViewer @JvmOverloads constructor(
video.pause()
videoToolbar.inflateMenu(R.menu.menu_video)
context.setMenuIcons(
videoToolbar.menu, Prefs.iconColor,
videoToolbar.menu, prefs.iconColor,
R.id.action_pip to GoogleMaterial.Icon.gmd_picture_in_picture_alt,
R.id.action_download to GoogleMaterial.Icon.gmd_file_download
)

View File

@ -22,6 +22,8 @@ import android.util.AttributeSet
import android.view.MotionEvent
import androidx.viewpager.widget.ViewPager
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-07-07.
@ -29,12 +31,14 @@ import com.pitchedapps.frost.utils.Prefs
* Basic override to allow us to control swiping
*/
class FrostViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
ViewPager(context, attrs) {
ViewPager(context, attrs), KoinComponent {
private val prefs: Prefs by inject()
var enableSwipe = true
override fun onInterceptTouchEvent(ev: MotionEvent?) =
try {
Prefs.viewpagerSwipe && enableSwipe && super.onInterceptTouchEvent(ev)
prefs.viewpagerSwipe && enableSwipe && super.onInterceptTouchEvent(ev)
} catch (e: IllegalArgumentException) {
false
}
@ -42,7 +46,7 @@ class FrostViewPager @JvmOverloads constructor(context: Context, attrs: Attribut
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(ev: MotionEvent?): Boolean =
try {
Prefs.viewpagerSwipe && enableSwipe && super.onTouchEvent(ev)
prefs.viewpagerSwipe && enableSwipe && super.onTouchEvent(ev)
} catch (e: IllegalArgumentException) {
false
}

View File

@ -41,6 +41,8 @@ import com.pitchedapps.frost.web.FrostChromeClient
import com.pitchedapps.frost.web.FrostJSI
import com.pitchedapps.frost.web.FrostWebViewClient
import com.pitchedapps.frost.web.NestedWebView
import org.koin.core.KoinComponent
import org.koin.core.inject
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@ -54,7 +56,10 @@ class FrostWebView @JvmOverloads constructor(
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : NestedWebView(context, attrs, defStyleAttr),
FrostContentCore {
FrostContentCore,
KoinComponent {
val prefs: Prefs by inject()
override fun reload(animate: Boolean) {
if (parent.registerTransition(false, animate))
@ -75,7 +80,7 @@ class FrostWebView @JvmOverloads constructor(
javaScriptEnabled = true
mediaPlaybackRequiresUserGesture = false // TODO check if we need this
allowFileAccess = true
textZoom = Prefs.webTextScaling
textZoom = prefs.webTextScaling
domStorageEnabled = true
}
setLayerType(LAYER_TYPE_HARDWARE, null)
@ -208,7 +213,7 @@ class FrostWebView @JvmOverloads constructor(
}
override fun reloadTextSizeSelf() {
settings.textZoom = Prefs.webTextScaling
settings.textZoom = prefs.webTextScaling
}
override fun destroy() {

View File

@ -38,6 +38,8 @@ import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.R
import com.pitchedapps.frost.utils.Prefs
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-06-19.
@ -46,8 +48,9 @@ class Keywords @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
) : ConstraintLayout(context, attrs, defStyleAttr), KoinComponent {
private val prefs: Prefs 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)
@ -55,8 +58,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))
editText.tint(prefs.textColor)
addIcon.setImageDrawable(GoogleMaterial.Icon.gmd_add.keywordDrawable(context, prefs))
addIcon.setOnClickListener {
if (editText.text.isNullOrEmpty()) editText.error =
context.string(R.string.empty_keyword)
@ -65,7 +68,7 @@ class Keywords @JvmOverloads constructor(
editText.text?.clear()
}
}
adapter.add(Prefs.notificationKeywords.map { KeywordItem(it) })
adapter.add(prefs.notificationKeywords.map { KeywordItem(it) })
recycler.layoutManager = LinearLayoutManager(context)
recycler.adapter = adapter
adapter.addEventHook(object : ClickEventHook<KeywordItem>() {
@ -84,12 +87,12 @@ class Keywords @JvmOverloads constructor(
}
fun save() {
Prefs.notificationKeywords = adapter.adapterItems.mapTo(mutableSetOf()) { it.keyword }
prefs.notificationKeywords = adapter.adapterItems.mapTo(mutableSetOf()) { it.keyword }
}
}
private fun IIcon.keywordDrawable(context: Context): Drawable =
toDrawable(context, 20, Prefs.textColor)
private fun IIcon.keywordDrawable(context: Context, prefs: Prefs): Drawable =
toDrawable(context, 20, prefs.textColor)
class KeywordItem(val keyword: String) : AbstractItem<KeywordItem.ViewHolder>() {
@ -111,13 +114,15 @@ class KeywordItem(val keyword: String) : AbstractItem<KeywordItem.ViewHolder>()
holder.text.text = null
}
class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
class ViewHolder(v: View) : RecyclerView.ViewHolder(v), KoinComponent {
private val prefs: Prefs 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)
delete.setImageDrawable(GoogleMaterial.Icon.gmd_delete.keywordDrawable(itemView.context))
text.setTextColor(prefs.textColor)
delete.setImageDrawable(GoogleMaterial.Icon.gmd_delete.keywordDrawable(itemView.context, prefs))
}
}
}

View File

@ -34,6 +34,8 @@ import com.pitchedapps.frost.utils.isFacebookUrl
import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2018-01-05.
@ -44,8 +46,9 @@ class DebugWebView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : WebView(context, attrs, defStyleAttr) {
) : WebView(context, attrs, defStyleAttr), KoinComponent {
private val prefs: Prefs by inject()
var onPageFinished: (String?) -> Unit = {}
init {
@ -93,7 +96,7 @@ class DebugWebView @JvmOverloads constructor(
private fun injectBackgroundColor() {
setBackgroundColor(
if (url.isFacebookUrl) Prefs.bgColor.withAlpha(255)
if (url.isFacebookUrl) prefs.bgColor.withAlpha(255)
else Color.WHITE
)
}
@ -104,15 +107,16 @@ class DebugWebView @JvmOverloads constructor(
if (url.isFacebookUrl)
view.jsInject(
// CssHider.CORE,
CssHider.COMPOSER.maybe(!Prefs.showComposer),
CssHider.STORIES.maybe(!Prefs.showStories),
CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends),
CssHider.SUGGESTED_GROUPS.maybe(!Prefs.showSuggestedGroups),
Prefs.themeInjector,
CssHider.COMPOSER.maybe(!prefs.showComposer),
CssHider.STORIES.maybe(!prefs.showStories),
CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!prefs.showSuggestedFriends),
CssHider.SUGGESTED_GROUPS.maybe(!prefs.showSuggestedGroups),
prefs.themeInjector,
CssHider.NON_RECENT.maybe(
(url?.contains("?sk=h_chr") ?: false) &&
Prefs.aggressiveRecents
)
prefs.aggressiveRecents
),
prefs= prefs
)
}
}

View File

@ -41,6 +41,7 @@ import kotlinx.coroutines.launch
*/
class FrostJSI(val web: FrostWebView) {
private val prefs: Prefs = web.prefs
private val context: Context = web.context
private val activity: MainActivity? = context as? MainActivity
private val header: SendChannel<String>? = activity?.headerBadgeChannel
@ -57,7 +58,7 @@ class FrostJSI(val web: FrostWebView) {
@JavascriptInterface
fun loadVideo(url: String?, isGif: Boolean): Boolean =
if (url != null && Prefs.enablePip) {
if (url != null && prefs.enablePip) {
web.post {
(context as? VideoViewHolder)?.showVideo(url, isGif)
?: L.e { "Could not load video; contract not implemented" }

View File

@ -76,7 +76,7 @@ fun FrostWebView.requestWebOverlay(url: String): Boolean {
L.d { "Forbid overlay switch" }
return false
}
if (!Prefs.overlayEnabled) return false
if (!prefs.overlayEnabled) return false
if (context is WebOverlayActivityBase) {
val shouldUseDesktop = url.isFacebookUrl
// already overlay; manage user agent

View File

@ -42,6 +42,8 @@ import com.pitchedapps.frost.utils.launchImageActivity
import com.pitchedapps.frost.utils.resolveActivityForUri
import com.pitchedapps.frost.views.FrostWebView
import kotlinx.coroutines.channels.SendChannel
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-05-31.
@ -67,6 +69,7 @@ open class BaseWebViewClient : WebViewClient() {
*/
open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
private val prefs: Prefs get() = web.prefs
private val refresh: SendChannel<Boolean> = web.parent.refreshChannel
private val isMain = web.parent.baseEnum != null
/**
@ -102,7 +105,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
web.setBackgroundColor(
when {
isMain -> Color.TRANSPARENT
web.url.isFacebookUrl -> Prefs.bgColor.withAlpha(255)
web.url.isFacebookUrl -> prefs.bgColor.withAlpha(255)
else -> Color.WHITE
}
)
@ -115,21 +118,22 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
view.jsInject(
// CssHider.CORE,
CssHider.HEADER,
CssHider.COMPOSER.maybe(!Prefs.showComposer),
CssHider.STORIES.maybe(!Prefs.showStories),
CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends),
CssHider.SUGGESTED_GROUPS.maybe(!Prefs.showSuggestedGroups),
Prefs.themeInjector,
CssHider.COMPOSER.maybe(!prefs.showComposer),
CssHider.STORIES.maybe(!prefs.showStories),
CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!prefs.showSuggestedFriends),
CssHider.SUGGESTED_GROUPS.maybe(!prefs.showSuggestedGroups),
prefs.themeInjector,
CssHider.NON_RECENT.maybe(
(web.url?.contains("?sk=h_chr") ?: false) &&
Prefs.aggressiveRecents
prefs.aggressiveRecents
),
JsAssets.DOCUMENT_WATCHER,
JsAssets.HORIZONTAL_SCROLLING,
JsAssets.CLICK_A,
CssHider.ADS.maybe(!Prefs.showFacebookAds),
CssHider.ADS.maybe(!prefs.showFacebookAds),
JsAssets.CONTEXT_A,
JsAssets.MEDIA
JsAssets.MEDIA,
prefs = prefs
)
} else {
refresh.offer(false)
@ -147,7 +151,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
}
internal open fun onPageFinishedActions(url: String) {
if (url.startsWith("${FbItem.MESSAGES.url}/read/") && Prefs.messageScrollToBottom) {
if (url.startsWith("${FbItem.MESSAGES.url}/read/") && prefs.messageScrollToBottom) {
web.pageDown(true)
}
injectAndFinish()
@ -160,7 +164,8 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
web.jsInject(
JsActions.LOGIN_CHECK,
JsAssets.TEXTAREA_LISTENER,
JsAssets.HEADER_BADGES.maybe(isMain)
JsAssets.HEADER_BADGES.maybe(isMain),
prefs = prefs
)
}
@ -207,7 +212,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
if (url.isImageUrl) {
return launchImage(url.formattedFbUrl)
}
if (Prefs.linksInDefaultApp && view.context.resolveActivityForUri(request.url)) {
if (prefs.linksInDefaultApp && view.context.resolveActivityForUri(request.url)) {
return true
}
// Convert desktop urls to mobile ones
@ -229,12 +234,14 @@ 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) {
return
}
jsInject(JsAssets.MENU)
jsInject(JsAssets.MENU, prefs = prefs)
}
override fun emit(flag: Int) {

View File

@ -42,6 +42,8 @@ import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.isFacebookUrl
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.coroutineScope
import org.koin.core.KoinComponent
import org.koin.core.inject
/**
* Created by Allan Wang on 2017-05-29.
@ -50,8 +52,9 @@ class LoginWebView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : WebView(context, attrs, defStyleAttr) {
) : WebView(context, attrs, defStyleAttr), KoinComponent {
private val prefs: Prefs by inject()
private val completable: CompletableDeferred<CookieEntity> = CompletableDeferred()
private lateinit var progressCallback: (Int) -> Unit
@ -101,7 +104,8 @@ class LoginWebView @JvmOverloads constructor(
if (url.isFacebookUrl)
view.jsInject(
CssHider.CORE,
Prefs.themeInjector
prefs.themeInjector,
prefs = prefs
)
}

View File

@ -50,7 +50,9 @@ import com.pitchedapps.frost.utils.toReadableTime
import org.koin.core.KoinComponent
import org.koin.core.inject
class NotificationWidget : AppWidgetProvider() {
class NotificationWidget : AppWidgetProvider(), KoinComponent {
private val prefs: Prefs by inject()
override fun onUpdate(
context: Context,
@ -59,19 +61,19 @@ class NotificationWidget : AppWidgetProvider() {
) {
super.onUpdate(context, appWidgetManager, appWidgetIds)
val type = NotificationType.GENERAL
val userId = Prefs.userId
val userId = prefs.userId
val intent = NotificationWidgetService.createIntent(context, type, userId)
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, prefs.headerColor)
views.setIcon(R.id.img_frost, context, R.drawable.frost_f_24, prefs.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, prefs.bgColor)
views.setRemoteAdapter(R.id.widget_notification_list, intent)
val pendingIntentTemplate = PendingIntent.getActivity(
@ -149,6 +151,8 @@ class NotificationWidgetDataProvider(val context: Context, val intent: Intent) :
RemoteViewsService.RemoteViewsFactory,
KoinComponent {
private val prefs: Prefs by inject()
private val notifDao: NotificationDao by inject()
@Volatile
private var content: List<NotificationContent> = emptyList()
@ -182,10 +186,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, prefs.nativeBgColor(notif.unread))
views.setTextColor(R.id.item_content, prefs.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, prefs.textColor.withAlpha(150))
views.setTextViewText(R.id.item_date, notif.timestamp.toReadableTime(context))
val avatar = glide.load(notif.profileUrl).transform(FrostGlide.circleCrop)

View File

@ -16,7 +16,7 @@ org.gradle.daemon = true
APP_ID=Frost
APP_GROUP=com.pitchedapps
KAU=e4bba6f
KAU=5038b93
android.useAndroidX=true
android.enableJetifier=true