refactor home screen ui options to viewmodel

This commit is contained in:
Owen LeJeune
2023-06-14 18:36:53 -04:00
parent 7941200b13
commit 3c2839f608
6 changed files with 56 additions and 76 deletions

View File

@@ -61,6 +61,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.*
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import coil.compose.AsyncImage import coil.compose.AsyncImage
import coil.compose.rememberAsyncImagePainter import coil.compose.rememberAsyncImagePainter
@@ -71,6 +72,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.viewmodel.HomeScreenViewModel
import com.owenlejeune.tvtime.utils.types.MediaViewType import com.owenlejeune.tvtime.utils.types.MediaViewType
import com.owenlejeune.tvtime.utils.SessionManager import com.owenlejeune.tvtime.utils.SessionManager
import com.owenlejeune.tvtime.utils.TmdbUtils import com.owenlejeune.tvtime.utils.TmdbUtils
@@ -209,7 +211,6 @@ fun SearchView(
title: String, title: String,
appNavController: NavHostController, appNavController: NavHostController,
mediaType: MediaViewType, mediaType: MediaViewType,
fab: MutableState<@Composable () -> Unit>,
preferences: AppPreferences = KoinJavaComponent.get(AppPreferences::class.java) preferences: AppPreferences = KoinJavaComponent.get(AppPreferences::class.java)
) { ) {
val route = AppNavItem.SearchView.withArgs(mediaType, title) val route = AppNavItem.SearchView.withArgs(mediaType, title)
@@ -220,7 +221,8 @@ fun SearchView(
appNavController.navigate(route) appNavController.navigate(route)
} }
} else { } else {
fab.value = @Composable { val homeScreenViewModel = viewModel<HomeScreenViewModel>()
homeScreenViewModel.fab.value = @Composable {
FloatingActionButton( FloatingActionButton(
onClick = { onClick = {
appNavController.navigate(route) appNavController.navigate(route)

View File

@@ -1,15 +1,13 @@
package com.owenlejeune.tvtime.ui.navigation package com.owenlejeune.tvtime.ui.navigation
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Face import androidx.compose.material.icons.outlined.Face
import androidx.compose.material.icons.outlined.Movie import androidx.compose.material.icons.outlined.Movie
import androidx.compose.material.icons.outlined.Person import androidx.compose.material.icons.outlined.Person
import androidx.compose.material.icons.outlined.Tv import androidx.compose.material.icons.outlined.Tv
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@@ -17,9 +15,10 @@ import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.preferences.AppPreferences import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.screens.AccountViewContent import com.owenlejeune.tvtime.ui.screens.AccountViewContent
import com.owenlejeune.tvtime.ui.screens.tabs.MediaTab import com.owenlejeune.tvtime.ui.screens.tabs.MediaTab
import com.owenlejeune.tvtime.utils.types.MediaViewType
import com.owenlejeune.tvtime.ui.screens.tabs.PeopleTab import com.owenlejeune.tvtime.ui.screens.tabs.PeopleTab
import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel
import com.owenlejeune.tvtime.utils.ResourceUtils import com.owenlejeune.tvtime.utils.ResourceUtils
import com.owenlejeune.tvtime.utils.types.MediaViewType
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@@ -27,40 +26,33 @@ import org.koin.core.component.inject
fun HomeScreenNavHost( fun HomeScreenNavHost(
appNavController: NavHostController, appNavController: NavHostController,
navController: NavHostController, navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
startDestination: String = HomeScreenNavItem.SortedItems[0].route startDestination: String = HomeScreenNavItem.SortedItems[0].route
) { ) {
val homeScreenViewModel = viewModel<HomeScreenViewModel>()
NavHost(navController = navController, startDestination = startDestination) { NavHost(navController = navController, startDestination = startDestination) {
composable(HomeScreenNavItem.Movies.route) { composable(HomeScreenNavItem.Movies.route) {
appBarActions.value = {} homeScreenViewModel.appBarActions.value = {}
MediaTab( MediaTab(
appBarTitle = appBarTitle,
appNavController = appNavController, appNavController = appNavController,
mediaType = MediaViewType.MOVIE, mediaType = MediaViewType.MOVIE,
fab = fab
) )
} }
composable(HomeScreenNavItem.TV.route) { composable(HomeScreenNavItem.TV.route) {
appBarActions.value = {} homeScreenViewModel.appBarActions.value = {}
MediaTab( MediaTab(
appBarTitle = appBarTitle,
appNavController = appNavController, appNavController = appNavController,
mediaType = MediaViewType.TV, mediaType = MediaViewType.TV,
fab = fab
) )
} }
composable(route = HomeScreenNavItem.Account.route) { composable(route = HomeScreenNavItem.Account.route) {
AccountViewContent(appNavController = appNavController) AccountViewContent(appNavController = appNavController)
fab.value = {} homeScreenViewModel.fab.value = {}
} }
composable(HomeScreenNavItem.People.route) { composable(HomeScreenNavItem.People.route) {
appBarActions.value = {} homeScreenViewModel.appBarActions.value = {}
PeopleTab( PeopleTab(
appBarTitle = appBarTitle,
appNavController = appNavController, appNavController = appNavController,
fab = fab
) )
} }
} }

View File

@@ -39,6 +39,7 @@ import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
@@ -51,6 +52,7 @@ import com.owenlejeune.tvtime.ui.components.ProfileMenuContainer
import com.owenlejeune.tvtime.ui.components.ProfileMenuDefaults import com.owenlejeune.tvtime.ui.components.ProfileMenuDefaults
import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavItem import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavItem
import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavHost import com.owenlejeune.tvtime.ui.navigation.HomeScreenNavHost
import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel
import org.koin.java.KoinJavaComponent import org.koin.java.KoinJavaComponent
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -68,9 +70,7 @@ fun HomeScreen(
TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec, topAppBarScrollState) TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec, topAppBarScrollState)
} }
val appBarTitle = remember { mutableStateOf<@Composable () -> Unit>({}) } val homeScreenViewModel = viewModel<HomeScreenViewModel>()
val appBarActions = remember { mutableStateOf<@Composable RowScope.() -> Unit>({}) }
val fab = remember { mutableStateOf<@Composable () -> Unit>({}) }
val showProfileMenuOverlay = remember { mutableStateOf(false) } val showProfileMenuOverlay = remember { mutableStateOf(false) }
val navigationIcon = @Composable { val navigationIcon = @Composable {
@@ -94,14 +94,13 @@ fun HomeScreen(
topBar = { topBar = {
if (windowSize != WindowSizeClass.Expanded) { if (windowSize != WindowSizeClass.Expanded) {
TopBar( TopBar(
title = appBarTitle.value,
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
appBarActions = appBarActions,
navigationIcon = navigationIcon navigationIcon = navigationIcon
) )
} }
}, },
floatingActionButton = { floatingActionButton = {
val fab = remember { homeScreenViewModel.fab }
fab.value() fab.value()
}, },
bottomBar = { bottomBar = {
@@ -115,9 +114,6 @@ fun HomeScreen(
windowSize = windowSize, windowSize = windowSize,
appNavController = appNavController, appNavController = appNavController,
navController = navController, navController = navController,
fab = fab,
appBarTitle = appBarTitle,
appBarActions = appBarActions,
topBarScrollBehaviour = scrollBehavior, topBarScrollBehaviour = scrollBehavior,
mainNavStartRoute = mainNavStartRoute, mainNavStartRoute = mainNavStartRoute,
navigationIcon = navigationIcon navigationIcon = navigationIcon
@@ -129,21 +125,21 @@ fun HomeScreen(
@Composable @Composable
private fun TopBar( private fun TopBar(
title: @Composable () -> Unit,
scrollBehavior: TopAppBarScrollBehavior, scrollBehavior: TopAppBarScrollBehavior,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
navigationIcon: @Composable () -> Unit = {} navigationIcon: @Composable () -> Unit = {}
) { ) {
val homeScreenViewModel = viewModel<HomeScreenViewModel>()
val title = remember { homeScreenViewModel.appBarTitle }
val actions = remember { homeScreenViewModel.appBarActions }
LargeTopAppBar( LargeTopAppBar(
title = title, title = { Text(text = title.value) },
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults colors = TopAppBarDefaults
.largeTopAppBarColors( .largeTopAppBarColors(
scrolledContainerColor = MaterialTheme.colorScheme.background scrolledContainerColor = MaterialTheme.colorScheme.background
), ),
actions = { actions = actions.value,
appBarActions.value(this)
},
navigationIcon = navigationIcon navigationIcon = navigationIcon
) )
} }
@@ -188,10 +184,7 @@ private fun MainContent(
windowSize: WindowSizeClass, windowSize: WindowSizeClass,
appNavController: NavHostController, appNavController: NavHostController,
navController: NavHostController, navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
topBarScrollBehaviour: TopAppBarScrollBehavior, topBarScrollBehaviour: TopAppBarScrollBehavior,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
navigationIcon: @Composable () -> Unit = {}, navigationIcon: @Composable () -> Unit = {},
mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route
) { ) {
@@ -199,9 +192,6 @@ private fun MainContent(
DualColumnMainContent( DualColumnMainContent(
appNavController = appNavController, appNavController = appNavController,
navController = navController, navController = navController,
fab = fab,
appBarTitle = appBarTitle,
appBarActions = appBarActions,
topBarScrollBehaviour = topBarScrollBehaviour, topBarScrollBehaviour = topBarScrollBehaviour,
mainNavStartRoute = mainNavStartRoute, mainNavStartRoute = mainNavStartRoute,
navigationIcon = navigationIcon navigationIcon = navigationIcon
@@ -210,9 +200,6 @@ private fun MainContent(
SingleColumnMainContent( SingleColumnMainContent(
appNavController = appNavController, appNavController = appNavController,
navController = navController, navController = navController,
fab = fab,
appBarTitle = appBarTitle,
appBarActions = appBarActions,
mainNavStartRoute = mainNavStartRoute mainNavStartRoute = mainNavStartRoute
) )
} }
@@ -222,17 +209,11 @@ private fun MainContent(
private fun SingleColumnMainContent( private fun SingleColumnMainContent(
appNavController: NavHostController, appNavController: NavHostController,
navController: NavHostController, navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route
) { ) {
MainMediaView( MainMediaView(
appNavController = appNavController, appNavController = appNavController,
navController = navController, navController = navController,
fab = fab,
appBarTitle = appBarTitle,
appBarActions = appBarActions,
mainNavStartRoute = mainNavStartRoute mainNavStartRoute = mainNavStartRoute
) )
} }
@@ -241,10 +222,7 @@ private fun SingleColumnMainContent(
private fun DualColumnMainContent( private fun DualColumnMainContent(
appNavController: NavHostController, appNavController: NavHostController,
navController: NavHostController, navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
topBarScrollBehaviour: TopAppBarScrollBehavior, topBarScrollBehaviour: TopAppBarScrollBehavior,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<@Composable (RowScope.() -> Unit)> = mutableStateOf({}),
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 = KoinJavaComponent.get(AppPreferences::class.java)
@@ -276,17 +254,12 @@ private fun DualColumnMainContent(
} }
Column { Column {
TopBar( TopBar(
title = appBarTitle.value,
scrollBehavior = topBarScrollBehaviour, scrollBehavior = topBarScrollBehaviour,
appBarActions = appBarActions,
navigationIcon = navigationIcon navigationIcon = navigationIcon
) )
MainMediaView( MainMediaView(
appNavController = appNavController, appNavController = appNavController,
navController = navController, navController = navController,
fab = fab,
appBarTitle = appBarTitle,
appBarActions = appBarActions,
mainNavStartRoute = mainNavStartRoute mainNavStartRoute = mainNavStartRoute
) )
} }
@@ -297,9 +270,6 @@ private fun DualColumnMainContent(
private fun MainMediaView( private fun MainMediaView(
appNavController: NavHostController, appNavController: NavHostController,
navController: NavHostController, navController: NavHostController,
fab: MutableState<@Composable () -> Unit>,
appBarTitle: MutableState<@Composable () -> Unit>,
appBarActions: MutableState<RowScope.() -> Unit> = mutableStateOf({}),
mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route mainNavStartRoute: String = HomeScreenNavItem.SortedItems[0].route
) { ) {
val activity = LocalContext.current as Activity val activity = LocalContext.current as Activity
@@ -311,9 +281,6 @@ private fun MainMediaView(
HomeScreenNavHost( HomeScreenNavHost(
appNavController = appNavController, appNavController = appNavController,
navController = navController, navController = navController,
fab = fab,
appBarTitle = appBarTitle,
appBarActions = appBarActions,
startDestination = mainNavStartRoute startDestination = mainNavStartRoute
) )
} }

View File

@@ -5,6 +5,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
@@ -18,30 +19,29 @@ import com.owenlejeune.tvtime.ui.components.SearchView
import com.owenlejeune.tvtime.ui.navigation.AppNavItem import com.owenlejeune.tvtime.ui.navigation.AppNavItem
import com.owenlejeune.tvtime.ui.navigation.MediaTabNavItem import com.owenlejeune.tvtime.ui.navigation.MediaTabNavItem
import com.owenlejeune.tvtime.ui.components.Tabs import com.owenlejeune.tvtime.ui.components.Tabs
import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel
import com.owenlejeune.tvtime.ui.viewmodel.MediaTabViewModel import com.owenlejeune.tvtime.ui.viewmodel.MediaTabViewModel
import com.owenlejeune.tvtime.utils.types.MediaViewType import com.owenlejeune.tvtime.utils.types.MediaViewType
@OptIn(ExperimentalPagerApi::class) @OptIn(ExperimentalPagerApi::class)
@Composable @Composable
fun MediaTab( fun MediaTab(
appBarTitle: MutableState<@Composable () -> Unit>,
appNavController: NavHostController, appNavController: NavHostController,
mediaType: MediaViewType, mediaType: MediaViewType
fab: MutableState<@Composable () -> Unit>
) { ) {
val titleText = when (mediaType) { val homeScreenViewModel = viewModel<HomeScreenViewModel>()
val titleText = when (mediaType) {
MediaViewType.MOVIE -> stringResource(id = R.string.nav_movies_title) MediaViewType.MOVIE -> stringResource(id = R.string.nav_movies_title)
MediaViewType.TV -> stringResource(id = R.string.nav_tv_title) MediaViewType.TV -> stringResource(id = R.string.nav_tv_title)
else -> "" else -> ""
} }
appBarTitle.value = @Composable { Text(text = titleText) } homeScreenViewModel.appBarTitle.value = titleText
Column { Column {
SearchView( SearchView(
title = titleText, title = titleText,
appNavController = appNavController, appNavController = appNavController,
mediaType = mediaType, mediaType = mediaType
fab = fab
) )
val tabs = when (mediaType) { val tabs = when (mediaType) {

View File

@@ -5,30 +5,29 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.ui.components.PagingPeoplePosterGrid import com.owenlejeune.tvtime.ui.components.PagingPeoplePosterGrid
import com.owenlejeune.tvtime.ui.components.SearchView import com.owenlejeune.tvtime.ui.components.SearchView
import com.owenlejeune.tvtime.ui.navigation.AppNavItem import com.owenlejeune.tvtime.ui.navigation.AppNavItem
import com.owenlejeune.tvtime.ui.viewmodel.HomeScreenViewModel
import com.owenlejeune.tvtime.ui.viewmodel.PeopleTabViewModel import com.owenlejeune.tvtime.ui.viewmodel.PeopleTabViewModel
import com.owenlejeune.tvtime.utils.types.MediaViewType import com.owenlejeune.tvtime.utils.types.MediaViewType
@Composable @Composable
fun PeopleTab( fun PeopleTab(
appBarTitle: MutableState<@Composable () -> Unit>,
appNavController: NavHostController, appNavController: NavHostController,
fab: MutableState<@Composable () -> Unit>
) { ) {
val titleText = stringResource(id = R.string.popular_today_header) val homeScreenViewModel = viewModel<HomeScreenViewModel>()
appBarTitle.value = { Text(text = titleText) } homeScreenViewModel.appBarTitle.value = stringResource(id = R.string.popular_today_header)
Column { Column {
SearchView( SearchView(
title = titleText, title = stringResource(id = R.string.popular_today_header),
appNavController = appNavController, appNavController = appNavController,
mediaType = MediaViewType.PERSON, mediaType = MediaViewType.PERSON
fab = fab
) )
val peopleList = PeopleTabViewModel().popularPeople.collectAsLazyPagingItems() val peopleList = PeopleTabViewModel().popularPeople.collectAsLazyPagingItems()

View File

@@ -0,0 +1,20 @@
package com.owenlejeune.tvtime.ui.viewmodel
import androidx.compose.foundation.layout.RowScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class HomeScreenViewModel: ViewModel() {
private object Backer {
val appBarTitle = mutableStateOf("")
val appBarActions = mutableStateOf<@Composable RowScope.() -> Unit>( {} )
val fab = mutableStateOf<@Composable () -> Unit>( {} )
}
val appBarTitle = Backer.appBarTitle
val appBarActions = Backer.appBarActions
val fab = Backer.fab
}