Skip to content

Commit

Permalink
Fix theme changing from preference
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbanes committed Dec 1, 2020
1 parent 6d89c50 commit bc5683e
Show file tree
Hide file tree
Showing 14 changed files with 117 additions and 28 deletions.
6 changes: 5 additions & 1 deletion app/src/main/java/app/tivi/home/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ import androidx.navigation.NavController
import app.tivi.AppNavigator
import app.tivi.R
import app.tivi.TiviActivity
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.databinding.ActivityMainBinding
import app.tivi.extensions.MultipleBackStackNavigation
import app.tivi.extensions.hideSoftInput
import app.tivi.settings.TiviPreferences
import app.tivi.trakt.TraktConstants
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.ProvideWindowInsets
Expand All @@ -50,6 +52,8 @@ class MainActivity : TiviActivity() {

@Inject lateinit var navigator: AppNavigator

@Inject lateinit var preferences: TiviPreferences

private var currentSelectedItem by mutableStateOf(HomeNavigation.Discover)

private lateinit var multiBackStackNavigation: MultipleBackStackNavigation
Expand Down Expand Up @@ -89,7 +93,7 @@ class MainActivity : TiviActivity() {

binding.homeBottomNavigation.setContent {
ProvideWindowInsets {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
HomeBottomNavigation(
selectedNavigation = currentSelectedItem,
onNavigationSelected = { item ->
Expand Down
7 changes: 6 additions & 1 deletion base/src/main/java/app/tivi/settings/TiviPreferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@

package app.tivi.settings

import kotlinx.coroutines.flow.Flow

interface TiviPreferences {

fun setup()

var themePreference: Theme
var theme: Theme
fun observeTheme(): Flow<Theme>

var useLessData: Boolean
fun observeUseLessData(): Flow<Boolean>

enum class Theme {
LIGHT,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package app.tivi.common.compose

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import app.tivi.settings.TiviPreferences

@Composable
fun TiviPreferences.shouldUseDarkColors(): Boolean {
val themePreference = observeTheme().collectAsState(initial = TiviPreferences.Theme.SYSTEM)
return when (themePreference.value) {
TiviPreferences.Theme.LIGHT -> false
TiviPreferences.Theme.DARK -> true
else -> isSystemInDarkTheme()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import app.tivi.common.compose.AmbientTiviDateFormatter
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.navigateToNavDestination
import app.tivi.settings.TiviPreferences
import app.tivi.util.TiviDateFormatter
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
Expand All @@ -50,6 +52,8 @@ class AccountUiFragment : DialogFragment() {

@Inject internal lateinit var tiviDateFormatter: TiviDateFormatter

@Inject lateinit var preferences: TiviPreferences

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -66,7 +70,7 @@ class AccountUiFragment : DialogFragment() {
AmbientTiviDateFormatter provides tiviDateFormatter,
AmbientWindowInsets provides windowInsets,
) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
val viewState by viewModel.liveData.observeAsState()
if (viewState != null) {
AccountUi(viewState!!) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import app.tivi.common.compose.AmbientTiviDateFormatter
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.DefaultNavOptions
import app.tivi.settings.TiviPreferences
import app.tivi.util.TiviDateFormatter
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
Expand All @@ -46,6 +48,7 @@ import javax.inject.Inject
class DiscoverFragment : Fragment() {
@Inject internal lateinit var tiviDateFormatter: TiviDateFormatter
@Inject internal lateinit var textCreator: DiscoverTextCreator
@Inject lateinit var preferences: TiviPreferences

private val viewModel: DiscoverViewModel by viewModels()

Expand All @@ -68,7 +71,7 @@ class DiscoverFragment : Fragment() {
AmbientDiscoverTextCreator provides textCreator,
AmbientWindowInsets provides windowInsets,
) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
val viewState by viewModel.liveData.observeAsState()
if (viewState != null) {
Discover(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import app.tivi.common.compose.AmbientTiviDateFormatter
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.viewModelProviderFactoryOf
import app.tivi.settings.TiviPreferences
import app.tivi.util.TiviDateFormatter
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
Expand All @@ -46,6 +48,7 @@ import javax.inject.Inject
@AndroidEntryPoint
class EpisodeDetailsFragment : Fragment() {
@Inject internal lateinit var vmFactory: EpisodeDetailsViewModel.Factory
@Inject lateinit var preferences: TiviPreferences

companion object {
private const val ARG_KEY_ID = "episode_id"
Expand Down Expand Up @@ -85,7 +88,7 @@ class EpisodeDetailsFragment : Fragment() {
AmbientTiviDateFormatter provides tiviDateFormatter,
AmbientWindowInsets provides windowInsets,
) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
val viewState by viewModel.liveData.observeAsState()
if (viewState != null) {
EpisodeDetails(viewState!!) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ import androidx.navigation.fragment.findNavController
import androidx.paging.compose.collectAsLazyPagingItems
import app.tivi.common.compose.AmbientHomeTextCreator
import app.tivi.common.compose.AmbientTiviDateFormatter
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.DefaultNavOptions
import app.tivi.home.HomeTextCreator
import app.tivi.settings.TiviPreferences
import app.tivi.util.TiviDateFormatter
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
Expand All @@ -49,6 +51,7 @@ import javax.inject.Inject
class FollowedFragment : Fragment() {
@Inject internal lateinit var tiviDateFormatter: TiviDateFormatter
@Inject internal lateinit var homeTextCreator: HomeTextCreator
@Inject lateinit var preferences: TiviPreferences

private val viewModel: FollowedViewModel by viewModels()

Expand All @@ -71,7 +74,7 @@ class FollowedFragment : Fragment() {
AmbientHomeTextCreator provides homeTextCreator,
AmbientWindowInsets provides windowInsets,
) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
val viewState by viewModel.liveData.observeAsState()
if (viewState != null) {
Followed(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ import androidx.navigation.fragment.findNavController
import app.tivi.common.compose.AmbientHomeTextCreator
import app.tivi.common.compose.AmbientTiviDateFormatter
import app.tivi.common.compose.paging.collectAsLazyPagingItems
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.DefaultNavOptions
import app.tivi.home.HomeTextCreator
import app.tivi.settings.TiviPreferences
import app.tivi.util.TiviDateFormatter
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
Expand All @@ -47,6 +49,7 @@ import javax.inject.Inject
class PopularShowsFragment : Fragment() {
@Inject internal lateinit var tiviDateFormatter: TiviDateFormatter
@Inject internal lateinit var homeTextCreator: HomeTextCreator
@Inject lateinit var preferences: TiviPreferences

private val pendingActions = Channel<PopularAction>(Channel.BUFFERED)

Expand All @@ -73,7 +76,7 @@ class PopularShowsFragment : Fragment() {
AmbientHomeTextCreator provides homeTextCreator,
AmbientWindowInsets provides windowInsets,
) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
Popular(
lazyPagingItems = pagedList.collectAsLazyPagingItems { old, new ->
old.entry.id == new.entry.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ import androidx.navigation.fragment.findNavController
import app.tivi.common.compose.AmbientHomeTextCreator
import app.tivi.common.compose.AmbientTiviDateFormatter
import app.tivi.common.compose.paging.collectAsLazyPagingItems
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.DefaultNavOptions
import app.tivi.home.HomeTextCreator
import app.tivi.settings.TiviPreferences
import app.tivi.util.TiviDateFormatter
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
Expand All @@ -47,6 +49,7 @@ import javax.inject.Inject
class RecommendedShowsFragment : Fragment() {
@Inject internal lateinit var tiviDateFormatter: TiviDateFormatter
@Inject internal lateinit var homeTextCreator: HomeTextCreator
@Inject lateinit var preferences: TiviPreferences

private val pendingActions = Channel<RecommendedAction>(Channel.BUFFERED)

Expand All @@ -73,7 +76,7 @@ class RecommendedShowsFragment : Fragment() {
AmbientHomeTextCreator provides homeTextCreator,
AmbientWindowInsets provides windowInsets,
) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
Recommended(
lazyPagingItems = pagedList.collectAsLazyPagingItems { old, new ->
old.entry.id == new.entry.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,20 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import app.tivi.common.compose.LogCompositions
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.DefaultNavOptions
import app.tivi.settings.TiviPreferences
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
import dev.chrisbanes.accompanist.insets.ViewWindowInsetObserver
import kotlinx.coroutines.channels.Channel
import javax.inject.Inject

@AndroidEntryPoint
internal class SearchFragment : Fragment() {
@Inject lateinit var preferences: TiviPreferences

private val viewModel: SearchViewModel by viewModels()
private val pendingActions = Channel<SearchAction>(Channel.BUFFERED)

Expand Down Expand Up @@ -74,7 +79,7 @@ internal class SearchFragment : Fragment() {

setContent {
Providers(AmbientWindowInsets provides windowInsets) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
val viewState by viewModel.liveData.observeAsState()
if (viewState != null) {
LogCompositions("ViewState observeAsState")
Expand Down
45 changes: 30 additions & 15 deletions ui-settings/src/main/java/app/tivi/settings/TiviPreferencesImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,37 @@ import android.content.SharedPreferences
import androidx.core.content.edit
import app.tivi.settings.TiviPreferences.Theme
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import javax.inject.Inject
import javax.inject.Named

class TiviPreferencesImpl @Inject constructor(
@ApplicationContext private val context: Context,
@Named("app") private val sharedPreferences: SharedPreferences
) : TiviPreferences {
private val defaultThemeValue = context.getString(R.string.pref_theme_default_value)

private val preferenceKeyChangedFlow = MutableSharedFlow<String>(extraBufferCapacity = 1)

private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
when (key) {
KEY_THEME -> updateUsingThemePreference()
}
preferenceKeyChangedFlow.tryEmit(key)
}

private val defaultThemeValue = context.getString(R.string.pref_theme_default_value)

companion object {
const val KEY_THEME = "pref_theme"
const val KEY_DATA_SAVER = "pref_data_saver"
}

override fun setup() {
updateUsingThemePreference()
sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
}

override var themePreference: Theme
override var theme: Theme
get() = getThemeForStorageValue(sharedPreferences.getString(KEY_THEME, defaultThemeValue)!!)
set(value) = sharedPreferences.edit {
putString(KEY_THEME, value.storageKey)
Expand All @@ -58,6 +63,24 @@ class TiviPreferencesImpl @Inject constructor(
putBoolean(KEY_DATA_SAVER, value)
}

override fun observeUseLessData(): Flow<Boolean> {
return preferenceKeyChangedFlow
// Emit on start so that we always send the initial value
.onStart { emit(KEY_DATA_SAVER) }
.filter { it == KEY_DATA_SAVER }
.map { useLessData }
.distinctUntilChanged()
}

override fun observeTheme(): Flow<Theme> {
return preferenceKeyChangedFlow
// Emit on start so that we always send the initial value
.onStart { emit(KEY_THEME) }
.filter { it == KEY_THEME }
.map { theme }
.distinctUntilChanged()
}

private val Theme.storageKey: String
get() = when (this) {
Theme.LIGHT -> context.getString(R.string.pref_theme_light_value)
Expand All @@ -70,12 +93,4 @@ class TiviPreferencesImpl @Inject constructor(
context.getString(R.string.pref_theme_dark_value) -> Theme.DARK
else -> Theme.SYSTEM
}

private fun updateUsingThemePreference() {
// when (themePreference) {
// Theme.DARK -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
// Theme.LIGHT -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
// Theme.SYSTEM -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
// }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.navOptions
import app.tivi.common.compose.LogCompositions
import app.tivi.common.compose.shouldUseDarkColors
import app.tivi.common.compose.theme.TiviTheme
import app.tivi.extensions.DefaultNavOptions
import app.tivi.extensions.viewModelProviderFactoryOf
import app.tivi.settings.TiviPreferences
import app.tivi.util.TiviDateFormatter
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.AmbientWindowInsets
Expand All @@ -49,6 +51,7 @@ class ShowDetailsFragment : Fragment() {
@Inject internal lateinit var vmFactory: ShowDetailsFragmentViewModel.Factory
@Inject internal lateinit var textCreator: ShowDetailsTextCreator
@Inject internal lateinit var tiviDateFormatter: TiviDateFormatter
@Inject lateinit var preferences: TiviPreferences

private val pendingActions = Channel<ShowDetailsAction>(Channel.BUFFERED)

Expand Down Expand Up @@ -121,7 +124,7 @@ class ShowDetailsFragment : Fragment() {
AmbientShowDetailsTextCreator provides textCreator,
AmbientWindowInsets provides windowInsets,
) {
TiviTheme {
TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) {
val viewState by viewModel.liveData.observeAsState()
if (viewState != null) {
LogCompositions("ViewState observeAsState")
Expand Down
Loading

0 comments on commit bc5683e

Please sign in to comment.