diff --git a/app/build.gradle b/app/build.gradle index 0bcae37978..23a622dc61 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,9 +26,6 @@ plugins { id 'kotlin-android' id 'kotlin-kapt' - - id 'com.google.android.gms.oss-licenses-plugin' - id 'androidx.navigation.safeargs.kotlin' } play { @@ -118,6 +115,12 @@ android { buildFeatures { viewBinding true + compose true + } + + composeOptions { + kotlinCompilerVersion Libs.Kotlin.version + kotlinCompilerExtensionVersion Libs.AndroidX.Compose.version } testOptions { @@ -163,6 +166,7 @@ dependencies { implementation project(':base-android') implementation project(':common-ui-view') implementation project(':common-imageloading') + implementation project(':common-ui-compose') implementation project(':data') implementation project(':data-android') implementation project(':trakt') @@ -186,16 +190,19 @@ dependencies { implementation Libs.AndroidX.Lifecycle.livedata implementation Libs.AndroidX.Lifecycle.viewmodel - implementation Libs.AndroidX.appcompat implementation Libs.AndroidX.emoji - implementation Libs.AndroidX.constraintlayout implementation Libs.AndroidX.Fragment.fragmentKtx implementation Libs.AndroidX.Navigation.fragment - implementation Libs.AndroidX.Navigation.ui - implementation Libs.Mdc.material + implementation Libs.AndroidX.Compose.foundation + implementation Libs.AndroidX.Compose.ui + implementation Libs.AndroidX.Compose.layout + implementation Libs.AndroidX.Compose.material + implementation Libs.AndroidX.Compose.animation + implementation Libs.AndroidX.Compose.tooling + implementation Libs.AndroidX.Compose.livedata - implementation Libs.Insetter.ktx + implementation Libs.Accompanist.insets implementation Libs.threeTenAbp @@ -215,7 +222,6 @@ dependencies { implementation Libs.Google.crashlytics implementation Libs.Google.analytics - implementation Libs.Google.openSourceLicensesLibrary debugImplementation Libs.leakCanary diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 24d7cd1751..af1af39614 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -24,22 +24,15 @@ native ; } --keep public class * extends android.view.View { +# We only need to keep ComposeView + FragmentContainerView +-keep public class androidx.compose.ui.platform.ComposeView { public (android.content.Context, android.util.AttributeSet); } --keepclasseswithmembers class * { +-keep public class androidx.fragment.app.FragmentContainerView { public (android.content.Context, android.util.AttributeSet); } --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet, int); -} - --keepclassmembers class * extends android.app.Activity { - public void *(android.view.View); -} - # For enumeration classes -keepclassmembers enum * { ; diff --git a/app/src/main/java/app/tivi/home/Home.kt b/app/src/main/java/app/tivi/home/Home.kt new file mode 100644 index 0000000000..4711e41dcc --- /dev/null +++ b/app/src/main/java/app/tivi/home/Home.kt @@ -0,0 +1,98 @@ +/* + * 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.home + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.preferredHeight +import androidx.compose.material.BottomNavigationItem +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.contentColorFor +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.FavoriteBorder +import androidx.compose.material.icons.filled.Search +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import app.tivi.R +import app.tivi.common.compose.IconResource +import dev.chrisbanes.accompanist.insets.navigationBarsHeight + +internal enum class HomeNavigation { + Discover, + Following, + Watched, + Search, +} + +@Composable +internal fun HomeBottomNavigation( + selectedNavigation: HomeNavigation, + onNavigationSelected: (HomeNavigation) -> Unit, + modifier: Modifier = Modifier +) { + Surface( + color = MaterialTheme.colors.surface, + contentColor = contentColorFor(MaterialTheme.colors.surface), + elevation = 8.dp, + modifier = modifier + ) { + Column { + Row( + Modifier.fillMaxWidth().preferredHeight(56.dp), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + BottomNavigationItem( + icon = { IconResource(R.drawable.ic_weekend_black_24dp) }, + label = { Text(stringResource(R.string.discover_title)) }, + selected = selectedNavigation == HomeNavigation.Discover, + onClick = { onNavigationSelected(HomeNavigation.Discover) }, + ) + + BottomNavigationItem( + icon = { Icon(Icons.Default.FavoriteBorder) }, + label = { Text(stringResource(R.string.following_shows_title)) }, + selected = selectedNavigation == HomeNavigation.Following, + onClick = { onNavigationSelected(HomeNavigation.Following) }, + ) + + BottomNavigationItem( + icon = { IconResource(R.drawable.ic_visibility) }, + label = { Text(stringResource(R.string.watched_shows_title)) }, + selected = selectedNavigation == HomeNavigation.Watched, + onClick = { onNavigationSelected(HomeNavigation.Watched) }, + ) + + BottomNavigationItem( + icon = { Icon(Icons.Default.Search) }, + label = { Text(stringResource(R.string.search_navigation_title)) }, + selected = selectedNavigation == HomeNavigation.Search, + onClick = { onNavigationSelected(HomeNavigation.Search) }, + ) + } + + Spacer(modifier = Modifier.navigationBarsHeight()) + } + } +} diff --git a/app/src/main/java/app/tivi/home/MainActivity.kt b/app/src/main/java/app/tivi/home/MainActivity.kt index 9442b13751..509d3424f8 100644 --- a/app/src/main/java/app/tivi/home/MainActivity.kt +++ b/app/src/main/java/app/tivi/home/MainActivity.kt @@ -18,19 +18,27 @@ package app.tivi.home import android.content.Intent import android.os.Bundle +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.core.view.WindowCompat import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModelProvider 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.extensions.setupWithNavController +import app.tivi.settings.TiviPreferences import app.tivi.trakt.TraktConstants import dagger.hilt.android.AndroidEntryPoint -import dev.chrisbanes.insetter.Insetter -import dev.chrisbanes.insetter.Side +import dev.chrisbanes.accompanist.insets.ProvideWindowInsets import javax.inject.Inject @AndroidEntryPoint @@ -44,60 +52,37 @@ 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 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + WindowCompat.setDecorFitsSystemWindows(window, false) + viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - Insetter.builder() - .applySystemWindowInsetsToPadding(Side.LEFT or Side.RIGHT) - .consumeSystemWindowInsets(Insetter.CONSUME_AUTO) - .applyToView(binding.root) - - Insetter.builder() - .applySystemWindowInsetsToPadding(Side.BOTTOM) - .consumeSystemWindowInsets(Insetter.CONSUME_AUTO) - .applyToView(binding.homeBottomNavigation) - - Insetter.setEdgeToEdgeSystemUiFlags(binding.homeRoot, true) - - if (savedInstanceState == null) { - setupBottomNavigationBar() - } - } - - override fun onRestoreInstanceState(savedInstanceState: Bundle) { - super.onRestoreInstanceState(savedInstanceState) - // Now that BottomNavigationBar has restored its instance state - // and its selectedItemId, we can proceed with setting up the - // BottomNavigationBar with Navigation - setupBottomNavigationBar() - } - - override fun handleIntent(intent: Intent) { - when (intent.action) { - TraktConstants.INTENT_ACTION_HANDLE_AUTH_RESPONSE -> { - navigator.onAuthResponse(intent) - } - } - } - - private fun setupBottomNavigationBar() { - currentNavController = binding.homeBottomNavigation.setupWithNavController( - navGraphIds = listOf( + multiBackStackNavigation = MultipleBackStackNavigation( + navGraphIds = intArrayOf( R.navigation.discover_nav_graph, - R.navigation.watched_nav_graph, R.navigation.following_nav_graph, + R.navigation.watched_nav_graph, R.navigation.search_nav_graph ), fragmentManager = supportFragmentManager, containerId = R.id.home_nav_container, - intent = intent + intent = intent, + getSelectedItemId = { currentSelectedItem.toNavigationId() }, + setSelectedItemId = { currentSelectedItem = navigationIdToHomeNavigation(it) }, ) + currentNavController = multiBackStackNavigation.selectedNavController currentNavController?.observe(this) { navController -> navController.addOnDestinationChangedListener { _, destination, _ -> if (destination.id != R.id.navigation_search) { @@ -105,9 +90,51 @@ class MainActivity : TiviActivity() { } } } + + binding.homeBottomNavigation.setContent { + ProvideWindowInsets { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { + HomeBottomNavigation( + selectedNavigation = currentSelectedItem, + onNavigationSelected = { item -> + if (currentSelectedItem == item) { + multiBackStackNavigation.onReselected(item.toNavigationId()) + } else { + currentSelectedItem = item + multiBackStackNavigation.onItemSelected(item.toNavigationId()) + } + }, + modifier = Modifier.fillMaxWidth() + ) + } + } + } } - override fun onSupportNavigateUp(): Boolean { - return currentNavController?.value?.navigateUp() ?: super.onSupportNavigateUp() + override fun handleIntent(intent: Intent) { + when (intent.action) { + TraktConstants.INTENT_ACTION_HANDLE_AUTH_RESPONSE -> { + navigator.onAuthResponse(intent) + } + } + } + + override fun onNavigateUp(): Boolean { + return currentNavController?.value?.navigateUp() ?: super.onNavigateUp() } } + +private fun HomeNavigation.toNavigationId(): Int = when (this) { + HomeNavigation.Discover -> R.navigation.discover_nav_graph + HomeNavigation.Following -> R.navigation.following_nav_graph + HomeNavigation.Watched -> R.navigation.watched_nav_graph + HomeNavigation.Search -> R.navigation.search_nav_graph +} + +private fun navigationIdToHomeNavigation(id: Int): HomeNavigation = when (id) { + R.navigation.discover_nav_graph -> HomeNavigation.Discover + R.navigation.following_nav_graph -> HomeNavigation.Following + R.navigation.watched_nav_graph -> HomeNavigation.Watched + R.navigation.search_nav_graph -> HomeNavigation.Search + else -> throw IllegalArgumentException("Navigation graph with id not found: $id") +} diff --git a/app/src/main/java/app/tivi/inject/AppModule.kt b/app/src/main/java/app/tivi/inject/AppModule.kt index 8eb2f1b007..6372cd6011 100644 --- a/app/src/main/java/app/tivi/inject/AppModule.kt +++ b/app/src/main/java/app/tivi/inject/AppModule.kt @@ -18,10 +18,8 @@ package app.tivi.inject import android.app.Application import android.content.Context -import androidx.navigation.ui.AppBarConfiguration import app.tivi.BuildConfig import app.tivi.extensions.withLocale -import app.tivi.home.followed.R import app.tivi.tmdb.TmdbModule import app.tivi.trakt.TraktModule import app.tivi.util.AppCoroutineDispatchers @@ -113,15 +111,6 @@ object AppModule { return DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(context) } - @Provides - @Singleton - fun provideAppBarConfiguration() = AppBarConfiguration.Builder( - R.id.navigation_followed, - R.id.navigation_watched, - R.id.navigation_discover, - R.id.navigation_search - ).build() - @Provides @Singleton fun provideFirebaseCrashlytics(): FirebaseCrashlytics = FirebaseCrashlytics.getInstance() diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 9950874202..18f94f273f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -15,32 +15,23 @@ ~ --> - - - - + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1" /> + + - + diff --git a/app/src/main/res/menu/home_bottomnav.xml b/app/src/main/res/menu/home_bottomnav.xml deleted file mode 100644 index 5f7f693bba..0000000000 --- a/app/src/main/res/menu/home_bottomnav.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/account_settings_nav_graph.xml b/app/src/main/res/navigation/account_settings_nav_graph.xml index cfae7abeb5..258f45e03b 100644 --- a/app/src/main/res/navigation/account_settings_nav_graph.xml +++ b/app/src/main/res/navigation/account_settings_nav_graph.xml @@ -29,14 +29,9 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/show_details_nav_graph.xml b/app/src/main/res/navigation/show_details_nav_graph.xml index 4e9b323e98..0ad2f7d765 100644 --- a/app/src/main/res/navigation/show_details_nav_graph.xml +++ b/app/src/main/res/navigation/show_details_nav_graph.xml @@ -39,7 +39,7 @@ - @@ -50,6 +50,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 0e3b6cb6a0..da16907623 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -16,15 +16,17 @@ --> + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml deleted file mode 100644 index 371bb56e20..0000000000 --- a/app/src/main/res/values/attrs.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/styles_typography.xml b/app/src/main/res/values/styles_typography.xml deleted file mode 100644 index e2aec23990..0000000000 --- a/app/src/main/res/values/styles_typography.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 6bcfdecc26..e4c01044a3 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -18,47 +18,27 @@ - + - - + + + + + + \ No newline at end of file diff --git a/common-ui-resources/src/main/res/color/color_on_background_10.xml b/common-ui-view/src/main/res/anim/tivi_fade_scale_exit.xml similarity index 55% rename from common-ui-resources/src/main/res/color/color_on_background_10.xml rename to common-ui-view/src/main/res/anim/tivi_fade_scale_exit.xml index 55b4eb760e..c498229e01 100644 --- a/common-ui-resources/src/main/res/color/color_on_background_10.xml +++ b/common-ui-view/src/main/res/anim/tivi_fade_scale_exit.xml @@ -1,6 +1,6 @@ - - - \ No newline at end of file + + + + + + \ No newline at end of file diff --git a/common-ui-view/src/main/res/values/ids.xml b/common-ui-view/src/main/res/values/ids.xml index 76deb11d0b..82afe3d836 100644 --- a/common-ui-view/src/main/res/values/ids.xml +++ b/common-ui-view/src/main/res/values/ids.xml @@ -25,7 +25,6 @@ - \ No newline at end of file diff --git a/ui-account/build.gradle b/ui-account/build.gradle index b891e9d531..c8ac749005 100644 --- a/ui-account/build.gradle +++ b/ui-account/build.gradle @@ -75,9 +75,6 @@ dependencies { implementation Libs.AndroidX.Compose.tooling implementation Libs.AndroidX.Compose.livedata - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-account/src/main/java/app/tivi/account/AccountUi.kt b/ui-account/src/main/java/app/tivi/account/AccountUi.kt index 99021c08b5..930fac14ff 100644 --- a/ui-account/src/main/java/app/tivi/account/AccountUi.kt +++ b/ui-account/src/main/java/app/tivi/account/AccountUi.kt @@ -17,7 +17,11 @@ package app.tivi.account import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayout +import androidx.compose.foundation.layout.FlowMainAxisAlignment +import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -26,6 +30,7 @@ import androidx.compose.foundation.layout.preferredHeight import androidx.compose.foundation.layout.preferredSize import androidx.compose.foundation.layout.preferredSizeIn import androidx.compose.foundation.layout.preferredWidth +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.AmbientContentAlpha import androidx.compose.material.ContentAlpha @@ -53,6 +58,7 @@ import dev.chrisbanes.accompanist.coil.CoilImage import org.threeten.bp.OffsetDateTime import org.threeten.bp.ZoneOffset +@OptIn(ExperimentalLayout::class) @Composable fun AccountUi( viewState: AccountUiViewState, @@ -70,20 +76,25 @@ fun AccountUi( Spacer(modifier = Modifier.preferredHeight(16.dp)) } - Row( - modifier = Modifier.align(Alignment.End) - .padding(horizontal = 16.dp) + Box( + modifier = Modifier.padding(horizontal = 16.dp) + .wrapContentSize(Alignment.CenterEnd) + .align(Alignment.End) ) { - if (viewState.authState == TraktAuthState.LOGGED_OUT) { - OutlinedButton(onClick = { actioner(Login) }) { - Text(text = stringResource(R.string.login)) + FlowRow( + mainAxisAlignment = FlowMainAxisAlignment.End, + mainAxisSpacing = 8.dp, + crossAxisSpacing = 4.dp, + ) { + if (viewState.authState == TraktAuthState.LOGGED_OUT) { + OutlinedButton(onClick = { actioner(Login) }) { + Text(text = stringResource(R.string.login)) + } + } else { + TextButton(onClick = { actioner(Login) }) { + Text(text = stringResource(R.string.refresh_credentials)) + } } - } else { - TextButton(onClick = { actioner(Login) }) { - Text(text = stringResource(R.string.refresh_credentials)) - } - - Spacer(modifier = Modifier.preferredWidth(8.dp)) OutlinedButton(onClick = { actioner(Logout) }) { Text(text = stringResource(R.string.logout)) diff --git a/ui-account/src/main/java/app/tivi/account/AccountUiFragment.kt b/ui-account/src/main/java/app/tivi/account/AccountUiFragment.kt index e4abd0daf0..db6f60deaa 100644 --- a/ui-account/src/main/java/app/tivi/account/AccountUiFragment.kt +++ b/ui-account/src/main/java/app/tivi/account/AccountUiFragment.kt @@ -26,14 +26,16 @@ import androidx.compose.runtime.Providers import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.platform.ComposeView +import androidx.fragment.app.DialogFragment 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.TiviContentSetup +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 com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint import dev.chrisbanes.accompanist.insets.AmbientWindowInsets import dev.chrisbanes.accompanist.insets.ViewWindowInsetObserver @@ -44,12 +46,14 @@ import kotlinx.coroutines.launch import javax.inject.Inject @AndroidEntryPoint -class AccountUiFragment : BottomSheetDialogFragment() { +class AccountUiFragment : DialogFragment() { private val pendingActions = Channel() private val viewModel: AccountUiViewModel by viewModels() @Inject internal lateinit var tiviDateFormatter: TiviDateFormatter + @Inject lateinit var preferences: TiviPreferences + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -66,7 +70,7 @@ class AccountUiFragment : BottomSheetDialogFragment() { AmbientTiviDateFormatter provides tiviDateFormatter, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { val viewState by viewModel.liveData.observeAsState() if (viewState != null) { AccountUi(viewState!!) { diff --git a/ui-discover/build.gradle b/ui-discover/build.gradle index 0374e6930d..1b2dc5a59a 100644 --- a/ui-discover/build.gradle +++ b/ui-discover/build.gradle @@ -61,7 +61,6 @@ dependencies { implementation Libs.AndroidX.Lifecycle.livedata implementation Libs.AndroidX.Lifecycle.viewmodel - implementation Libs.AndroidX.appcompat implementation Libs.AndroidX.coreKtx implementation Libs.AndroidX.Fragment.fragment implementation Libs.AndroidX.Fragment.fragmentKtx @@ -76,9 +75,6 @@ dependencies { implementation Libs.AndroidX.Compose.tooling implementation Libs.AndroidX.Compose.livedata - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-discover/src/main/java/app/tivi/home/discover/DiscoverFragment.kt b/ui-discover/src/main/java/app/tivi/home/discover/DiscoverFragment.kt index 9e2048cd7f..be8a851bc8 100644 --- a/ui-discover/src/main/java/app/tivi/home/discover/DiscoverFragment.kt +++ b/ui-discover/src/main/java/app/tivi/home/discover/DiscoverFragment.kt @@ -31,7 +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.TiviContentSetup +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 @@ -45,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() @@ -67,7 +71,7 @@ class DiscoverFragment : Fragment() { AmbientDiscoverTextCreator provides textCreator, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { val viewState by viewModel.liveData.observeAsState() if (viewState != null) { Discover( @@ -93,11 +97,29 @@ class DiscoverFragment : Fragment() { if (action.episodeId != null) { uri += "/episode/${action.episodeId}" } - findNavController().navigate(uri.toUri()) + findNavController().navigate(uri.toUri(), DefaultNavOptions) + } + OpenTrendingShows -> { + findNavController().navigate( + R.id.navigation_trending, + null, + DefaultNavOptions + ) + } + OpenPopularShows -> { + findNavController().navigate( + R.id.navigation_popular, + null, + DefaultNavOptions + ) + } + OpenRecommendedShows -> { + findNavController().navigate( + R.id.navigation_recommended, + null, + DefaultNavOptions + ) } - OpenTrendingShows -> findNavController().navigate(R.id.navigation_trending) - OpenPopularShows -> findNavController().navigate(R.id.navigation_popular) - OpenRecommendedShows -> findNavController().navigate(R.id.navigation_recommended) else -> viewModel.submitAction(action) } } diff --git a/ui-episodedetails/build.gradle b/ui-episodedetails/build.gradle index a3e419ffdd..4330221d39 100644 --- a/ui-episodedetails/build.gradle +++ b/ui-episodedetails/build.gradle @@ -72,6 +72,7 @@ dependencies { implementation Libs.AndroidX.Fragment.fragment implementation Libs.AndroidX.Fragment.fragmentKtx + implementation Libs.AndroidX.Navigation.fragment implementation Libs.AndroidX.Compose.runtime implementation Libs.AndroidX.Compose.foundation @@ -82,9 +83,6 @@ dependencies { implementation Libs.AndroidX.Compose.tooling implementation Libs.AndroidX.Compose.livedata - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetails.kt b/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetails.kt index 889cd2989c..5bd69d881e 100644 --- a/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetails.kt +++ b/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetails.kt @@ -99,6 +99,7 @@ import app.tivi.ui.animations.lerp import dev.chrisbanes.accompanist.coil.CoilImage import dev.chrisbanes.accompanist.insets.navigationBarsHeight import dev.chrisbanes.accompanist.insets.navigationBarsPadding +import dev.chrisbanes.accompanist.insets.statusBarsPadding import kotlinx.coroutines.launch import org.threeten.bp.OffsetDateTime import kotlin.math.absoluteValue @@ -124,7 +125,8 @@ fun EpisodeDetails( backgroundColor = Color.Transparent, isRefreshing = viewState.refreshing, actioner = actioner, - elevation = 0.dp + elevation = 0.dp, + modifier = Modifier.fillMaxWidth().statusBarsPadding() ) } ScrollableColumn { diff --git a/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetailsFragment.kt b/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetailsFragment.kt index 024e728217..7fb0dcd863 100644 --- a/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetailsFragment.kt +++ b/ui-episodedetails/src/main/java/app/tivi/episodedetails/EpisodeDetailsFragment.kt @@ -26,13 +26,16 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.platform.ComposeView import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment 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.TiviContentSetup +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 com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint import dev.chrisbanes.accompanist.insets.AmbientWindowInsets import dev.chrisbanes.accompanist.insets.ViewWindowInsetObserver @@ -43,8 +46,9 @@ import kotlinx.coroutines.launch import javax.inject.Inject @AndroidEntryPoint -class EpisodeDetailsFragment : BottomSheetDialogFragment() { +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" @@ -84,7 +88,7 @@ class EpisodeDetailsFragment : BottomSheetDialogFragment() { AmbientTiviDateFormatter provides tiviDateFormatter, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { val viewState by viewModel.liveData.observeAsState() if (viewState != null) { EpisodeDetails(viewState!!) { @@ -98,12 +102,11 @@ class EpisodeDetailsFragment : BottomSheetDialogFragment() { override fun onStart() { super.onStart() - (requireDialog().findViewById(R.id.container) as View).fitsSystemWindows = false lifecycleScope.launch { pendingActions.consumeAsFlow().collect { action -> when (action) { - is Close -> requireView().post { dismiss() } + is Close -> requireView().post { findNavController().navigateUp() } else -> viewModel.submitAction(action) } } diff --git a/ui-followed/build.gradle b/ui-followed/build.gradle index 8ecb48a8ba..e5d9cf30af 100644 --- a/ui-followed/build.gradle +++ b/ui-followed/build.gradle @@ -65,7 +65,6 @@ dependencies { implementation Libs.AndroidX.Paging.runtime implementation Libs.AndroidX.Paging.compose - implementation Libs.AndroidX.appcompat implementation Libs.AndroidX.coreKtx implementation Libs.AndroidX.Fragment.fragment implementation Libs.AndroidX.Fragment.fragmentKtx @@ -80,9 +79,6 @@ dependencies { implementation Libs.AndroidX.Compose.tooling implementation Libs.AndroidX.Compose.livedata - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-followed/src/main/java/app/tivi/home/followed/FollowedFragment.kt b/ui-followed/src/main/java/app/tivi/home/followed/FollowedFragment.kt index f686ed7b50..9c5e053642 100644 --- a/ui-followed/src/main/java/app/tivi/home/followed/FollowedFragment.kt +++ b/ui-followed/src/main/java/app/tivi/home/followed/FollowedFragment.kt @@ -33,8 +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.TiviContentSetup +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 @@ -48,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() @@ -70,7 +74,7 @@ class FollowedFragment : Fragment() { AmbientHomeTextCreator provides homeTextCreator, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { val viewState by viewModel.liveData.observeAsState() if (viewState != null) { Followed( @@ -91,9 +95,14 @@ class FollowedFragment : Fragment() { pendingActions.consumeAsFlow().collect { action -> when (action) { FollowedAction.LoginAction, - FollowedAction.OpenUserDetails -> findNavController().navigate("app.tivi://account".toUri()) + FollowedAction.OpenUserDetails -> { + findNavController().navigate("app.tivi://account".toUri()) + } is FollowedAction.OpenShowDetails -> { - findNavController().navigate("app.tivi://show/${action.showId}".toUri()) + findNavController().navigate( + "app.tivi://show/${action.showId}".toUri(), + DefaultNavOptions + ) } else -> viewModel.submitAction(action) } diff --git a/ui-popular/build.gradle b/ui-popular/build.gradle index 18740b782b..6fcf434821 100644 --- a/ui-popular/build.gradle +++ b/ui-popular/build.gradle @@ -74,9 +74,6 @@ dependencies { implementation Libs.AndroidX.Compose.animation implementation Libs.AndroidX.Compose.tooling - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-popular/src/main/java/app/tivi/home/popular/PopularShowsFragment.kt b/ui-popular/src/main/java/app/tivi/home/popular/PopularShowsFragment.kt index e5549a8c80..1b45cc3a4f 100644 --- a/ui-popular/src/main/java/app/tivi/home/popular/PopularShowsFragment.kt +++ b/ui-popular/src/main/java/app/tivi/home/popular/PopularShowsFragment.kt @@ -30,9 +30,12 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import app.tivi.common.compose.AmbientHomeTextCreator import app.tivi.common.compose.AmbientTiviDateFormatter -import app.tivi.common.compose.TiviContentSetup 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 @@ -46,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(Channel.BUFFERED) @@ -72,7 +76,7 @@ class PopularShowsFragment : Fragment() { AmbientHomeTextCreator provides homeTextCreator, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { Popular( lazyPagingItems = pagedList.collectAsLazyPagingItems { old, new -> old.entry.id == new.entry.id @@ -91,7 +95,10 @@ class PopularShowsFragment : Fragment() { pendingActions.consumeAsFlow().collect { action -> when (action) { is PopularAction.OpenShowDetails -> { - findNavController().navigate("app.tivi://show/${action.showId}".toUri()) + findNavController().navigate( + "app.tivi://show/${action.showId}".toUri(), + DefaultNavOptions + ) } // else -> viewModel.submitAction(action) } diff --git a/ui-recommended/build.gradle b/ui-recommended/build.gradle index 18740b782b..6fcf434821 100644 --- a/ui-recommended/build.gradle +++ b/ui-recommended/build.gradle @@ -74,9 +74,6 @@ dependencies { implementation Libs.AndroidX.Compose.animation implementation Libs.AndroidX.Compose.tooling - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-recommended/src/main/java/app/tivi/home/recommended/RecommendedShowsFragment.kt b/ui-recommended/src/main/java/app/tivi/home/recommended/RecommendedShowsFragment.kt index 222f1925be..4994dc1935 100644 --- a/ui-recommended/src/main/java/app/tivi/home/recommended/RecommendedShowsFragment.kt +++ b/ui-recommended/src/main/java/app/tivi/home/recommended/RecommendedShowsFragment.kt @@ -30,9 +30,12 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import app.tivi.common.compose.AmbientHomeTextCreator import app.tivi.common.compose.AmbientTiviDateFormatter -import app.tivi.common.compose.TiviContentSetup 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 @@ -46,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(Channel.BUFFERED) @@ -72,7 +76,7 @@ class RecommendedShowsFragment : Fragment() { AmbientHomeTextCreator provides homeTextCreator, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { Recommended( lazyPagingItems = pagedList.collectAsLazyPagingItems { old, new -> old.entry.id == new.entry.id @@ -91,7 +95,10 @@ class RecommendedShowsFragment : Fragment() { pendingActions.consumeAsFlow().collect { action -> when (action) { is RecommendedAction.OpenShowDetails -> { - findNavController().navigate("app.tivi://show/${action.showId}".toUri()) + findNavController().navigate( + "app.tivi://show/${action.showId}".toUri(), + DefaultNavOptions + ) } // else -> viewModel.submitAction(action) } diff --git a/ui-search/build.gradle b/ui-search/build.gradle index 3672edce51..a4f6358936 100644 --- a/ui-search/build.gradle +++ b/ui-search/build.gradle @@ -62,7 +62,6 @@ dependencies { implementation Libs.AndroidX.Lifecycle.livedata implementation Libs.AndroidX.Lifecycle.viewmodel - implementation Libs.AndroidX.appcompat implementation Libs.AndroidX.coreKtx implementation Libs.AndroidX.Fragment.fragment implementation Libs.AndroidX.Navigation.fragment @@ -76,9 +75,6 @@ dependencies { implementation Libs.AndroidX.Compose.tooling implementation Libs.AndroidX.Compose.livedata - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-search/src/main/java/app/tivi/home/search/SearchFragment.kt b/ui-search/src/main/java/app/tivi/home/search/SearchFragment.kt index c817733d39..579241c17f 100644 --- a/ui-search/src/main/java/app/tivi/home/search/SearchFragment.kt +++ b/ui-search/src/main/java/app/tivi/home/search/SearchFragment.kt @@ -31,14 +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.TiviContentSetup +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(Channel.BUFFERED) @@ -49,7 +55,10 @@ internal class SearchFragment : Fragment() { for (action in pendingActions) { when (action) { is SearchAction.OpenShowDetails -> { - findNavController().navigate("app.tivi://show/${action.showId}".toUri()) + findNavController().navigate( + "app.tivi://show/${action.showId}".toUri(), + DefaultNavOptions + ) } else -> viewModel.submitAction(action) } @@ -70,7 +79,7 @@ internal class SearchFragment : Fragment() { setContent { Providers(AmbientWindowInsets provides windowInsets) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { val viewState by viewModel.liveData.observeAsState() if (viewState != null) { LogCompositions("ViewState observeAsState") diff --git a/ui-settings/build.gradle b/ui-settings/build.gradle index 7754618751..7bc8a43e39 100644 --- a/ui-settings/build.gradle +++ b/ui-settings/build.gradle @@ -40,29 +40,17 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } - - buildFeatures { - viewBinding true - } } dependencies { implementation project(':base') implementation project(':base-android') - implementation project(':domain') implementation project(':common-ui-resources') implementation project(':common-ui-view') - implementation Libs.AndroidX.appcompat implementation Libs.AndroidX.browser implementation Libs.AndroidX.coreKtx - api Libs.AndroidX.preference - - implementation Libs.AndroidX.Navigation.fragment - implementation Libs.AndroidX.Fragment.fragment - implementation Libs.AndroidX.Fragment.fragmentKtx - - implementation Libs.Mdc.material + implementation Libs.AndroidX.Lifecycle.runtime implementation Libs.Hilt.library kapt Libs.Hilt.compiler diff --git a/ui-settings/src/main/AndroidManifest.xml b/ui-settings/src/main/AndroidManifest.xml index 8c61f96909..ea07ccceac 100644 --- a/ui-settings/src/main/AndroidManifest.xml +++ b/ui-settings/src/main/AndroidManifest.xml @@ -19,4 +19,11 @@ + + + + + + diff --git a/ui-settings/src/main/java/app/tivi/settings/SettingsActivity.kt b/ui-settings/src/main/java/app/tivi/settings/SettingsActivity.kt new file mode 100644 index 0000000000..8181127420 --- /dev/null +++ b/ui-settings/src/main/java/app/tivi/settings/SettingsActivity.kt @@ -0,0 +1,48 @@ +/* + * 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. + */ + +@file:Suppress("DEPRECATION") + +package app.tivi.settings + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.lifecycle.lifecycleScope +import app.tivi.util.PowerController +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.collect +import javax.inject.Inject + +@AndroidEntryPoint +class SettingsActivity : ComponentActivity() { + @Inject lateinit var powerController: PowerController + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val fragment = SettingsPreferenceFragment() + + fragmentManager.beginTransaction() + .replace(android.R.id.content, fragment) + .commit() + + lifecycleScope.launchWhenStarted { + powerController.observeShouldSaveData(ignorePreference = true).collect { saveData -> + fragment.saveData = saveData + } + } + } +} diff --git a/ui-settings/src/main/java/app/tivi/settings/SettingsFragment.kt b/ui-settings/src/main/java/app/tivi/settings/SettingsFragment.kt deleted file mode 100644 index 619a477048..0000000000 --- a/ui-settings/src/main/java/app/tivi/settings/SettingsFragment.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 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.settings - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.fragment.app.commitNow -import androidx.navigation.fragment.findNavController -import app.tivi.settings.databinding.FragmentSettingsBinding - -class SettingsFragment : Fragment() { - private lateinit var binding: FragmentSettingsBinding - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentSettingsBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - binding.settingsToolbar.setNavigationOnClickListener { - findNavController().navigateUp() - } - - childFragmentManager.commitNow { - replace(R.id.settings_container, SettingsPreferenceFragment()) - } - } -} diff --git a/ui-settings/src/main/java/app/tivi/settings/SettingsInject.kt b/ui-settings/src/main/java/app/tivi/settings/SettingsInject.kt index daa1eaff06..ca677f9ee3 100644 --- a/ui-settings/src/main/java/app/tivi/settings/SettingsInject.kt +++ b/ui-settings/src/main/java/app/tivi/settings/SettingsInject.kt @@ -14,11 +14,13 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package app.tivi.settings import android.content.Context import android.content.SharedPreferences -import androidx.preference.PreferenceManager +import android.preference.PreferenceManager import dagger.Binds import dagger.Module import dagger.Provides diff --git a/ui-settings/src/main/java/app/tivi/settings/SettingsPreferenceFragment.kt b/ui-settings/src/main/java/app/tivi/settings/SettingsPreferenceFragment.kt index 78f01b6759..fca3e6cdbd 100644 --- a/ui-settings/src/main/java/app/tivi/settings/SettingsPreferenceFragment.kt +++ b/ui-settings/src/main/java/app/tivi/settings/SettingsPreferenceFragment.kt @@ -14,66 +14,59 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package app.tivi.settings import android.content.pm.PackageManager import android.os.Bundle +import android.preference.PreferenceFragment +import android.preference.SwitchPreference import androidx.browser.customtabs.CustomTabsIntent import androidx.core.content.pm.PackageInfoCompat import androidx.core.net.toUri -import androidx.lifecycle.lifecycleScope -import androidx.navigation.fragment.findNavController -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat import app.tivi.extensions.resolveThemeColor -import app.tivi.util.PowerController import app.tivi.util.SaveData import app.tivi.util.SaveDataReason -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.flow.collect -import javax.inject.Inject - -@AndroidEntryPoint -internal class SettingsPreferenceFragment : PreferenceFragmentCompat() { - @Inject lateinit var powerController: PowerController - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) +internal class SettingsPreferenceFragment : PreferenceFragment() { + internal var saveData: SaveData? = null + set(value) { + val pref = findPreference("pref_data_saver") as? SwitchPreference + ?: throw IllegalStateException() - lifecycleScope.launchWhenStarted { - powerController.observeShouldSaveData(ignorePreference = true).collect { saveData -> - val pref = findPreference("pref_data_saver") - ?: throw CancellationException() - val prefDisabled = findPreference("pref_data_saver_disabled") - ?: throw CancellationException() + pref.isEnabled = when (value) { + is SaveData.Enabled -> value.reason == SaveDataReason.PREFERENCE + else -> true + } - pref.isVisible = saveData is SaveData.Disabled || - (saveData is SaveData.Enabled && saveData.reason == SaveDataReason.PREFERENCE) - prefDisabled.isVisible = !pref.isVisible + if (pref.isEnabled) { + pref.summary = null + pref.setSummaryOn(R.string.settings_data_saver_summary_on) + } else { + pref.summaryOn = null + pref.setSummary(R.string.settings_data_saver_summary_system) } + + field = value } - } - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.preferences, rootKey) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.preferences) - findPreference("privacy_policy")?.setOnPreferenceClickListener { + findPreference("privacy_policy")?.setOnPreferenceClickListener { CustomTabsIntent.Builder() - .setToolbarColor(requireContext().resolveThemeColor(R.attr.colorPrimaryVariant)) + .setToolbarColor(context.resolveThemeColor(android.R.attr.colorPrimary)) .build() - .launchUrl(requireContext(), getString(R.string.privacy_policy_url).toUri()) - true - } - - findPreference("open_source")?.setOnPreferenceClickListener { - findNavController().navigate(R.id.navigation_licences) + .launchUrl(context, getString(R.string.privacy_policy_url).toUri()) true } - findPreference("version")?.apply { - val pkgManager: PackageManager = requireContext().packageManager - val pkgInfo = pkgManager.getPackageInfo(requireContext().packageName, 0) + findPreference("version")?.apply { + val pkgManager: PackageManager = context.packageManager + val pkgInfo = pkgManager.getPackageInfo(context.packageName, 0) summary = getString( R.string.settings_app_version_summary, pkgInfo.versionName, diff --git a/ui-settings/src/main/java/app/tivi/settings/TiviPreferencesImpl.kt b/ui-settings/src/main/java/app/tivi/settings/TiviPreferencesImpl.kt index 111dd62b8c..2b8775d1ff 100644 --- a/ui-settings/src/main/java/app/tivi/settings/TiviPreferencesImpl.kt +++ b/ui-settings/src/main/java/app/tivi/settings/TiviPreferencesImpl.kt @@ -18,10 +18,15 @@ package app.tivi.settings import android.content.Context import android.content.SharedPreferences -import androidx.appcompat.app.AppCompatDelegate 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 @@ -29,25 +34,24 @@ 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(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) @@ -59,7 +63,25 @@ class TiviPreferencesImpl @Inject constructor( putBoolean(KEY_DATA_SAVER, value) } - val Theme.storageKey: String + override fun observeUseLessData(): Flow { + 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 { + 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) Theme.DARK -> context.getString(R.string.pref_theme_dark_value) @@ -71,10 +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) - } } diff --git a/ui-settings/src/main/res/layout/fragment_settings.xml b/ui-settings/src/main/res/layout/fragment_settings.xml deleted file mode 100644 index 7faf1e0e79..0000000000 --- a/ui-settings/src/main/res/layout/fragment_settings.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - diff --git a/ui-settings/src/main/res/xml/preferences.xml b/ui-settings/src/main/res/xml/preferences.xml index bbac31a23b..76cd675e7d 100644 --- a/ui-settings/src/main/res/xml/preferences.xml +++ b/ui-settings/src/main/res/xml/preferences.xml @@ -16,8 +16,7 @@ ~ --> - + @@ -26,22 +25,14 @@ android:entries="@array/prefs_theme_titles" android:entryValues="@array/prefs_theme_values" android:key="pref_theme" - android:title="@string/settings_theme_title" - app:useSimpleSummaryProvider="true" /> + android:title="@string/settings_theme_title" /> - - - - - diff --git a/ui-showdetails/build.gradle b/ui-showdetails/build.gradle index 30d329865e..d4f304411d 100644 --- a/ui-showdetails/build.gradle +++ b/ui-showdetails/build.gradle @@ -69,7 +69,6 @@ dependencies { implementation Libs.AndroidX.Lifecycle.livedata implementation Libs.AndroidX.Lifecycle.viewmodel - implementation Libs.AndroidX.appcompat implementation Libs.AndroidX.coreKtx implementation Libs.AndroidX.emoji implementation Libs.AndroidX.Fragment.fragment @@ -87,9 +86,6 @@ dependencies { implementation Libs.AndroidX.Compose.tooling implementation Libs.AndroidX.Compose.livedata - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsAction.kt b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsAction.kt index 8fb65d2b16..bd178b511b 100644 --- a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsAction.kt +++ b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsAction.kt @@ -43,6 +43,5 @@ data class ChangeSeasonExpandedAction( data class OpenShowDetails(val showId: Long) : ShowDetailsAction() data class OpenEpisodeDetails(val episodeId: Long) : ShowDetailsAction() -data class ClearPendingUiEffect(val effect: UiEffect) : ShowDetailsAction() object ClearError : ShowDetailsAction() object NavigateUp : ShowDetailsAction() diff --git a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsFragment.kt b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsFragment.kt index de179bd9c2..94aef0b74e 100644 --- a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsFragment.kt +++ b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsFragment.kt @@ -30,9 +30,13 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController +import androidx.navigation.navOptions import app.tivi.common.compose.LogCompositions -import app.tivi.common.compose.TiviContentSetup +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 @@ -40,7 +44,6 @@ import dev.chrisbanes.accompanist.insets.ViewWindowInsetObserver import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.consumeAsFlow -import kotlinx.coroutines.launch import javax.inject.Inject @AndroidEntryPoint @@ -48,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(Channel.BUFFERED) @@ -64,11 +68,51 @@ class ShowDetailsFragment : Fragment() { } } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + lifecycleScope.launchWhenStarted { + pendingActions.consumeAsFlow().collect { action -> + when (action) { + NavigateUp -> findNavController().navigateUp() + else -> viewModel.submitAction(action) + } + } + } + + lifecycleScope.launchWhenStarted { + viewModel.uiEffects.collect { effect -> + when (effect) { + is OpenShowUiEffect -> { + findNavController().navigate( + "app.tivi://show/${effect.showId}".toUri(), + DefaultNavOptions + ) + } + is OpenEpisodeUiEffect -> { + findNavController().navigate( + "app.tivi://episode/${effect.episodeId}".toUri(), + navOptions { + anim { + enter = R.anim.tivi_enter_bottom_anim + popExit = R.anim.tivi_exit_bottom_anim + } + } + ) + } + else -> { + // TODO: any remaining ui effects need to be passed down to the UI + } + } + } + } + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? = ComposeView(requireContext()).apply { + ): View = ComposeView(requireContext()).apply { layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) // We use ViewWindowInsetObserver rather than ProvideWindowInsets @@ -80,7 +124,7 @@ class ShowDetailsFragment : Fragment() { AmbientShowDetailsTextCreator provides textCreator, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { val viewState by viewModel.liveData.observeAsState() if (viewState != null) { LogCompositions("ViewState observeAsState") @@ -92,34 +136,4 @@ class ShowDetailsFragment : Fragment() { } } } - - override fun onStart() { - super.onStart() - - viewModel.liveData.observe(this, ::render) - - lifecycleScope.launch { - pendingActions.consumeAsFlow().collect { action -> - when (action) { - NavigateUp -> findNavController().navigateUp() - else -> viewModel.submitAction(action) - } - } - } - } - - private fun render(state: ShowDetailsViewState) { - state.pendingUiEffects.forEach { effect -> - when (effect) { - is OpenShowUiEffect -> { - findNavController().navigate("app.tivi://show/${effect.showId}".toUri()) - viewModel.submitAction(ClearPendingUiEffect(effect)) - } - is OpenEpisodeUiEffect -> { - findNavController().navigate("app.tivi://episode/${effect.episodeId}".toUri()) - viewModel.submitAction(ClearPendingUiEffect(effect)) - } - } - } - } } diff --git a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsFragmentViewModel.kt b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsViewModel.kt similarity index 88% rename from ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsFragmentViewModel.kt rename to ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsViewModel.kt index 34081d0799..0f9944f176 100644 --- a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsFragmentViewModel.kt +++ b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsViewModel.kt @@ -48,6 +48,8 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.flow.distinctUntilChanged @@ -78,6 +80,11 @@ internal class ShowDetailsFragmentViewModel @AssistedInject constructor( private val pendingActions = Channel(Channel.BUFFERED) + private val _uiEffects = MutableSharedFlow(extraBufferCapacity = 100) + + val uiEffects: Flow + get() = _uiEffects.asSharedFlow() + init { viewModelScope.launch { observeShowFollowStatus.observe() @@ -138,7 +145,6 @@ internal class ShowDetailsFragmentViewModel @AssistedInject constructor( is UnfollowPreviousSeasonsFollowedAction -> onUnfollowPreviousSeasonsFollowState(action) is OpenEpisodeDetails -> openEpisodeDetails(action) is OpenShowDetails -> openShowDetails(action) - is ClearPendingUiEffect -> clearPendingUiEffect(action) is ClearError -> snackbarManager.removeCurrentError() } } @@ -201,35 +207,27 @@ internal class ShowDetailsFragmentViewModel @AssistedInject constructor( } private fun openShowDetails(action: OpenShowDetails) { - viewModelScope.launchSetState { - val pending = pendingUiEffects.filter { it !is OpenShowUiEffect } - copy(pendingUiEffects = pending + OpenShowUiEffect(action.showId)) + viewModelScope.launch { + _uiEffects.emit(OpenShowUiEffect(action.showId)) } } private fun openEpisodeDetails(action: OpenEpisodeDetails) = viewModelScope.launch { val episode = getEpisode(GetEpisodeDetails.Params(action.episodeId)).first() if (episode != null) { + // Make sure the season is expanded setState { - val pending = pendingUiEffects.filterNot { it is OpenEpisodeUiEffect } - copy( - expandedSeasonIds = expandedSeasonIds + episode.seasonId, - pendingUiEffects = pending + - OpenEpisodeUiEffect(action.episodeId, episode.seasonId) - ) + copy(expandedSeasonIds = expandedSeasonIds + episode.seasonId) } - } - } - - private fun clearPendingUiEffect(action: ClearPendingUiEffect) { - viewModelScope.launchSetState { - copy(pendingUiEffects = pendingUiEffects - action.effect) + // And emit an open episode ui effect + _uiEffects.emit(OpenEpisodeUiEffect(action.episodeId, episode.seasonId)) } } private fun onMarkSeasonWatched(action: MarkSeasonWatchedAction) { - changeSeasonWatchedStatus(Params(action.seasonId, Action.WATCHED, action.onlyAired, action.date)) - .watchStatus() + changeSeasonWatchedStatus( + Params(action.seasonId, Action.WATCHED, action.onlyAired, action.date) + ).watchStatus() } private fun onMarkSeasonUnwatched(action: MarkSeasonUnwatchedAction) { @@ -237,17 +235,16 @@ internal class ShowDetailsFragmentViewModel @AssistedInject constructor( } private fun onChangeSeasonExpandState(seasonId: Long, expanded: Boolean) { - viewModelScope.launchSetState { - val pending = ArrayList(pendingUiEffects) - pending.removeAll { it is FocusSeasonUiEffect } - + viewModelScope.launch { + setState { + when { + expanded -> copy(expandedSeasonIds = expandedSeasonIds + seasonId) + else -> copy(expandedSeasonIds = expandedSeasonIds - seasonId) + } + } if (expanded) { - copy( - pendingUiEffects = pending + FocusSeasonUiEffect(seasonId), - expandedSeasonIds = expandedSeasonIds + seasonId - ) - } else { - copy(expandedSeasonIds = expandedSeasonIds - seasonId) + // If we've expanded, focus the season + _uiEffects.emit(FocusSeasonUiEffect(seasonId)) } } } diff --git a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsViewState.kt b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsViewState.kt index 57d3cdea2e..f0179da2d2 100644 --- a/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsViewState.kt +++ b/ui-showdetails/src/main/java/app/tivi/showdetails/details/ShowDetailsViewState.kt @@ -37,7 +37,6 @@ data class ShowDetailsViewState( val watchStats: FollowedShowsWatchStats? = null, val seasons: List = emptyList(), val expandedSeasonIds: Set = emptySet(), - val pendingUiEffects: List = emptyList(), // TODO this should really be a queue val refreshing: Boolean = false, val refreshError: UiError? = null ) diff --git a/ui-trending/build.gradle b/ui-trending/build.gradle index 18740b782b..6fcf434821 100644 --- a/ui-trending/build.gradle +++ b/ui-trending/build.gradle @@ -74,9 +74,6 @@ dependencies { implementation Libs.AndroidX.Compose.animation implementation Libs.AndroidX.Compose.tooling - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-trending/src/main/java/app/tivi/home/trending/TrendingShowsFragment.kt b/ui-trending/src/main/java/app/tivi/home/trending/TrendingShowsFragment.kt index cd1a9ac8fa..526a2ce8b4 100644 --- a/ui-trending/src/main/java/app/tivi/home/trending/TrendingShowsFragment.kt +++ b/ui-trending/src/main/java/app/tivi/home/trending/TrendingShowsFragment.kt @@ -30,9 +30,12 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import app.tivi.common.compose.AmbientHomeTextCreator import app.tivi.common.compose.AmbientTiviDateFormatter -import app.tivi.common.compose.TiviContentSetup 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 @@ -46,6 +49,7 @@ import javax.inject.Inject class TrendingShowsFragment : Fragment() { @Inject internal lateinit var tiviDateFormatter: TiviDateFormatter @Inject internal lateinit var homeTextCreator: HomeTextCreator + @Inject lateinit var preferences: TiviPreferences private val pendingActions = Channel(Channel.BUFFERED) @@ -72,7 +76,7 @@ class TrendingShowsFragment : Fragment() { AmbientHomeTextCreator provides homeTextCreator, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { Trending( lazyPagingItems = pagedList.collectAsLazyPagingItems { old, new -> old.entry.id == new.entry.id @@ -91,7 +95,10 @@ class TrendingShowsFragment : Fragment() { pendingActions.consumeAsFlow().collect { action -> when (action) { is TrendingAction.OpenShowDetails -> { - findNavController().navigate("app.tivi://show/${action.showId}".toUri()) + findNavController().navigate( + "app.tivi://show/${action.showId}".toUri(), + DefaultNavOptions + ) } // else -> viewModel.submitAction(action) } diff --git a/ui-watched/build.gradle b/ui-watched/build.gradle index 8ecb48a8ba..e5d9cf30af 100644 --- a/ui-watched/build.gradle +++ b/ui-watched/build.gradle @@ -65,7 +65,6 @@ dependencies { implementation Libs.AndroidX.Paging.runtime implementation Libs.AndroidX.Paging.compose - implementation Libs.AndroidX.appcompat implementation Libs.AndroidX.coreKtx implementation Libs.AndroidX.Fragment.fragment implementation Libs.AndroidX.Fragment.fragmentKtx @@ -80,9 +79,6 @@ dependencies { implementation Libs.AndroidX.Compose.tooling implementation Libs.AndroidX.Compose.livedata - implementation Libs.Mdc.material - implementation Libs.Mdc.composeThemeAdapter - implementation Libs.Accompanist.coil implementation Libs.Accompanist.insets diff --git a/ui-watched/src/main/java/app/tivi/home/watched/WatchedFragment.kt b/ui-watched/src/main/java/app/tivi/home/watched/WatchedFragment.kt index 206a78c2fc..fb05594d46 100644 --- a/ui-watched/src/main/java/app/tivi/home/watched/WatchedFragment.kt +++ b/ui-watched/src/main/java/app/tivi/home/watched/WatchedFragment.kt @@ -33,8 +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.TiviContentSetup +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 @@ -48,6 +51,7 @@ import javax.inject.Inject class WatchedFragment : Fragment() { @Inject internal lateinit var tiviDateFormatter: TiviDateFormatter @Inject internal lateinit var homeTextCreator: HomeTextCreator + @Inject lateinit var preferences: TiviPreferences private val viewModel: WatchedViewModel by viewModels() @@ -57,7 +61,7 @@ class WatchedFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? = ComposeView(requireContext()).apply { + ): View = ComposeView(requireContext()).apply { layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) // We use ViewWindowInsetObserver rather than ProvideWindowInsets @@ -70,7 +74,7 @@ class WatchedFragment : Fragment() { AmbientHomeTextCreator provides homeTextCreator, AmbientWindowInsets provides windowInsets, ) { - TiviContentSetup { + TiviTheme(useDarkColors = preferences.shouldUseDarkColors()) { val viewState by viewModel.liveData.observeAsState() if (viewState != null) { Watched( @@ -95,7 +99,10 @@ class WatchedFragment : Fragment() { findNavController().navigate("app.tivi://account".toUri()) } is WatchedAction.OpenShowDetails -> { - findNavController().navigate("app.tivi://show/${action.showId}".toUri()) + findNavController().navigate( + "app.tivi://show/${action.showId}".toUri(), + DefaultNavOptions + ) } else -> viewModel.submitAction(action) }