add option for floating bottom bar design

This commit is contained in:
Owen LeJeune
2023-07-25 20:46:17 -04:00
parent 3df94cbd70
commit 8abd40a0c2
13 changed files with 188 additions and 29 deletions

View File

@@ -1,6 +1,7 @@
package com.owenlejeune.tvtime package com.owenlejeune.tvtime
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@@ -12,17 +13,23 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.kieronquinn.monetcompat.app.MonetCompatActivity import com.kieronquinn.monetcompat.app.MonetCompatActivity
import com.owenlejeune.tvtime.extensions.copy
import com.owenlejeune.tvtime.extensions.rememberWindowSizeClass import com.owenlejeune.tvtime.extensions.rememberWindowSizeClass
import com.owenlejeune.tvtime.ui.navigation.AppNavigationHost import com.owenlejeune.tvtime.ui.navigation.AppNavigationHost
import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavItem import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavItem
@@ -50,6 +57,9 @@ class MainActivity : MonetCompatActivity() {
lifecycleScope.launch { lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { lifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
monet.awaitMonetReady() monet.awaitMonetReady()
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent { setContent {
AppKeyboardFocusManager() AppKeyboardFocusManager()
TVTimeTheme(monetCompat = monet) { TVTimeTheme(monetCompat = monet) {
@@ -83,10 +93,10 @@ class MainActivity : MonetCompatActivity() {
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) } snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
) { ) { innerPadding ->
val windowSize = rememberWindowSizeClass() val windowSize = rememberWindowSizeClass()
val appNavController = rememberNavController() val appNavController = rememberNavController()
Box(modifier = Modifier.padding(it)) { Box(modifier = Modifier.padding(innerPadding.copy(bottom = 0.dp))) {
AppNavigationHost( AppNavigationHost(
appNavController = appNavController, appNavController = appNavController,
mainNavStartRoute = mainNavStartRoute, mainNavStartRoute = mainNavStartRoute,

View File

@@ -1,13 +1,19 @@
package com.owenlejeune.tvtime.extensions package com.owenlejeune.tvtime.extensions
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyGridItemScope import androidx.compose.foundation.lazy.grid.LazyGridItemScope
import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyGridScope
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.LazyPagingItems
fun <T: Any> LazyGridScope.lazyPagingItems( fun <T: Any> LazyGridScope.lazyPagingItems(
@@ -55,3 +61,13 @@ fun <T: Any> LazyListScope.lazyPagingItems(
fun Color.unlessDarkMode(other: Color): Color { fun Color.unlessDarkMode(other: Color): Color {
return if (isSystemInDarkTheme()) this else other return if (isSystemInDarkTheme()) this else other
} }
@Composable
fun ColorScheme.defaultNavBarColor(): Color = primary.copy(alpha = 0.08f).compositeOver(background = surface)
fun PaddingValues.copy(
start: Dp = this.calculateLeftPadding(LayoutDirection.Ltr),
end: Dp = this.calculateRightPadding(LayoutDirection.Ltr),
top: Dp = this.calculateTopPadding(),
bottom: Dp = this.calculateBottomPadding()
) = PaddingValues(start = start, end = end, top = top, bottom = bottom)

View File

@@ -36,6 +36,7 @@ class AppPreferences(context: Context) {
private val SHOW_POSTER_TITLE = "show_poster_titles" private val SHOW_POSTER_TITLE = "show_poster_titles"
private val SHOW_NEXT_MCU = "show_next_mcu" private val SHOW_NEXT_MCU = "show_next_mcu"
private val STORED_TEST_ROUTE = "stored_test_route" private val STORED_TEST_ROUTE = "stored_test_route"
private val FLOATING_BOTTOM_BAR = "floating_bottom_bar"
} }
private val preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE) private val preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE)
@@ -105,7 +106,7 @@ class AppPreferences(context: Context) {
get() = preferences.getInt(ACCOUNT_TAB_POSITION, accountTabPositionDefault) get() = preferences.getInt(ACCOUNT_TAB_POSITION, accountTabPositionDefault)
set(value) { preferences.put(ACCOUNT_TAB_POSITION, value) } set(value) { preferences.put(ACCOUNT_TAB_POSITION, value) }
val showBottomTabLabelsDefault: Boolean = true val showBottomTabLabelsDefault: Boolean = false
var showBottomTabLabels: Boolean var showBottomTabLabels: Boolean
get() = preferences.getBoolean(SHOW_BTAB_LABELS, showBottomTabLabelsDefault) get() = preferences.getBoolean(SHOW_BTAB_LABELS, showBottomTabLabelsDefault)
set(value) { preferences.put(SHOW_BTAB_LABELS, value) } set(value) { preferences.put(SHOW_BTAB_LABELS, value) }
@@ -115,6 +116,11 @@ class AppPreferences(context: Context) {
get() = preferences.getBoolean(SHOW_POSTER_TITLE, showPosterTitlesDefault) get() = preferences.getBoolean(SHOW_POSTER_TITLE, showPosterTitlesDefault)
set(value) { preferences.put(SHOW_POSTER_TITLE, value) } set(value) { preferences.put(SHOW_POSTER_TITLE, value) }
val floatingBottomBarDefault: Boolean = false
var floatingBottomBar: Boolean
get() = preferences.getBoolean(FLOATING_BOTTOM_BAR, floatingBottomBarDefault)
set(value) { preferences.put(FLOATING_BOTTOM_BAR, value) }
/******** Dev Preferences ********/ /******** Dev Preferences ********/
val firstLaunchTestingDefault: Boolean = false val firstLaunchTestingDefault: Boolean = false
var firstLaunchTesting: Boolean var firstLaunchTesting: Boolean

View File

@@ -55,7 +55,6 @@ import kotlinx.coroutines.launch
private const val ALPHA = 0.7f private const val ALPHA = 0.7f
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ProfileMenuOverlay( fun ProfileMenuOverlay(
appNavController: NavController, appNavController: NavController,
@@ -73,7 +72,7 @@ fun ProfileMenuOverlay(
Card( Card(
modifier = Modifier modifier = Modifier
.align(Alignment.TopCenter) .align(Alignment.TopCenter)
.padding(vertical = 100.dp, horizontal = 12.dp) .padding(vertical = 100.dp, horizontal = 24.dp)
.fillMaxWidth() .fillMaxWidth()
.wrapContentHeight(), .wrapContentHeight(),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(

View File

@@ -73,6 +73,7 @@ import com.owenlejeune.tvtime.extensions.toDp
import com.owenlejeune.tvtime.extensions.unlessEmpty import com.owenlejeune.tvtime.extensions.unlessEmpty
import com.owenlejeune.tvtime.preferences.AppPreferences import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.navigation.AppNavItem import com.owenlejeune.tvtime.ui.navigation.AppNavItem
import com.owenlejeune.tvtime.ui.screens.HomeScreen
import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel
import com.owenlejeune.tvtime.utils.SessionManager import com.owenlejeune.tvtime.utils.SessionManager
import com.owenlejeune.tvtime.utils.TmdbUtils import com.owenlejeune.tvtime.utils.TmdbUtils
@@ -229,7 +230,8 @@ fun SearchView(
contentColor = MaterialTheme.colorScheme.tertiary, contentColor = MaterialTheme.colorScheme.tertiary,
onClick = { onClick = {
appNavController.navigate(route) appNavController.navigate(route)
} },
modifier = Modifier.offset(y = if (preferences.floatingBottomBar) -(HomeScreen.FLOATING_NAV_BAR_HEIGHT - HomeScreen.FLOATING_NAV_BAR_OFFSET) else 0.dp)
) { ) {
Icon(Icons.Filled.Search, stringResource(id = R.string.preference_heading_search)) Icon(Icons.Filled.Search, stringResource(id = R.string.preference_heading_search))
} }

View File

@@ -235,7 +235,7 @@ fun AppNavigationHost(
// Settings View // Settings View
composable(AppNavItem.SettingsView.route) { composable(AppNavItem.SettingsView.route) {
applicationViewModel.currentRoute.value = AppNavItem.SettingsView.route applicationViewModel.currentRoute.value = AppNavItem.SettingsView.route
SettingsScreen(appNavController = appNavController) SettingsScreen(appNavController = appNavController, windowSizeClass = windowSize)
} }
// Web Link View // Web Link View
composable( composable(

View File

@@ -1,5 +1,7 @@
package com.owenlejeune.tvtime.ui.navigation package com.owenlejeune.tvtime.ui.navigation
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -35,8 +37,8 @@ fun HomeScreenNavHost(
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = startDestination, startDestination = startDestination,
enterTransition = { fadeIn() }, enterTransition = { EnterTransition.None },
exitTransition = { fadeOut() } exitTransition = { ExitTransition.None }
) { ) {
composable(HomeScreenNavItem.Movies.route) { composable(HomeScreenNavItem.Movies.route) {
homeScreenViewModel.appBarActions.value = {} homeScreenViewModel.appBarActions.value = {}

View File

@@ -12,6 +12,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.extensions.WindowSizeClass
import com.owenlejeune.tvtime.ui.screens.DarkModePreferences import com.owenlejeune.tvtime.ui.screens.DarkModePreferences
import com.owenlejeune.tvtime.ui.screens.DesignPreferences import com.owenlejeune.tvtime.ui.screens.DesignPreferences
import com.owenlejeune.tvtime.ui.screens.DevPreferences import com.owenlejeune.tvtime.ui.screens.DevPreferences
@@ -23,6 +24,7 @@ import com.owenlejeune.tvtime.ui.screens.SpecialFeaturePreferences
@Composable @Composable
fun SettingsNavigationHost( fun SettingsNavigationHost(
appNavController: NavController, appNavController: NavController,
windowSizeClass: WindowSizeClass,
appBarTitle: MutableState<String>, appBarTitle: MutableState<String>,
popBackAction: MutableState<() -> Unit> popBackAction: MutableState<() -> Unit>
) { ) {
@@ -58,7 +60,7 @@ fun SettingsNavigationHost(
composable(SettingsNavItem.HomeScreen.route) { composable(SettingsNavItem.HomeScreen.route) {
appBarTitle.value = stringResource(id = R.string.preference_heading_home_screen) appBarTitle.value = stringResource(id = R.string.preference_heading_home_screen)
popBackAction.value = { settingsNavController.popBackStack() } popBackAction.value = { settingsNavController.popBackStack() }
HomeScreenPreferences() HomeScreenPreferences(windowSizeClass = windowSizeClass)
} }
composable(SettingsNavItem.SpecialFeatures.route) { composable(SettingsNavItem.SpecialFeatures.route) {
appBarTitle.value = stringResource(id = R.string.preference_heading_special_features) appBarTitle.value = stringResource(id = R.string.preference_heading_special_features)

View File

@@ -2,13 +2,19 @@ package com.owenlejeune.tvtime.ui.screens
import android.app.Activity import android.app.Activity
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Scaffold import androidx.compose.material.Scaffold
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -28,6 +34,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.graphics.compositeOver
@@ -40,6 +47,7 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.owenlejeune.tvtime.extensions.WindowSizeClass import com.owenlejeune.tvtime.extensions.WindowSizeClass
import com.owenlejeune.tvtime.extensions.defaultNavBarColor
import com.owenlejeune.tvtime.extensions.navigateInBottomBar import com.owenlejeune.tvtime.extensions.navigateInBottomBar
import com.owenlejeune.tvtime.preferences.AppPreferences import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.components.AccountIcon import com.owenlejeune.tvtime.ui.components.AccountIcon
@@ -50,13 +58,20 @@ import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavHost
import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavItem import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavItem
import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel
import org.koin.java.KoinJavaComponent import org.koin.java.KoinJavaComponent
import org.koin.java.KoinJavaComponent.get
object HomeScreen {
val FLOATING_NAV_BAR_HEIGHT = 80.dp
val FLOATING_NAV_BAR_OFFSET = (-24).dp
}
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun HomeScreen( fun HomeScreen(
appNavController: NavHostController, appNavController: NavHostController,
mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route, mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route,
windowSize: WindowSizeClass windowSize: WindowSizeClass,
preferences: AppPreferences = get(AppPreferences::class.java)
) { ) {
val navController = rememberNavController() val navController = rememberNavController()
@@ -74,13 +89,11 @@ fun HomeScreen(
) )
} }
val defaultNavBarColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.08f).compositeOver(background = MaterialTheme.colorScheme.surface)
ProfileMenuContainer( ProfileMenuContainer(
appNavController = appNavController, appNavController = appNavController,
visible = showProfileMenuOverlay.value, visible = showProfileMenuOverlay.value,
onDismissRequest = { showProfileMenuOverlay.value = false }, onDismissRequest = { showProfileMenuOverlay.value = false },
colors = ProfileMenuDefaults.systemBarColors(navBarColor = defaultNavBarColor) colors = ProfileMenuDefaults.systemBarColors(navBarColor = MaterialTheme.colorScheme.defaultNavBarColor())
) { ) {
Scaffold( Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
@@ -98,7 +111,7 @@ fun HomeScreen(
fab.value() fab.value()
}, },
bottomBar = { bottomBar = {
if (windowSize != WindowSizeClass.Expanded) { if (windowSize != WindowSizeClass.Expanded && !preferences.floatingBottomBar) {
BottomNavBar(navController = navController) BottomNavBar(navController = navController)
} }
} }
@@ -112,6 +125,10 @@ fun HomeScreen(
mainNavStartRoute = mainNavStartRoute, mainNavStartRoute = mainNavStartRoute,
navigationIcon = navigationIcon navigationIcon = navigationIcon
) )
if (windowSize != WindowSizeClass.Expanded && preferences.floatingBottomBar) {
FloatingBottomNavBar(navController = navController, modifier = Modifier.align(Alignment.BottomCenter))
}
} }
} }
} }
@@ -137,10 +154,60 @@ private fun TopBar(
) )
} }
@Composable
private fun FloatingBottomNavBar(
navController: NavHostController,
modifier: Modifier = Modifier,
preferences: AppPreferences = get(AppPreferences::class.java)
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
Box(
modifier = modifier.then(
Modifier
.fillMaxWidth()
.height(HomeScreen.FLOATING_NAV_BAR_HEIGHT)
.padding(horizontal = 24.dp)
.offset(y = HomeScreen.FLOATING_NAV_BAR_OFFSET)
.clip(RoundedCornerShape(50))
.background(MaterialTheme.colorScheme.defaultNavBarColor())
)
) {
Row(
modifier = Modifier.align(Alignment.Center),
verticalAlignment = Alignment.CenterVertically
) {
HomeScreenNavItem.SortedItems.forEach { item ->
val isSelected = currentRoute == item.route
NavigationBarItem(
modifier = Modifier.clip(RoundedCornerShape(25.dp)),
icon = { Icon(imageVector = item.icon, contentDescription = null) },
label = {
if (preferences.showBottomTabLabels) {
Text(text = item.name)
}
},
selected = isSelected,
onClick = {
if (!isSelected) {
navController.navigateInBottomBar(item.route)
}
},
colors = NavigationBarItemDefaults.colors(
indicatorColor = MaterialTheme.colorScheme.secondary,
selectedIconColor = MaterialTheme.colorScheme.onSecondary
)
)
}
}
}
}
@Composable @Composable
private fun BottomNavBar( private fun BottomNavBar(
navController: NavController, navController: NavController,
preferences: AppPreferences = KoinJavaComponent.get(AppPreferences::class.java) preferences: AppPreferences = get(AppPreferences::class.java)
) { ) {
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route val currentRoute = navBackStackEntry?.destination?.route
@@ -220,7 +287,7 @@ private fun DualColumnMainContent(
topBarScrollBehaviour: TopAppBarScrollBehavior, topBarScrollBehaviour: TopAppBarScrollBehavior,
navigationIcon: @Composable () -> Unit = {}, navigationIcon: @Composable () -> Unit = {},
mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route, mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route,
preferences: AppPreferences = KoinJavaComponent.get(AppPreferences::class.java) preferences: AppPreferences = get(AppPreferences::class.java)
) { ) {
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route val currentRoute = navBackStackEntry?.destination?.route

View File

@@ -16,7 +16,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.IconButton import androidx.compose.material.IconButton
import androidx.compose.material.TextButton import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -67,6 +69,7 @@ import com.kieronquinn.monetcompat.core.MonetCompat
import com.owenlejeune.tvtime.BuildConfig import com.owenlejeune.tvtime.BuildConfig
import com.owenlejeune.tvtime.OnboardingActivity import com.owenlejeune.tvtime.OnboardingActivity
import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.extensions.WindowSizeClass
import com.owenlejeune.tvtime.extensions.unlessEmpty import com.owenlejeune.tvtime.extensions.unlessEmpty
import com.owenlejeune.tvtime.preferences.AppPreferences import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.components.CenteredIconCircle import com.owenlejeune.tvtime.ui.components.CenteredIconCircle
@@ -89,7 +92,8 @@ import org.koin.java.KoinJavaComponent.get
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SettingsScreen( fun SettingsScreen(
appNavController: NavController appNavController: NavController,
windowSizeClass: WindowSizeClass
) { ) {
val applicationViewModel = viewModel<ApplicationViewModel>() val applicationViewModel = viewModel<ApplicationViewModel>()
applicationViewModel.statusBarColor.value = MaterialTheme.colorScheme.background applicationViewModel.statusBarColor.value = MaterialTheme.colorScheme.background
@@ -137,7 +141,8 @@ fun SettingsScreen(
SettingsNavigationHost( SettingsNavigationHost(
appNavController = appNavController, appNavController = appNavController,
appBarTitle = appBarTitle, appBarTitle = appBarTitle,
popBackAction = popBackAction popBackAction = popBackAction,
windowSizeClass = windowSizeClass
) )
} }
} }
@@ -150,7 +155,8 @@ fun SettingsHome(
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(all = 24.dp), .padding(horizontal = 24.dp)
.verticalScroll(state = rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(24.dp) verticalArrangement = Arrangement.spacedBy(24.dp)
) { ) {
TopLevelSettingsCard( TopLevelSettingsCard(
@@ -202,7 +208,8 @@ fun SearchPreferences() {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(all = 24.dp), .padding(horizontal = 24.dp)
.verticalScroll(state = rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(24.dp) verticalArrangement = Arrangement.spacedBy(24.dp)
) { ) {
SwitchPreference( SwitchPreference(
@@ -235,7 +242,8 @@ fun DesignPreferences(
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(all = 24.dp), .padding(horizontal = 24.dp)
.verticalScroll(state = rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(24.dp) verticalArrangement = Arrangement.spacedBy(24.dp)
) { ) {
TopLevelSettingsCard( TopLevelSettingsCard(
@@ -325,7 +333,8 @@ fun DarkModePreferences() {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(all = 24.dp), .padding(horizontal = 24.dp)
.verticalScroll(state = rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(24.dp) verticalArrangement = Arrangement.spacedBy(24.dp)
) { ) {
PreferenceHeading(text = stringResource(R.string.preference_dark_mode_automatic_heading)) PreferenceHeading(text = stringResource(R.string.preference_dark_mode_automatic_heading))
@@ -359,13 +368,14 @@ fun DarkModePreferences() {
} }
@Composable @Composable
fun HomeScreenPreferences() { fun HomeScreenPreferences(windowSizeClass: WindowSizeClass) {
val settingsViewModel = viewModel<SettingsViewModel>() val settingsViewModel = viewModel<SettingsViewModel>()
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(all = 24.dp), .padding(horizontal = 24.dp)
.verticalScroll(state = rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(24.dp) verticalArrangement = Arrangement.spacedBy(24.dp)
) { ) {
PreferenceHeading(text = stringResource(R.string.preference_look_and_feel_heading)) PreferenceHeading(text = stringResource(R.string.preference_look_and_feel_heading))
@@ -388,6 +398,17 @@ fun HomeScreenPreferences() {
} }
) )
if (windowSizeClass != WindowSizeClass.Expanded) {
SwitchPreference(
titleText = "Floating bottom navigation bar",
subtitleText = "Show the bottom navigation bar as a floating overlay",
checkState = settingsViewModel.showFloatingBottomBar.collectAsState(),
onCheckedChange = {
settingsViewModel.toggleShowFloatingBottomBar()
}
)
}
PreferenceHeading(text = stringResource(R.string.preference_home_tab_order_heading)) PreferenceHeading(text = stringResource(R.string.preference_home_tab_order_heading))
Box( Box(
@@ -398,6 +419,7 @@ fun HomeScreenPreferences() {
shape = RoundedCornerShape(10.dp) shape = RoundedCornerShape(10.dp)
) )
.padding(horizontal = 12.dp) .padding(horizontal = 12.dp)
.wrapContentHeight()
) { ) {
AndroidView( AndroidView(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -424,7 +446,8 @@ fun SpecialFeaturePreferences() {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(all = 24.dp), .padding(horizontal = 24.dp)
.verticalScroll(state = rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(24.dp) verticalArrangement = Arrangement.spacedBy(24.dp)
) { ) {
SwitchPreference( SwitchPreference(
@@ -449,7 +472,8 @@ fun DevPreferences(preferences: AppPreferences = get(AppPreferences::class.java)
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(all = 24.dp), .padding(horizontal = 24.dp)
.verticalScroll(state = rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(24.dp) verticalArrangement = Arrangement.spacedBy(24.dp)
) { ) {
SwitchPreference( SwitchPreference(

View File

@@ -1,13 +1,20 @@
package com.owenlejeune.tvtime.ui.theme package com.owenlejeune.tvtime.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.Colors import androidx.compose.material.Colors
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material3.darkColorScheme import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.kieronquinn.monetcompat.core.MonetCompat import com.kieronquinn.monetcompat.core.MonetCompat
@@ -124,7 +131,18 @@ fun TVTimeTheme(
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
systemUiController.setStatusBarColor(color = statusBarColor) systemUiController.setStatusBarColor(color = statusBarColor)
systemUiController.setNavigationBarColor(color = navigationBarColor) systemUiController.setNavigationBarColor(color = Color.Transparent)
// systemUiController.setNavigationBarColor(color = navigationBarColor)
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.navigationBarColor = Color.Transparent.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars = isDarkTheme
}
}
} }
) )
} }

View File

@@ -24,6 +24,7 @@ class SettingsViewModel: ViewModel() {
private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting) private val _firstLaunchTesting = MutableStateFlow(preferences.firstLaunchTesting)
private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery) private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery)
private val _showNextMcuProduction = MutableStateFlow(preferences.showNextMcuProduction) private val _showNextMcuProduction = MutableStateFlow(preferences.showNextMcuProduction)
private val _showFloatingBottomBar = MutableStateFlow(preferences.floatingBottomBar)
} }
val showSearchBar = _showSearchBar.asStateFlow() val showSearchBar = _showSearchBar.asStateFlow()
@@ -38,6 +39,7 @@ class SettingsViewModel: ViewModel() {
val firstLaunchTesting = _firstLaunchTesting.asStateFlow() val firstLaunchTesting = _firstLaunchTesting.asStateFlow()
val showBackdropGallery = _showBackdropGallery.asStateFlow() val showBackdropGallery = _showBackdropGallery.asStateFlow()
val showNextMcuProduction = _showNextMcuProduction.asStateFlow() val showNextMcuProduction = _showNextMcuProduction.asStateFlow()
val showFloatingBottomBar = _showFloatingBottomBar.asStateFlow()
fun toggleShowSearchBar() { fun toggleShowSearchBar() {
_showSearchBar.value = _showSearchBar.value.not() _showSearchBar.value = _showSearchBar.value.not()
@@ -144,4 +146,14 @@ class SettingsViewModel: ViewModel() {
preferences.showNextMcuProduction = value preferences.showNextMcuProduction = value
} }
fun toggleShowFloatingBottomBar() {
_showFloatingBottomBar.value = _showFloatingBottomBar.value.not()
preferences.floatingBottomBar = _showFloatingBottomBar.value
}
fun setShowFloatingBottomBar(value: Boolean) {
_showFloatingBottomBar.value = value
preferences.floatingBottomBar = value
}
} }

View File

@@ -2,5 +2,6 @@
<resources> <resources>
<style name="Theme.TVTime" parent="Theme.AppCompat.NoActionBar"> <style name="Theme.TVTime" parent="Theme.AppCompat.NoActionBar">
<item name="android:navigationBarColor">@android:color/transparent</item>
</style> </style>
</resources> </resources>