diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt index e365269..e1efc55 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt @@ -9,6 +9,7 @@ import androidx.compose.animation.fadeOut import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NamedNavArgument import androidx.navigation.NavBackStackEntry import androidx.navigation.NavDeepLink @@ -16,6 +17,7 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import com.paulcoding.hviewer.model.PostItem import com.paulcoding.hviewer.model.SiteConfigs import com.paulcoding.hviewer.network.Github import com.paulcoding.hviewer.ui.page.post.PostPage @@ -23,10 +25,6 @@ import com.paulcoding.hviewer.ui.page.posts.PostsPage import com.paulcoding.hviewer.ui.page.search.SearchPage import com.paulcoding.hviewer.ui.page.settings.SettingsPage import com.paulcoding.hviewer.ui.page.sites.SitesPage -import com.paulcoding.hviewer.ui.page.topics.TopicsPage -import java.net.URLDecoder -import java.net.URLEncoder -import java.nio.charset.StandardCharsets @Composable fun AppEntry() { @@ -34,18 +32,20 @@ fun AppEntry() { val githubState by Github.stateFlow.collectAsState() val siteConfigs = githubState.siteConfigs ?: SiteConfigs() + val appViewModel: AppViewModel = viewModel() + + fun navToImages(post: PostItem) { + appViewModel.setCurrentPost(post) + navController.navigate(Route.POST) + } NavHost(navController, Route.SITES) { animatedComposable(Route.SITES) { SitesPage(siteConfigs = siteConfigs, refresh = { Github.refreshLocalConfigs() }, navToTopics = { site -> - val firstTopic = siteConfigs.sites[site]?.tags?.keys?.first() - if (firstTopic != null) { - navController.navigate("${Route.POSTS}/$site/$firstTopic") - } else { - navController.navigate("${Route.TOPICS}/$site") - } + appViewModel.setSiteConfig(siteConfigs.sites[site]!!) + navController.navigate(Route.POSTS) }, navToSettings = { navController.navigate(Route.SETTINGS) }, @@ -54,59 +54,28 @@ fun AppEntry() { animatedComposable(Route.SETTINGS) { SettingsPage(goBack = { navController.popBackStack() }) } - animatedComposable("${Route.TOPICS}/{site}") { backStackEntry -> - val site = backStackEntry.arguments?.getString("site") ?: "" - val siteConfig = siteConfigs.sites[site] - - if (siteConfig != null) - TopicsPage( - siteConfig = siteConfig, - navToTopic = { topic -> - navController.navigate( - "${Route.POSTS}/${site}/$topic" - ) - }, - goBack = { navController.popBackStack() }) - } - animatedComposable("${Route.POSTS}/{site}/{topic}") { backStackEntry -> - val topic = backStackEntry.arguments?.getString("topic") ?: "" - val site = backStackEntry.arguments?.getString("site") ?: "" - val siteConfig = siteConfigs.sites[site]!! - + animatedComposable(Route.POSTS) { PostsPage( - siteConfig = siteConfig, - navToImages = { postUrl: String -> - navController.navigate( - "${Route.POST}/${site}/${topic}/${ - URLEncoder.encode(postUrl, StandardCharsets.UTF_8.toString()) - }" - ) + appViewModel, + navToImages = { post: PostItem -> + navToImages(post) }, - navToSearch = { navController.navigate("${Route.SEARCH}/$site") }, + navToSearch = { navController.navigate(Route.SEARCH) }, goBack = { navController.popBackStack() }, ) } - animatedComposable("${Route.POST}/{site}/{topic}/{postUrl}") { backStackEntry -> - val postUrl = backStackEntry.arguments?.getString("postUrl") ?: "" - val site = backStackEntry.arguments?.getString("site") ?: "" - val decodedUrl = URLDecoder.decode(postUrl, StandardCharsets.UTF_8.toString()) + animatedComposable(Route.POST) { PostPage( - siteConfig = siteConfigs.sites[site]!!, postUrl = decodedUrl, goBack = { + appViewModel, + goBack = { navController.popBackStack() }) } - animatedComposable("${Route.SEARCH}/{site}") { backStackEntry -> - val site = backStackEntry.arguments?.getString("site") ?: "" - val siteConfig = siteConfigs.sites[site]!! - + animatedComposable(Route.SEARCH) { SearchPage( - siteConfig = siteConfig, - navToImages = { postUrl: String -> - navController.navigate( - "${Route.POST}/${site}/search/${ - URLEncoder.encode(postUrl, StandardCharsets.UTF_8.toString()) - }" - ) + appViewModel = appViewModel, + navToImages = { post: PostItem -> + navToImages(post) }, goBack = { navController.popBackStack() }, ) diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt new file mode 100644 index 0000000..60b2935 --- /dev/null +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt @@ -0,0 +1,26 @@ +package com.paulcoding.hviewer.ui.page + +import androidx.lifecycle.ViewModel +import com.paulcoding.hviewer.model.PostItem +import com.paulcoding.hviewer.model.SiteConfig +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update + +class AppViewModel : ViewModel() { + private var _stateFlow = MutableStateFlow(UiState()) + val stateFlow = _stateFlow.asStateFlow() + + fun setCurrentPost(post: PostItem) { + _stateFlow.update { it.copy(post = post) } + } + + fun setSiteConfig(siteConfig: SiteConfig) { + _stateFlow.update { it.copy(siteConfig = siteConfig) } + } + + data class UiState( + val post: PostItem = PostItem(), + val siteConfig: SiteConfig = SiteConfig(), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/post/PostPage.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/post/PostPage.kt index 20ec8bf..8a9e9d6 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/post/PostPage.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/post/PostPage.kt @@ -40,6 +40,7 @@ import com.paulcoding.hviewer.ui.component.HImage import com.paulcoding.hviewer.ui.component.HLoading import com.paulcoding.hviewer.ui.component.HPageProgress import com.paulcoding.hviewer.ui.component.HideSystemBars +import com.paulcoding.hviewer.ui.page.AppViewModel import me.saket.telephoto.zoomable.DoubleClickToZoomListener import me.saket.telephoto.zoomable.ZoomSpec import me.saket.telephoto.zoomable.rememberZoomableState @@ -47,9 +48,13 @@ import me.saket.telephoto.zoomable.zoomable @OptIn(ExperimentalMaterial3Api::class) @Composable -fun PostPage(siteConfig: SiteConfig, postUrl: String, goBack: () -> Unit) { +fun PostPage(appViewModel: AppViewModel, goBack: () -> Unit) { + val appState by appViewModel.stateFlow.collectAsState() + val post = appState.post + val siteConfig = appState.siteConfig + val viewModel: PostViewModel = viewModel( - factory = PostViewModelFactory(postUrl, siteConfig = siteConfig) + factory = PostViewModelFactory(post.url, siteConfig = siteConfig) ) val uiState by viewModel.stateFlow.collectAsState() diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/posts/PostsPage.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/posts/PostsPage.kt index 361cbe1..773763f 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/posts/PostsPage.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/posts/PostsPage.kt @@ -41,17 +41,21 @@ import com.paulcoding.hviewer.ui.component.HImage import com.paulcoding.hviewer.ui.component.HLoading import com.paulcoding.hviewer.ui.component.HPageProgress import com.paulcoding.hviewer.ui.icon.Search +import com.paulcoding.hviewer.ui.page.AppViewModel import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable fun PostsPage( - navToImages: (postUrl: String) -> Unit, + appViewModel: AppViewModel, + navToImages: (PostItem) -> Unit, navToSearch: () -> Unit, - siteConfig: SiteConfig, goBack: () -> Unit ) { + val appState by appViewModel.stateFlow.collectAsState() + val siteConfig = appState.siteConfig + val listTopic = siteConfig.tags.keys.toList() val pagerState = rememberPagerState { listTopic.size } val selectedTabIndex = pagerState.currentPage @@ -98,8 +102,8 @@ fun PostsPage( page, onPageChange = { currentPage, total -> pageProgress = currentPage to total - }) { postUrl -> - navToImages(postUrl) + }) { post -> + navToImages(post) } } } @@ -111,7 +115,7 @@ fun PageContent( siteConfig: SiteConfig, topic: String, onPageChange: (Int, Int) -> Unit, - onClick: (String) -> Unit + onClick: (PostItem) -> Unit ) { val viewModel: PostsViewModel = viewModel( factory = PostsViewModelFactory(siteConfig, topic), @@ -144,8 +148,8 @@ fun PageContent( state = listState ) { items(uiState.postItems) { post -> - PostItemView(post) { postUrl -> - onClick(postUrl) + PostItemView(post) { + onClick(post) } } if (uiState.isLoading) @@ -165,11 +169,11 @@ fun PageContent( } @Composable -fun PostItemView(postItem: PostItem, viewPost: (postUrl: String) -> Unit) { +fun PostItemView(postItem: PostItem, viewPost: () -> Unit) { return Column(modifier = Modifier .padding(horizontal = 16.dp, vertical = 12.dp) .clickable { - viewPost(postItem.url) + viewPost() }) { Text(postItem.name) HImage( diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/search/SearchPage.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/search/SearchPage.kt index 2c7efbf..99a8b1a 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/search/SearchPage.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/search/SearchPage.kt @@ -34,22 +34,26 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.paulcoding.hviewer.MainApp.Companion.appContext import com.paulcoding.hviewer.extensions.isScrolledToEnd -import com.paulcoding.hviewer.model.SiteConfig +import com.paulcoding.hviewer.model.PostItem import com.paulcoding.hviewer.ui.component.HBackIcon import com.paulcoding.hviewer.ui.component.HEmpty import com.paulcoding.hviewer.ui.component.HLoading import com.paulcoding.hviewer.ui.component.HPageProgress import com.paulcoding.hviewer.ui.icon.EditIcon +import com.paulcoding.hviewer.ui.page.AppViewModel import com.paulcoding.hviewer.ui.page.posts.PostItemView @OptIn(ExperimentalMaterial3Api::class) @Composable fun SearchPage( - navToImages: (postUrl: String) -> Unit, - siteConfig: SiteConfig, - goBack: () -> Unit + appViewModel: AppViewModel, + navToImages: (post: PostItem) -> Unit, + goBack: () -> Unit, ) { + val appState by appViewModel.stateFlow.collectAsState() + val siteConfig = appState.siteConfig + val viewModel: SearchViewModel = viewModel( factory = SearchViewModelFactory(siteConfig), ) @@ -100,8 +104,8 @@ fun SearchPage( Icon(EditIcon, contentDescription = "Search") } } - PageContent(viewModel = viewModel) { postUrl -> - navToImages(postUrl) + PageContent(viewModel = viewModel) { post -> + navToImages(post) } } } @@ -111,7 +115,7 @@ fun SearchPage( @Composable fun PageContent( viewModel: SearchViewModel, - onClick: (String) -> Unit + onClick: (PostItem) -> Unit ) { val listState = rememberLazyListState() val uiState by viewModel.stateFlow.collectAsState() @@ -130,8 +134,8 @@ fun PageContent( state = listState ) { items(uiState.postItems) { post -> - PostItemView(post) { postUrl -> - onClick(postUrl) + PostItemView(post) { + onClick(post) } } if (uiState.isLoading)