diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 417e9c89..647a9b89 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -199,6 +199,7 @@ dependencies { implementation(libs.geetest.sensebot) implementation(libs.koin.android) implementation(libs.koin.compose) + implementation(libs.koin.compose.navigation) implementation(libs.kotlinx.serialization) implementation(libs.ktor.client.cio) implementation(libs.koin.core) diff --git a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/component/Test.kt b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/component/Test.kt index d1aff49b..cd5fa84b 100644 --- a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/component/Test.kt +++ b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/component/Test.kt @@ -19,7 +19,7 @@ import dev.aaa1115910.bv.mobile.theme.BVMobileTheme @Composable fun ListDetailPaneScaffoldSample() { BVMobileTheme { - val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() + val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() ListDetailPaneScaffold( scaffoldState = scaffoldNavigator.scaffoldState, listPane = { @@ -66,7 +66,7 @@ private fun SettingPre() { @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun Settings() { - val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() + val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() ListDetailPaneScaffold( scaffoldState = scaffoldNavigator.scaffoldState, listPane = { diff --git a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/HomeScreenForPhone.kt b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/HomeScreenForPhone.kt deleted file mode 100644 index a12aea70..00000000 --- a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/HomeScreenForPhone.kt +++ /dev/null @@ -1,174 +0,0 @@ -package dev.aaa1115910.bv.mobile.screen - -import android.content.Intent -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.grid.rememberLazyGridState -import androidx.compose.material3.DrawerState -import androidx.compose.material3.Icon -import androidx.compose.material3.NavigationBar -import androidx.compose.material3.NavigationBarItem -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleEventObserver -import com.origeek.imageViewer.previewer.ImagePreviewerState -import dev.aaa1115910.bv.mobile.activities.LoginActivity -import dev.aaa1115910.bv.mobile.screen.home.DynamicScreen -import dev.aaa1115910.bv.mobile.screen.home.HomeScreen -import dev.aaa1115910.bv.mobile.screen.home.UserSwitchDialog -import dev.aaa1115910.bv.screen.user.UserSwitchViewModel -import dev.aaa1115910.bv.viewmodel.UserViewModel -import dev.aaa1115910.bv.viewmodel.home.PopularViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.koin.androidx.compose.koinViewModel - -@Composable -fun HomeScreenForPhone( - modifier: Modifier = Modifier, - drawerState: DrawerState, - homeViewModel: PopularViewModel = koinViewModel(), - userViewModel: UserViewModel = koinViewModel(), - userSwitchViewModel: UserSwitchViewModel = koinViewModel(), - currentScreen: MobileMainScreenNav, - onCurrentScreenChange: (MobileMainScreenNav) -> Unit, - windowSize: WindowWidthSizeClass, - previewerState: ImagePreviewerState, - onShowPreviewer: (newPictures: List, afterSetPictures: () -> Unit) -> Unit -) { - val context = LocalContext.current - val scope = rememberCoroutineScope() - val lifecycleOwner = LocalLifecycleOwner.current - - val lazyGridState = rememberLazyGridState() - var activeSearch by remember { mutableStateOf(false) } - var showUserSwitchDialog by remember { mutableStateOf(false) } - - LaunchedEffect(Unit) { - scope.launch(Dispatchers.IO) { homeViewModel.loadMore() } - } - - LaunchedEffect(Unit) { - userViewModel.updateUserInfo() - } - - DisposableEffect(lifecycleOwner) { - var leaveFromThisPage = false - val observer = LifecycleEventObserver { _, event -> - if (event == Lifecycle.Event.ON_PAUSE) { - leaveFromThisPage = true - } else if (event == Lifecycle.Event.ON_RESUME) { - if (leaveFromThisPage) { - scope.launch(Dispatchers.IO) { - userSwitchViewModel.updateUserDbList() - } - } - leaveFromThisPage = false - } - } - - lifecycleOwner.lifecycle.addObserver(observer) - - onDispose { - lifecycleOwner.lifecycle.removeObserver(observer) - } - } - - Box { - Scaffold( - modifier = modifier, - bottomBar = { - if (windowSize == WindowWidthSizeClass.Expanded) return@Scaffold - - Column { - AnimatedVisibility(visible = !activeSearch) { - NavigationBar { - NavigationBarItem( - icon = { - Icon( - MobileMainScreenNav.Home.icon, - contentDescription = MobileMainScreenNav.Home.displayName - ) - }, - label = { Text(text = MobileMainScreenNav.Home.displayName) }, - selected = currentScreen == MobileMainScreenNav.Home, - onClick = { onCurrentScreenChange(MobileMainScreenNav.Home) } - ) - NavigationBarItem( - icon = { - Icon( - MobileMainScreenNav.Dynamic.icon, - contentDescription = MobileMainScreenNav.Dynamic.displayName - ) - }, - label = { Text(text = MobileMainScreenNav.Dynamic.displayName) }, - selected = currentScreen == MobileMainScreenNav.Dynamic, - onClick = { onCurrentScreenChange(MobileMainScreenNav.Dynamic) } - ) - } - } - } - } - ) { innerPadding -> - val modifier = Modifier.padding(innerPadding) - when (currentScreen) { - MobileMainScreenNav.Home -> { - HomeScreen( - drawerState = drawerState, - gridState = lazyGridState, - windowSize = windowSize, - onSearchActiveChange = { activeSearch = it }, - onShowSwitchUser = { - scope.launch(Dispatchers.IO) { - userSwitchViewModel.updateUserDbList() - showUserSwitchDialog = true - } - } - ) - } - - MobileMainScreenNav.Dynamic -> { - DynamicScreen( - previewerState = previewerState, - onShowPreviewer = onShowPreviewer - ) - } - - else -> {} - } - } - UserSwitchDialog( - show = showUserSwitchDialog, - onHideDialog = { showUserSwitchDialog = false }, - currentUser = userSwitchViewModel.currentUser, - userList = userSwitchViewModel.userDbList, - onSwitchUser = { user -> - scope.launch(Dispatchers.IO) { - userSwitchViewModel.switchUser(user) - } - }, - onAddUser = { context.startActivity(Intent(context, LoginActivity::class.java)) }, - onDeleteUser = { user -> - scope.launch(Dispatchers.IO) { - userSwitchViewModel.deleteUser(user) - } - } - ) - } -} - diff --git a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/MobileMainScreen.kt b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/MobileMainScreen.kt index 9c2fc1da..9e5ac23e 100644 --- a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/MobileMainScreen.kt +++ b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/MobileMainScreen.kt @@ -1,10 +1,11 @@ package dev.aaa1115910.bv.mobile.screen import android.app.Activity +import android.content.Context import android.content.Intent import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.FavoriteBorder @@ -14,18 +15,25 @@ import androidx.compose.material.icons.rounded.Home import androidx.compose.material.icons.rounded.People import androidx.compose.material.icons.rounded.Search import androidx.compose.material.icons.rounded.Settings +import androidx.compose.material3.DrawerState import androidx.compose.material3.DrawerValue import androidx.compose.material3.Icon import androidx.compose.material3.ModalNavigationDrawer -import androidx.compose.material3.NavigationRail -import androidx.compose.material3.NavigationRailItem import androidx.compose.material3.Text +import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.material3.adaptive.navigationsuite.ExperimentalMaterial3AdaptiveNavigationSuiteApi +import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold +import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldDefaults +import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi -import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass +import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf @@ -35,8 +43,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest @@ -49,35 +63,48 @@ import dev.aaa1115910.bv.mobile.activities.SettingsActivity import dev.aaa1115910.bv.mobile.screen.home.DynamicScreen import dev.aaa1115910.bv.mobile.screen.home.FollowingUserScreen import dev.aaa1115910.bv.mobile.screen.home.HomeScreen +import dev.aaa1115910.bv.mobile.screen.home.UserSwitchDialog +import dev.aaa1115910.bv.screen.user.UserSwitchViewModel import dev.aaa1115910.bv.util.Prefs import dev.aaa1115910.bv.util.swapList import dev.aaa1115910.bv.viewmodel.UserViewModel import dev.aaa1115910.bv.viewmodel.home.PopularViewModel import io.github.oshai.kotlinlogging.KotlinLogging +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel -@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) +@OptIn( + ExperimentalMaterial3AdaptiveNavigationSuiteApi::class, + ExperimentalMaterial3AdaptiveApi::class +) @Composable fun MobileMainScreen( modifier: Modifier = Modifier, homeViewModel: PopularViewModel = koinViewModel(), - userViewModel: UserViewModel = koinViewModel() + userViewModel: UserViewModel = koinViewModel(), + userSwitchViewModel: UserSwitchViewModel = koinViewModel() ) { + val state = rememberMobileMainScreenState( + homeViewModel = homeViewModel, + userViewModel = userViewModel, + userSwitchViewModel = userSwitchViewModel + ) val context = LocalContext.current val scope = rememberCoroutineScope() - val logger = KotlinLogging.logger { } - val windowSizeClass = calculateWindowSizeClass(context as Activity) - val drawerState = rememberDrawerState(DrawerValue.Closed) - val lazyGridState = rememberLazyGridState() - val navController = rememberNavController() + val navSuiteType = + NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(currentWindowAdaptiveInfo()) + val navigationItems = when (navSuiteType) { + NavigationSuiteType.NavigationBar -> listOf( + MobileMainScreenNav.Home, + MobileMainScreenNav.Dynamic + ) - var searchText by remember { mutableStateOf("") } - var activeSearch by remember { mutableStateOf(false) } - - var currentScreen by remember { mutableStateOf(MobileMainScreenNav.Home) } + NavigationSuiteType.NavigationRail -> MobileMainScreenNav.entries + else -> MobileMainScreenNav.entries + } val pictures = remember { mutableStateListOf() } val previewerState = rememberPreviewerState( @@ -86,163 +113,96 @@ fun MobileMainScreen( getKey = { pictures[it] } ) - val openNavDrawer: () -> Unit = { scope.launch { drawerState.open() } } - - val goHome = { - navController.navigate("home") { - popUpTo("home") - launchSingleTop = true - } - currentScreen = MobileMainScreenNav.Home - } - - val goHistory = { - navController.navigate("history") { - popUpTo("home") - } - currentScreen = MobileMainScreenNav.History - } - - val goFavorite = { - navController.navigate("favorite") { - popUpTo("home") - } - currentScreen = MobileMainScreenNav.Favorite - } - - val goSettings = { - /*navController.navigate("setting") { - popUpTo("home") - } - currentScreen = MobileMainScreenNav.Setting*/ - context.startActivity(Intent(context, SettingsActivity::class.java)) - } - - val goMyFollowingUser = { - navController.navigate("followingUser") { - popUpTo("home") - } - currentScreen = MobileMainScreenNav.FollowingUser - } - - val goDynamic = { - navController.navigate("dynamic") { - popUpTo("dynamic") - } - currentScreen = MobileMainScreenNav.Dynamic - } - val onShowPreviewer: (newPictures: List, afterSetPictures: () -> Unit) -> Unit = { newPictures, afterSetPictures -> pictures.swapList(newPictures) afterSetPictures() } - LaunchedEffect(Unit) { - scope.launch(Dispatchers.IO) { homeViewModel.loadMore() } - } - - LaunchedEffect(Unit) { - userViewModel.updateUserInfo() - - navController.addOnDestinationChangedListener { controller, destination, arguments -> - logger.info { "current route: ${destination.route}" } - if (destination.route == "home") { - currentScreen = MobileMainScreenNav.Home - } - } - } - BackHandler(previewerState.canClose || previewerState.animating) { if (previewerState.canClose) scope.launch { previewerState.closeTransform() } } + BackHandler(state.showUserSwitchDialog) { + state.hideUserSwitch() + } + ModalNavigationDrawer( modifier = modifier, - drawerState = drawerState, - gesturesEnabled = !activeSearch, + drawerState = state.drawerState, + gesturesEnabled = !state.activeSearch, drawerContent = { ModalNavDrawerContent( avatar = userViewModel.face, username = userViewModel.username, isLogin = Prefs.isLogin, - onCloseDrawer = { scope.launch { drawerState.close() } }, + onCloseDrawer = { scope.launch { state.drawerState.close() } }, onLogin = { context.startActivity(Intent(context, LoginActivity::class.java)) }, onLogout = { }, - onGoHome = goHome, - onGoHistory = goHistory, - onGoFavorite = goFavorite, - onGoSetting = goSettings, - onGoMyFollowingUser = goMyFollowingUser, + onGoHome = { state.navigate(MobileMainScreenNav.Home) }, + onGoHistory = { state.navigate(MobileMainScreenNav.History) }, + onGoFavorite = { state.navigate(MobileMainScreenNav.Favorite) }, + onGoSetting = { state.navigate(MobileMainScreenNav.Setting) }, + onGoMyFollowingUser = { state.navigate(MobileMainScreenNav.FollowingUser) }, ) } ) { - Row { - if (windowSizeClass.widthSizeClass == WindowWidthSizeClass.Expanded) { - MainNavRail( - currentScreen = currentScreen, - onCurrentScreenChange = { - when (it) { - MobileMainScreenNav.Home -> goHome() - MobileMainScreenNav.Search -> goHistory() - MobileMainScreenNav.Dynamic -> goDynamic() - MobileMainScreenNav.Setting -> goSettings() - MobileMainScreenNav.History -> goHistory() - MobileMainScreenNav.Favorite -> goFavorite() - MobileMainScreenNav.FollowingUser -> goMyFollowingUser() - } - }, - ) + NavigationSuiteScaffold( + navigationSuiteItems = { + navigationItems.forEach { navItem -> + item( + icon = { Icon(navItem.icon, contentDescription = navItem.displayName) }, + label = { Text(navItem.displayName) }, + selected = state.currentNavItem == navItem, + onClick = { state.navigate(navItem) } + ) + } } - + ) { NavHost( - modifier = Modifier.fillMaxSize(), - navController = navController, - startDestination = "home" + navController = state.navController, + startDestination = MobileMainScreenNav.Home.name ) { - composable("home") { - if (windowSizeClass.widthSizeClass != WindowWidthSizeClass.Expanded) { - HomeScreenForPhone( - drawerState = drawerState, - currentScreen = currentScreen, - onCurrentScreenChange = { currentScreen = it }, - windowSize = windowSizeClass.widthSizeClass, - previewerState = previewerState, - onShowPreviewer = onShowPreviewer, - ) - } else { - HomeScreen( - drawerState = drawerState, - gridState = lazyGridState, - windowSize = windowSizeClass.widthSizeClass, - onSearchActiveChange = { activeSearch = it }, - onShowSwitchUser = {} - ) - } + composable(MobileMainScreenNav.Home.name) { + HomeScreen( + drawerState = state.drawerState, + gridState = state.lazyGridState, + windowSize = state.windowSizeClass.widthSizeClass, + onSearchActiveChange = { state.activeSearch = it }, + onShowSwitchUser = state::showUserSwitch + ) } - composable("dynamic") { + + composable(MobileMainScreenNav.Dynamic.name) { + BackHandler(previewerState.canClose || previewerState.animating) { + if (previewerState.canClose) scope.launch { + previewerState.closeTransform() + } + } + DynamicScreen( previewerState = previewerState, onShowPreviewer = onShowPreviewer ) } - composable("history") { + + composable(MobileMainScreenNav.History.name) { Text(text = "History") } - composable("search") { + composable(MobileMainScreenNav.Search.name) { Text(text = "Search") } - composable("setting") { + composable(MobileMainScreenNav.Setting.name) { Text(text = "Setting") } - composable("favorite") { + composable(MobileMainScreenNav.Favorite.name) { Text(text = "Favorite") } - composable("followingUser") { + composable(MobileMainScreenNav.FollowingUser.name) { FollowingUserScreen( - onBack = goHome + onBack = {} ) } } @@ -261,28 +221,183 @@ fun MobileMainScreen( rememberAsyncImagePainter(imageRequest) } ) + + UserSwitchDialog( + show = state.showUserSwitchDialog, + onHideDialog = { state.showUserSwitchDialog = false }, + currentUser = userSwitchViewModel.currentUser, + userList = userSwitchViewModel.userDbList, + onSwitchUser = { user -> + scope.launch(Dispatchers.IO) { + userSwitchViewModel.switchUser(user) + } + }, + onAddUser = { context.startActivity(Intent(context, LoginActivity::class.java)) }, + onDeleteUser = { user -> + scope.launch(Dispatchers.IO) { + userSwitchViewModel.deleteUser(user) + } + } + ) } -@Composable -private fun MainNavRail( - modifier: Modifier = Modifier, - currentScreen: MobileMainScreenNav, - onCurrentScreenChange: (MobileMainScreenNav) -> Unit +data class MobileMainScreenState( + val context: Context, + val scope: CoroutineScope, + val windowSizeClass: WindowSizeClass, + val drawerState: DrawerState, + val lazyGridState: LazyGridState, + val navController: NavHostController, + val currentBackStackEntry: NavBackStackEntry?, + val currentNavItem: MobileMainScreenNav, + private val homeViewModel: PopularViewModel, + private val userViewModel: UserViewModel, + private val userSwitchViewModel: UserSwitchViewModel, ) { - NavigationRail( - modifier = modifier - ) { - MobileMainScreenNav.values().forEach { nav -> - NavigationRailItem( - icon = { Icon(imageVector = nav.icon, contentDescription = nav.displayName) }, - label = { Text(text = nav.displayName) }, - selected = currentScreen == nav, - onClick = { onCurrentScreenChange(nav) } - ) + companion object { + val logger = KotlinLogging.logger {} + } + + var activeSearch by mutableStateOf(false) + + var showUserSwitchDialog by mutableStateOf(false) + + fun navigate(navItem: MobileMainScreenNav) { + logger.info { "Navigate to ${navItem.name}" } + when (navItem) { + MobileMainScreenNav.Home -> { + navController.navigate(navItem.name) { + popUpTo(navItem.name) + launchSingleTop = true + } + } + + MobileMainScreenNav.Search -> { + navController.navigate(navItem.name) { + popUpTo(MobileMainScreenNav.Home.name) + } + } + + MobileMainScreenNav.Favorite -> { + navController.navigate(navItem.name) { + popUpTo(MobileMainScreenNav.Home.name) + } + } + + MobileMainScreenNav.Setting -> { + context.startActivity(Intent(context, SettingsActivity::class.java)) + } + + MobileMainScreenNav.FollowingUser -> { + navController.navigate(navItem.name) { + popUpTo(MobileMainScreenNav.Home.name) + } + } + + MobileMainScreenNav.Dynamic -> { + navController.navigate(navItem.name) { + popUpTo(MobileMainScreenNav.Home.name) + } + } + + MobileMainScreenNav.History -> { + navController.navigate(navItem.name) { + popUpTo(MobileMainScreenNav.Home.name) + } + } + } + } + + fun showUserSwitch() { + scope.launch(Dispatchers.IO) { + userSwitchViewModel.updateUserDbList() + showUserSwitchDialog = true } } + + fun hideUserSwitch() { + showUserSwitchDialog = false + } } +@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) +@Composable +fun rememberMobileMainScreenState( + context: Context = LocalContext.current, + scope: CoroutineScope = rememberCoroutineScope(), + windowSizeClass: WindowSizeClass = calculateWindowSizeClass(context as Activity), + drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed), + lazyGridState: LazyGridState = rememberLazyGridState(), + navController: NavHostController = rememberNavController(), + homeViewModel: PopularViewModel,//= koinNavViewModel(), + userViewModel: UserViewModel,//= koinNavViewModel(), + userSwitchViewModel: UserSwitchViewModel //= koinNavViewModel() +): MobileMainScreenState { + val lifecycleOwner = LocalLifecycleOwner.current + + val currentBackStackEntry by navController.currentBackStackEntryAsState() + val currentNavItem by remember { + derivedStateOf { + MobileMainScreenNav.fromName(currentBackStackEntry?.destination?.route ?: "") + } + } + + LaunchedEffect(Unit) { + if (homeViewModel.popularVideoList.isNotEmpty()) { + scope.launch(Dispatchers.IO) { homeViewModel.loadMore() } + } + } + + LaunchedEffect(Unit) { + userViewModel.updateUserInfo() + } + + DisposableEffect(lifecycleOwner) { + var leaveFromThisPage = false + val observer = LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_PAUSE) { + leaveFromThisPage = true + } else if (event == Lifecycle.Event.ON_RESUME) { + if (leaveFromThisPage) { + scope.launch(Dispatchers.IO) { + userSwitchViewModel.updateUserDbList() + } + } + leaveFromThisPage = false + } + } + + lifecycleOwner.lifecycle.addObserver(observer) + + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + } + } + + return remember( + context, + scope, + windowSizeClass, + drawerState, + lazyGridState, + navController, + currentNavItem + ) { + MobileMainScreenState( + context, + scope, + windowSizeClass, + drawerState, + lazyGridState, + navController, + currentBackStackEntry, + currentNavItem, + homeViewModel, + userViewModel, + userSwitchViewModel + ) + } +} enum class MobileMainScreenNav(val displayName: String, val icon: ImageVector) { Home("首页", Icons.Rounded.Home), @@ -291,5 +406,9 @@ enum class MobileMainScreenNav(val displayName: String, val icon: ImageVector) { Setting("设置", Icons.Rounded.Settings), History("历史记录", Icons.Rounded.History), Favorite("私人藏品", Icons.Rounded.FavoriteBorder), - FollowingUser("我推的UP", Icons.Rounded.People) + FollowingUser("我推的UP", Icons.Rounded.People); + + companion object { + fun fromName(name: String) = entries.firstOrNull { it.name == name } ?: Home + } } \ No newline at end of file diff --git a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/DynamicScreen.kt b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/DynamicScreen.kt index 2d88121b..a90ef795 100644 --- a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/DynamicScreen.kt +++ b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/DynamicScreen.kt @@ -1,7 +1,9 @@ package dev.aaa1115910.bv.mobile.screen.home +import android.app.Activity import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -12,6 +14,9 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -23,17 +28,19 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import com.origeek.imageViewer.previewer.ImagePreviewerState import dev.aaa1115910.biliapi.entity.user.DynamicType +import dev.aaa1115910.bv.component.ifElse import dev.aaa1115910.bv.mobile.activities.VideoPlayerActivity import dev.aaa1115910.bv.mobile.component.home.dynamic.DynamicItem import dev.aaa1115910.bv.util.isScrolledToEnd import dev.aaa1115910.bv.viewmodel.home.DynamicViewModel import org.koin.androidx.compose.koinViewModel +import org.koin.androidx.compose.navigation.koinNavViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun DynamicScreen( modifier: Modifier = Modifier, - dynamicViewModel: DynamicViewModel = koinViewModel(), + dynamicViewModel: DynamicViewModel = koinNavViewModel(), previewerState: ImagePreviewerState, onShowPreviewer: (newPictures: List, afterSetPictures: () -> Unit) -> Unit ) { @@ -60,9 +67,7 @@ fun DynamicScreen( } ) { innerPadding -> Box( - modifier = Modifier - .padding(innerPadding) - .padding(bottom = 80.dp) + modifier = Modifier.padding(top = innerPadding.calculateTopPadding()) ) { LazyColumn( modifier = Modifier.background(MaterialTheme.colorScheme.surfaceVariant), diff --git a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/HomeScreen.kt b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/HomeScreen.kt index 9d6b9342..96a184bf 100644 --- a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/HomeScreen.kt +++ b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/home/HomeScreen.kt @@ -18,7 +18,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import dev.aaa1115910.bv.mobile.activities.LoginActivity import dev.aaa1115910.bv.mobile.activities.VideoPlayerActivity @@ -47,16 +49,14 @@ fun HomeScreen( onShowSwitchUser: () -> Unit ) { val context = LocalContext.current + val density = LocalDensity.current val scope = rememberCoroutineScope() val pageState = rememberPagerState(pageCount = { 2 }) var searchText by remember { mutableStateOf("") } var activeSearch by remember { mutableStateOf(false) } - //LaunchedEffect(Unit) { - // homeViewModel.loadMore() - //} - + var paddingToTop by remember { mutableStateOf(0.dp) } Scaffold( modifier = modifier, @@ -99,16 +99,18 @@ fun HomeScreen( ) { if (windowSize == WindowWidthSizeClass.Expanded) { HomeSearchTopBarExpanded( + modifier = Modifier.onSizeChanged { + paddingToTop = with(density) { it.height.toDp() } + }, query = searchText, active = activeSearch, onQueryChange = { searchText = it }, onActiveChange = { activeSearch = it } ) } - val gridTopPadding = - if (windowSize == WindowWidthSizeClass.Expanded) 68.dp else 8.dp + HorizontalPager( - modifier = Modifier, + modifier = Modifier.padding(top = paddingToTop), state = pageState, ) { page -> when (page) { diff --git a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/settings/SettingsScreen.kt b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/settings/SettingsScreen.kt index b102bf37..c5029763 100644 --- a/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/dev/aaa1115910/bv/mobile/screen/settings/SettingsScreen.kt @@ -27,7 +27,7 @@ import androidx.compose.ui.unit.dp @Composable fun SettingsScreen() { val context = LocalContext.current - val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator( + val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator( scaffoldDirective = calculateStandardPaneScaffoldDirective(currentWindowAdaptiveInfo()) ) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 50477387..13418da6 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -4,8 +4,8 @@ compose = "1.5.4" compose-compiler = "1.5.8" compose-constraintlayout = "1.0.1" compose-material3 = "1.2.0-beta02" -compose-material3-adaptive = "1.0.0-alpha02" -compose-material3-adaptive-navigation-suite = "1.0.0-alpha01" +compose-material3-adaptive = "1.0.0-alpha06" +compose-material3-adaptive-navigation-suite = "1.0.0-alpha03" compose-tv = "1.0.0-alpha10" core = "1.12.0" core-splashscreen = "1.0.1" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9813bbb5..cfa8a45c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -60,6 +60,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } koin-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin-compose" } +koin-compose-navigation = { module = "io.insert-koin:koin-androidx-compose-navigation", version.ref = "koin-compose" } # https://kotlinlang.org/docs/jvm-test-using-junit.html kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" }