From 6c926419e9b253dfcde1b1f0c71f960bdb48d1f2 Mon Sep 17 00:00:00 2001 From: Vladimir Dostoyevskiy <99822064+VDostoyevskiy@users.noreply.github.com> Date: Sun, 26 Nov 2023 23:02:03 +0800 Subject: [PATCH] Compose Era!!! (#346) * Initial Kill Fragment! * Cleanup * Cleanup * Convert to use Compose ModalBottomSheet * Ignore insets * Navigate * Fixes * Cleanup * Fix navToWebview * Fix navToWebview * showtip * Refine * Fixes --------- Co-authored-by: GG Bond --- .../androidx/navigation/ui/NavigationUI.kt | 38 --- .../ehviewer/ui/GalleryInfoBottomSheet.kt | 72 +++-- .../com/hippo/ehviewer/ui/MainActivity.kt | 270 ++++++++---------- .../com/hippo/ehviewer/ui/main/GalleryList.kt | 13 +- .../com/hippo/ehviewer/ui/scene/BaseScene.kt | 53 +--- .../ehviewer/ui/scene/DownloadsFragment.kt | 27 +- .../ehviewer/ui/scene/FavoritesFragment.kt | 33 +-- .../ui/scene/GalleryCommentsFragment.kt | 32 +-- .../ui/scene/GalleryDetailFragment.kt | 129 ++++----- .../ehviewer/ui/scene/GalleryListFragment.kt | 97 +++---- .../ui/scene/GalleryPreviewFragment.kt | 29 -- .../ehviewer/ui/scene/HistoryFragment.kt | 28 +- .../com/hippo/ehviewer/ui/scene/MainNav.kt | 70 ++--- .../ehviewer/ui/scene/ProgressFragment.kt | 38 +-- .../hippo/ehviewer/ui/scene/SceneCompose.kt | 15 - app/src/main/res/layout/activity_main.xml | 23 -- app/src/main/res/navigation/nav_graph.xml | 87 ------ gradle/libs.versions.toml | 3 +- 18 files changed, 305 insertions(+), 752 deletions(-) delete mode 100644 app/src/main/kotlin/androidx/navigation/ui/NavigationUI.kt delete mode 100644 app/src/main/kotlin/com/hippo/ehviewer/ui/scene/SceneCompose.kt delete mode 100644 app/src/main/res/layout/activity_main.xml delete mode 100644 app/src/main/res/navigation/nav_graph.xml diff --git a/app/src/main/kotlin/androidx/navigation/ui/NavigationUI.kt b/app/src/main/kotlin/androidx/navigation/ui/NavigationUI.kt deleted file mode 100644 index 41a7c2705..000000000 --- a/app/src/main/kotlin/androidx/navigation/ui/NavigationUI.kt +++ /dev/null @@ -1,38 +0,0 @@ -package androidx.navigation.ui - -import android.annotation.SuppressLint -import androidx.annotation.IdRes -import androidx.navigation.ActivityNavigator -import androidx.navigation.NavController -import androidx.navigation.NavDestination -import androidx.navigation.NavDestination.Companion.hierarchy -import androidx.navigation.NavOptions - -@SuppressLint("PrivateResource") -fun onNavDestinationSelected2(@IdRes id: Int, navController: NavController): Boolean { - if (navController.currentDestination?.matchDestination(id) == true) return true - val builder = NavOptions.Builder().setLaunchSingleTop(true) - if (navController.currentDestination!!.parent!!.findNode(id) is ActivityNavigator.Destination) { - builder.setEnterAnim(R.anim.nav_default_enter_anim) - .setExitAnim(R.anim.nav_default_exit_anim) - .setPopEnterAnim(R.anim.nav_default_pop_enter_anim) - .setPopExitAnim(R.anim.nav_default_pop_exit_anim) - } else { - builder.setEnterAnim(androidx.fragment.R.animator.fragment_open_enter) - .setExitAnim(androidx.fragment.R.animator.fragment_open_exit) - .setPopEnterAnim(androidx.fragment.R.animator.fragment_close_enter) - .setPopExitAnim(androidx.fragment.R.animator.fragment_close_exit) - } - val options = builder.build() - return try { - // TODO provide proper API instead of using Exceptions as Control-Flow. - navController.navigate(id, null, options) - // Return true only if the destination we've navigated to matches the MenuItem - navController.currentDestination?.matchDestination(id) == true - } catch (e: IllegalArgumentException) { - false - } -} - -fun NavDestination.matchDestination(@IdRes destId: Int): Boolean = - hierarchy.any { it.id == destId } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/GalleryInfoBottomSheet.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/GalleryInfoBottomSheet.kt index 279862205..f8bc3e726 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/GalleryInfoBottomSheet.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/GalleryInfoBottomSheet.kt @@ -1,8 +1,5 @@ package com.hippo.ehviewer.ui -import android.os.Bundle -import android.view.LayoutInflater -import android.view.ViewGroup import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -14,6 +11,7 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.Text +import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -21,8 +19,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.navigation.fragment.findNavController -import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings import com.hippo.ehviewer.client.EhUrl @@ -30,9 +26,9 @@ import com.hippo.ehviewer.client.EhUtils import com.hippo.ehviewer.client.data.GalleryDetail import com.hippo.ehviewer.client.data.GalleryInfo.Companion.LOCAL_FAVORITED import com.hippo.ehviewer.client.thumbUrl -import com.hippo.ehviewer.databinding.InfoSheetBinding import com.hippo.ehviewer.ui.scene.navWithUrl import com.hippo.ehviewer.util.addTextToClipboard +import com.ramcosta.composedestinations.navigation.DestinationsNavigator private const val INDEX_URL = 2 private const val INDEX_PARENT = 9 @@ -61,43 +57,39 @@ private fun GalleryDetail.generateContent() = arrayOf( R.string.favorite_name to favoriteName, ) -class GalleryInfoBottomSheet(private val detail: GalleryDetail) : BottomSheetDialogFragment() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = InfoSheetBinding.inflate(layoutInflater, container, false).apply { - content.setMD3Content { - Column(modifier = Modifier.fillMaxWidth()) { - val context = LocalContext.current - val navController = remember { findNavController() } - Text( - text = stringResource(id = R.string.gallery_info), - modifier = Modifier.align(Alignment.CenterHorizontally), - style = MaterialTheme.typography.titleLarge, - ) - val data = remember(detail) { detail.generateContent() } - ProvideTextStyle(MaterialTheme.typography.labelLarge) { - LazyColumn { - itemsIndexed(data) { index, (key, content) -> - Row( - modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.keyline_margin)).clickable { - if (index == INDEX_PARENT) { - if (content != null) { - navController.navWithUrl(content) - } - } else { - context.addTextToClipboard(content, true) - if (index == INDEX_URL) { - // Save it to avoid detect the gallery - Settings.clipboardTextHashCode = data[index].hashCode() - } - } - }.fillMaxWidth(), - ) { - Text(stringResource(id = key), modifier = Modifier.width(90.dp).padding(8.dp)) - Text(content.orEmpty(), modifier = Modifier.padding(8.dp)) +@Composable +fun GalleryInfoBottomSheet(detail: GalleryDetail, navigator: DestinationsNavigator) { + Column(modifier = Modifier.fillMaxWidth()) { + val context = LocalContext.current + Text( + text = stringResource(id = R.string.gallery_info), + modifier = Modifier.align(Alignment.CenterHorizontally), + style = MaterialTheme.typography.titleLarge, + ) + val data = remember(detail) { detail.generateContent() } + ProvideTextStyle(MaterialTheme.typography.labelLarge) { + LazyColumn { + itemsIndexed(data) { index, (key, content) -> + Row( + modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.keyline_margin)).clickable { + if (index == INDEX_PARENT) { + if (content != null) { + navigator.navWithUrl(content) + } + } else { + context.addTextToClipboard(content, true) + if (index == INDEX_URL) { + // Save it to avoid detect the gallery + Settings.clipboardTextHashCode = data[index].hashCode() + } } - } + }.fillMaxWidth(), + ) { + Text(stringResource(id = key), modifier = Modifier.width(90.dp).padding(8.dp)) + Text(content.orEmpty(), modifier = Modifier.padding(8.dp)) } } } } - }.root + } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt index 3c61df5cf..55a784732 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt @@ -15,6 +15,7 @@ */ package com.hippo.ehviewer.ui +import android.annotation.SuppressLint import android.app.assist.AssistContent import android.content.DialogInterface import android.content.Intent @@ -34,12 +35,9 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.ime -import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState @@ -59,17 +57,20 @@ import androidx.compose.material3.Icon import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.NavigationDrawerItem +import androidx.compose.material3.Scaffold import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.SideDrawer +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.currentRecomposeScope import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue @@ -79,37 +80,37 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidViewBinding -import androidx.core.os.bundleOf import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController -import androidx.navigation.fragment.NavHostFragment -import androidx.navigation.ui.onNavDestinationSelected2 +import androidx.navigation.compose.rememberNavController import com.google.android.material.snackbar.Snackbar import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings -import com.hippo.ehviewer.Settings.launchPage import com.hippo.ehviewer.client.data.ListUrlBuilder import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser import com.hippo.ehviewer.client.parser.GalleryPageUrlParser -import com.hippo.ehviewer.databinding.ActivityMainBinding import com.hippo.ehviewer.download.DownloadService import com.hippo.ehviewer.download.downloadLocation import com.hippo.ehviewer.icons.EhIcons import com.hippo.ehviewer.icons.filled.Subscriptions import com.hippo.ehviewer.image.Image.Companion.decodeBitmap +import com.hippo.ehviewer.ui.destinations.DownloadScreenDestination +import com.hippo.ehviewer.ui.destinations.FavouritesScreenDestination +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination +import com.hippo.ehviewer.ui.destinations.GalleryListScreenDestination +import com.hippo.ehviewer.ui.destinations.HistoryScreenDestination +import com.hippo.ehviewer.ui.destinations.HomePageScreenDestination +import com.hippo.ehviewer.ui.destinations.ProgressScreenDestination +import com.hippo.ehviewer.ui.destinations.SubscriptionScreenDestination +import com.hippo.ehviewer.ui.destinations.ToplistScreenDestination +import com.hippo.ehviewer.ui.destinations.WhatshotScreenDestination import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder import com.hippo.ehviewer.ui.legacy.EditTextDialogBuilder import com.hippo.ehviewer.ui.scene.BaseScene -import com.hippo.ehviewer.ui.scene.GalleryDetailFragment -import com.hippo.ehviewer.ui.scene.GalleryListFragment.Companion.toStartArgs -import com.hippo.ehviewer.ui.scene.ProgressFragment import com.hippo.ehviewer.ui.scene.TokenArgs -import com.hippo.ehviewer.ui.scene.navAnimated import com.hippo.ehviewer.ui.scene.navWithUrl +import com.hippo.ehviewer.ui.scene.navigate import com.hippo.ehviewer.ui.settings.showNewVersion import com.hippo.ehviewer.ui.tools.LocalDialogState import com.hippo.ehviewer.ui.tools.LocalTouchSlopProvider @@ -117,10 +118,12 @@ import com.hippo.ehviewer.updater.AppUpdater import com.hippo.ehviewer.util.AppConfig import com.hippo.ehviewer.util.ExceptionUtils import com.hippo.ehviewer.util.addTextToClipboard -import com.hippo.ehviewer.util.buildWindowInsets import com.hippo.ehviewer.util.getParcelableExtraCompat import com.hippo.ehviewer.util.getUrlFromClipboard -import com.hippo.ehviewer.util.set +import com.ramcosta.composedestinations.DestinationsNavHost +import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations +import com.ramcosta.composedestinations.rememberNavHostEngine +import com.ramcosta.composedestinations.utils.currentDestinationAsState import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext @@ -137,20 +140,16 @@ import splitties.systemservices.clipboardManager import splitties.systemservices.connectivityManager private val navItems = arrayOf( - Triple(R.id.nav_homepage, R.string.homepage, Icons.Default.Home), - Triple(R.id.nav_subscription, R.string.subscription, EhIcons.Default.Subscriptions), - Triple(R.id.nav_whats_hot, R.string.whats_hot, Icons.Default.Whatshot), - Triple(R.id.nav_toplist, R.string.toplist, Icons.Default.FormatListNumbered), - Triple(R.id.nav_favourite, R.string.favourite, Icons.Default.Favorite), - Triple(R.id.nav_history, R.string.history, Icons.Default.History), - Triple(R.id.nav_downloads, R.string.downloads, Icons.Default.Download), - Triple(R.id.nav_settings, R.string.settings, Icons.Default.Settings), + Triple(HomePageScreenDestination, R.string.homepage, Icons.Default.Home), + Triple(SubscriptionScreenDestination, R.string.subscription, EhIcons.Default.Subscriptions), + Triple(WhatshotScreenDestination, R.string.whats_hot, Icons.Default.Whatshot), + Triple(ToplistScreenDestination, R.string.toplist, Icons.Default.FormatListNumbered), + Triple(FavouritesScreenDestination, R.string.favourite, Icons.Default.Favorite), + Triple(HistoryScreenDestination, R.string.history, Icons.Default.History), + Triple(DownloadScreenDestination, R.string.downloads, Icons.Default.Download), ) class MainActivity : EhActivity() { - private lateinit var navController: NavController - private val isInitializedFlow = MutableStateFlow(false) - private var sideSheet = mutableStateListOf<@Composable ColumnScope.(DrawerState2) -> Unit>() @Composable @@ -212,7 +211,7 @@ class MainActivity : EhActivity() { when (intent?.action) { Intent.ACTION_VIEW -> { val uri = intent.data ?: return false - return navController.navWithUrl(uri.toString()) + return navigator?.navWithUrl(uri.toString()) ?: false } Intent.ACTION_SEND -> { @@ -220,10 +219,7 @@ class MainActivity : EhActivity() { if ("text/plain" == type) { val builder = ListUrlBuilder() builder.keyword = intent.getStringExtra(Intent.EXTRA_TEXT) - navController.navAnimated( - R.id.galleryListScene, - builder.toStartArgs(), - ) + navigator?.navigate(GalleryListScreenDestination(builder)) return true } else if (type != null && type.startsWith("image/")) { val uri = intent.getParcelableExtraCompat(Intent.EXTRA_STREAM) @@ -234,10 +230,7 @@ class MainActivity : EhActivity() { builder.mode = ListUrlBuilder.MODE_IMAGE_SEARCH builder.imagePath = temp.path builder.isUseSimilarityScan = true - navController.navAnimated( - R.id.galleryListScene, - builder.toStartArgs(), - ) + navigator?.navigate(GalleryListScreenDestination(builder)) return true } } @@ -246,7 +239,7 @@ class MainActivity : EhActivity() { DownloadService.ACTION_START_DOWNLOADSCENE -> { val args = intent.getBundleExtra(DownloadService.ACTION_START_DOWNLOADSCENE_ARGS) - navController.navAnimated(R.id.nav_downloads, args) + navigator?.navigate(DownloadScreenDestination) } } @@ -256,12 +249,11 @@ class MainActivity : EhActivity() { var drawerLocked by mutableStateOf(false) private var openDrawerFlow = MutableSharedFlow(extraBufferCapacity = 1) private var openSideSheetFlow = MutableSharedFlow(extraBufferCapacity = 1) - private var recomposeFlow = MutableSharedFlow(extraBufferCapacity = 1) - - fun recompose() { - recomposeFlow.tryEmit(Unit) - } + private var tipFlow = MutableSharedFlow(extraBufferCapacity = 1) + private var navigator: NavController? = null + private val isInitializedFlow = MutableStateFlow(false) + @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") override fun onCreate(savedInstanceState: Bundle?) { installSplashScreen() super.onCreate(savedInstanceState) @@ -270,8 +262,13 @@ class MainActivity : EhActivity() { val dialogState = LocalDialogState.current val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() - val recomposeScope = currentRecomposeScope - fun isSelected(id: Int) = ::navController.isInitialized && id == navController.currentDestination?.id + val navController = rememberNavController() + DisposableEffect(navController) { + navigator = navController + onDispose { + navigator = null + } + } fun closeDrawer(callback: () -> Unit = {}) = scope.launch { drawerState.close() callback() @@ -293,105 +290,94 @@ class MainActivity : EhActivity() { drawerState.open() } } + val snackbarState = remember { SnackbarHostState() } LaunchedEffect(Unit) { - recomposeFlow.collect { - recomposeScope.invalidate() + tipFlow.collectLatest { + snackbarState.showSnackbar(it) } } - LocalTouchSlopProvider(Settings.touchSlopFactor.toFloat()) { - ModalNavigationDrawer( - drawerContent = { - ModalDrawerSheet( - modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 56).dp), - windowInsets = WindowInsets(0, 0, 0, 0), - ) { - val scrollState = rememberScrollState() - Column( - modifier = Modifier.verticalScroll(scrollState).navigationBarsPadding(), + val currentDestination by navController.currentDestinationAsState() + Scaffold(snackbarHost = { SnackbarHost(snackbarState) }) { + LocalTouchSlopProvider(Settings.touchSlopFactor.toFloat()) { + ModalNavigationDrawer( + drawerContent = { + ModalDrawerSheet( + modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 56).dp), + windowInsets = WindowInsets(0, 0, 0, 0), ) { - Image( - painter = painterResource(id = R.drawable.sadpanda_low_poly), - contentDescription = null, - modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp), - contentScale = ContentScale.FillWidth, - ) - navItems.forEach { (id, stringId, icon) -> + val scrollState = rememberScrollState() + Column( + modifier = Modifier.verticalScroll(scrollState).navigationBarsPadding(), + ) { + Image( + painter = painterResource(id = R.drawable.sadpanda_low_poly), + contentDescription = null, + modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp), + contentScale = ContentScale.FillWidth, + ) + navItems.forEach { (direction, stringId, icon) -> + NavigationDrawerItem( + label = { + Text(text = stringResource(id = stringId)) + }, + selected = currentDestination === direction, + onClick = { + navController.navigate(direction.route) + closeDrawer() + }, + modifier = Modifier.padding(horizontal = 12.dp), + icon = { + Icon(imageVector = icon, contentDescription = null) + }, + ) + } NavigationDrawerItem( label = { - Text(text = stringResource(id = stringId)) + Text(text = stringResource(id = R.string.settings)) }, - selected = isSelected(id), + selected = false, onClick = { - if (id == R.id.nav_settings) { - closeDrawer { - onNavDestinationSelected2(id, navController) - } - } else { - closeDrawer() - onNavDestinationSelected2(id, navController) - } + closeDrawer { startActivity(Intent(applicationContext, ConfigureActivity::class.java)) } }, modifier = Modifier.padding(horizontal = 12.dp), icon = { - Icon(imageVector = icon, contentDescription = null) + Icon(imageVector = Icons.Default.Settings, contentDescription = null) }, ) } } - } - }, - drawerState = drawerState, - gesturesEnabled = !drawerLocked || drawerState.isOpen, - ) { - val sheet = sideSheet.firstOrNull() - val sideDrawerState = rememberDrawerState(DrawerValue.Closed) - LaunchedEffect(Unit) { - openSideSheetFlow.collectLatest { - sideDrawerState.open() - } - } - SideDrawer( - drawerContent = { - if (sheet != null) { - ModalDrawerSheet( - modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 112).dp), - drawerShape = ShapeDefaults.Large.copy(topEnd = CornerSize(0), bottomEnd = CornerSize(0)), - windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.End), - ) { - sheet(sideDrawerState) - } - } }, - drawerState = sideDrawerState, - gesturesEnabled = sheet != null && !drawerLocked, + drawerState = drawerState, + gesturesEnabled = !drawerLocked || drawerState.isOpen, ) { - val insets = buildWindowInsets { - set( - WindowInsetsCompat.Type.statusBars(), - WindowInsets.statusBars, - ) - set( - WindowInsetsCompat.Type.navigationBars(), - WindowInsets.navigationBars, - ) - set( - WindowInsetsCompat.Type.ime(), - WindowInsets.ime, - ) + val sheet = sideSheet.firstOrNull() + val sideDrawerState = rememberDrawerState(DrawerValue.Closed) + LaunchedEffect(Unit) { + openSideSheetFlow.collectLatest { + sideDrawerState.open() + } } - AndroidViewBinding(factory = { inflater, parent, attachToParent -> - ActivityMainBinding.inflate(inflater, parent, attachToParent).apply { - val navHostFragment = fragmentContainer.getFragment() - navController = navHostFragment.navController.apply { - graph = navInflater.inflate(R.navigation.nav_graph).apply { - check(launchPage in 0..3) - setStartDestination(navItems[launchPage].first) + SideDrawer( + drawerContent = { + if (sheet != null) { + ModalDrawerSheet( + modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 112).dp), + drawerShape = ShapeDefaults.Large.copy(topEnd = CornerSize(0), bottomEnd = CornerSize(0)), + windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.End), + ) { + sheet(sideDrawerState) } } - isInitializedFlow.value = true - } - }) { - ViewCompat.dispatchApplyWindowInsets(root, insets) + }, + drawerState = sideDrawerState, + gesturesEnabled = sheet != null && !drawerLocked, + ) { + DestinationsNavHost( + navGraph = NavGraphs.root, + startRoute = navItems[Settings.launchPage].first, + engine = rememberNavHostEngine(rootDefaultAnimations = RootNavGraphDefaultAnimations.ACCOMPANIST_FADING), + navController = navController, + ) } } } @@ -469,7 +455,7 @@ class MainActivity : EhActivity() { if (connectivityManager.isActiveNetworkMetered) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Snackbar.make( - findViewById(R.id.fragment_container), + findViewById(R.id.content), R.string.metered_network_warning, Snackbar.LENGTH_LONG, ) @@ -504,25 +490,16 @@ class MainActivity : EhActivity() { val result1 = GalleryDetailUrlParser.parse(text, false) var launch: (() -> Unit)? = null if (result1 != null) { - launch = { - navController.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to TokenArgs(result1.gid, result1.token)), - ) - } + launch = { navigator?.navigate(GalleryDetailScreenDestination(TokenArgs(result1.gid, result1.token))) } } val result2 = GalleryPageUrlParser.parse(text, false) if (result2 != null) { - val args = Bundle() - args.putLong(ProgressFragment.KEY_GID, result2.gid) - args.putString(ProgressFragment.KEY_PTOKEN, result2.pToken) - args.putInt(ProgressFragment.KEY_PAGE, result2.page) - launch = { navController.navAnimated(R.id.progressScene, args) } + launch = { navigator?.navigate(ProgressScreenDestination(result2.gid, result2.pToken, result2.page)) } } launch?.let { withUIContext { val snackbar = Snackbar.make( - findViewById(R.id.fragment_container), + findViewById(R.id.content), R.string.clipboard_gallery_url_snack_message, Snackbar.LENGTH_SHORT, ) @@ -548,22 +525,9 @@ class MainActivity : EhActivity() { showTip(getString(id), length, useToast) } - /** - * If activity is running, show snack bar, otherwise show toast - */ fun showTip(message: CharSequence, length: Int, useToast: Boolean = false) { - if (!useToast) { - Snackbar.make( - findViewById(R.id.fragment_container), - message, - if (length == BaseScene.LENGTH_LONG) Snackbar.LENGTH_LONG else Snackbar.LENGTH_SHORT, - ).show() - } else { - Toast.makeText( - this, - message, - if (length == BaseScene.LENGTH_LONG) Toast.LENGTH_LONG else Toast.LENGTH_SHORT, - ).show() + if (useToast || tipFlow.tryEmit(message.toString())) { + Toast.makeText(this, message, if (length == BaseScene.LENGTH_LONG) Toast.LENGTH_LONG else Toast.LENGTH_SHORT).show() } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt index 3da9e0e4e..b746e4614 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt @@ -1,5 +1,6 @@ package com.hippo.ehviewer.ui.main +import android.content.Intent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -38,13 +39,12 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.core.os.bundleOf -import androidx.navigation.NavController import androidx.paging.LoadState import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.itemContentType @@ -59,7 +59,6 @@ import com.hippo.ehviewer.icons.EhIcons import com.hippo.ehviewer.icons.big.SadAndroid import com.hippo.ehviewer.ui.WebViewActivity import com.hippo.ehviewer.ui.scene.collectDetailSizeAsState -import com.hippo.ehviewer.ui.scene.navAnimated import com.hippo.ehviewer.ui.tools.FastScrollLazyVerticalGrid import com.hippo.ehviewer.ui.tools.FastScrollLazyVerticalStaggeredGrid import com.hippo.ehviewer.ui.tools.LocalDialogState @@ -80,8 +79,8 @@ fun GalleryList( refreshState: PullToRefreshState, onRefresh: suspend CoroutineScope.() -> Unit, onLoading: suspend CoroutineScope.() -> Unit, - navigator: NavController, ) { + val context = LocalContext.current val layoutDirection = LocalLayoutDirection.current val marginH = dimensionResource(id = R.dimen.gallery_list_margin_h) val marginV = dimensionResource(id = R.dimen.gallery_list_margin_v) @@ -205,7 +204,11 @@ fun GalleryList( dialogState.awaitPermissionOrCancel(title = R.string.cloudflare_bypass_failed) { Text(text = stringResource(id = R.string.open_in_webview)) } - navigator.navAnimated(R.id.webView, bundleOf(WebViewActivity.KEY_URL to EhUrl.host)) + context.startActivity( + Intent(context, WebViewActivity::class.java).apply { + putExtra(WebViewActivity.KEY_URL, EhUrl.host) + }, + ) } } Box( diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/BaseScene.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/BaseScene.kt index 9bde55d23..0d9f5931a 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/BaseScene.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/BaseScene.kt @@ -1,53 +1,6 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package com.hippo.ehviewer.ui.scene -import android.content.res.Resources.Theme -import android.os.Bundle -import android.view.View -import androidx.core.view.SoftwareKeyboardControllerCompat -import androidx.fragment.app.Fragment -import com.hippo.ehviewer.ui.MainActivity -import rikka.core.res.resolveDrawable - -abstract class BaseScene : Fragment() { - open val enableDrawerGestures = false - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - view.background = requireActivity().theme.resolveDrawable(android.R.attr.windowBackground) - - // Update left drawer locked state - mainActivity?.drawerLocked = !enableDrawerGestures - hideSoftInput() - mainActivity?.recompose() - } - - private val mainActivity: MainActivity? - get() = activity as? MainActivity - - private fun hideSoftInput() = activity?.window?.decorView?.run { - SoftwareKeyboardControllerCompat(this) - }?.hide() - - val theme: Theme - get() = requireActivity().theme - - companion object { - const val LENGTH_SHORT = 0 - const val LENGTH_LONG = 1 - } +object BaseScene { + const val LENGTH_SHORT = 0 + const val LENGTH_LONG = 1 } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/DownloadsFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/DownloadsFragment.kt index fbfb3d745..3e07b0459 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/DownloadsFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/DownloadsFragment.kt @@ -1,10 +1,6 @@ package com.hippo.ehviewer.ui.scene import android.content.Intent -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.Image import androidx.compose.foundation.clickable @@ -71,9 +67,6 @@ import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import com.hippo.ehviewer.EhDB import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings @@ -84,6 +77,7 @@ import com.hippo.ehviewer.icons.EhIcons import com.hippo.ehviewer.icons.big.Download import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.ui.confirmRemoveDownloadRange +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination import com.hippo.ehviewer.ui.main.DownloadCard import com.hippo.ehviewer.ui.main.FabLayout import com.hippo.ehviewer.ui.navToReader @@ -98,6 +92,7 @@ import com.hippo.ehviewer.util.containsIgnoreCase import com.hippo.ehviewer.util.findActivity import com.hippo.ehviewer.util.mapToLongArray import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.withNonCancellableContext import kotlin.math.roundToInt @@ -109,7 +104,7 @@ import sh.calvin.reorderable.rememberReorderableLazyColumnState @Destination @Composable -fun DownloadsScreen(navigator: NavController) { +fun DownloadsScreen(navigator: DestinationsNavigator) { var label by rememberSaveable { mutableStateOf(null) } var keyword by rememberSaveable { mutableStateOf(null) } var filterType by rememberSaveable { mutableStateOf(-1) } @@ -436,10 +431,7 @@ fun DownloadsScreen(navigator: NavController) { } }, onThumbClick = { - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to GalleryInfoArgs(info.galleryInfo)), - ) + navigator.navigate(GalleryDetailScreenDestination(GalleryInfoArgs(info.galleryInfo))) }, onLongClick = { checkedInfoMap[info.gid] = info @@ -521,16 +513,7 @@ fun DownloadsScreen(navigator: NavController) { } } -class DownloadsFragment : BaseScene() { - override val enableDrawerGestures = true - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val navController = findNavController() - return ComposeWithMD3 { - DownloadsScreen(navController) - } - } - +class DownloadsFragment { companion object { const val KEY_GID = "gid" const val KEY_ACTION = "action" diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/FavoritesFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/FavoritesFragment.kt index 9c2f7db50..ca75f5544 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/FavoritesFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/FavoritesFragment.kt @@ -1,9 +1,5 @@ package com.hippo.ehviewer.ui.scene -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets @@ -49,10 +45,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.core.os.bundleOf import androidx.lifecycle.viewModelScope -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import androidx.paging.LoadState import androidx.paging.Pager import androidx.paging.PagingConfig @@ -76,6 +69,7 @@ import com.hippo.ehviewer.collectAsState import com.hippo.ehviewer.icons.EhIcons import com.hippo.ehviewer.icons.filled.GoTo import com.hippo.ehviewer.ui.MainActivity +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination import com.hippo.ehviewer.ui.main.FabLayout import com.hippo.ehviewer.ui.main.GalleryInfoGridItem import com.hippo.ehviewer.ui.main.GalleryInfoListItem @@ -86,6 +80,7 @@ import com.hippo.ehviewer.ui.tools.rememberInVM import com.hippo.ehviewer.util.findActivity import com.hippo.ehviewer.util.mapToLongArray import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.withIOContext import java.time.Instant import java.time.LocalDateTime @@ -100,7 +95,7 @@ import moe.tarsin.coroutines.runSuspendCatching @Destination @Composable -fun FavouritesScreen(navigator: NavController) { +fun FavouritesScreen(navigator: DestinationsNavigator) { // Meta State var urlBuilder by rememberSaveable { mutableStateOf(FavListUrlBuilder(favCat = Settings.recentFavCat)) } var searchBarOffsetY by remember { mutableStateOf(0) } @@ -276,10 +271,7 @@ fun FavouritesScreen(navigator: NavController) { checkedInfoMap[info.gid] = info } } else { - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to GalleryInfoArgs(info)), - ) + navigator.navigate(GalleryDetailScreenDestination(GalleryInfoArgs(info))) } }, onLongClick = { @@ -305,10 +297,7 @@ fun FavouritesScreen(navigator: NavController) { checkedInfoMap[info.gid] = info } } else { - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to GalleryInfoArgs(info)), - ) + navigator.navigate(GalleryDetailScreenDestination(GalleryInfoArgs(info))) } }, onLongClick = { @@ -322,7 +311,6 @@ fun FavouritesScreen(navigator: NavController) { refreshState = refreshState, onRefresh = { refresh() }, onLoading = { searchBarOffsetY = 0 }, - navigator = navigator, ) } @@ -427,14 +415,3 @@ fun FavouritesScreen(navigator: NavController) { } } } - -class FavoritesFragment : BaseScene() { - override val enableDrawerGestures = true - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - return ComposeWithMD3 { - val navController = remember { findNavController() } - FavouritesScreen(navController) - } - } -} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryCommentsFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryCommentsFragment.kt index 233fa2269..e16fad505 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryCommentsFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryCommentsFragment.kt @@ -3,14 +3,10 @@ package com.hippo.ehviewer.ui.scene import android.annotation.SuppressLint import android.content.Context import android.graphics.Typeface -import android.os.Bundle import android.text.SpannableStringBuilder import android.text.style.ForegroundColorSpan import android.text.style.RelativeSizeSpan import android.text.style.StyleSpan -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import android.widget.TextView import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement @@ -79,8 +75,6 @@ import androidx.compose.ui.unit.max import androidx.compose.ui.util.lerp import androidx.core.text.inSpans import androidx.core.text.parseAsHtml -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import com.hippo.ehviewer.R import com.hippo.ehviewer.client.EhEngine import com.hippo.ehviewer.client.EhFilter.remember @@ -91,11 +85,11 @@ import com.hippo.ehviewer.client.data.ListUrlBuilder import com.hippo.ehviewer.dao.Filter import com.hippo.ehviewer.dao.FilterMode import com.hippo.ehviewer.ui.MainActivity +import com.hippo.ehviewer.ui.destinations.GalleryListScreenDestination import com.hippo.ehviewer.ui.jumpToReaderByPage import com.hippo.ehviewer.ui.legacy.CoilImageGetter import com.hippo.ehviewer.ui.main.GalleryCommentCard import com.hippo.ehviewer.ui.openBrowser -import com.hippo.ehviewer.ui.scene.GalleryListFragment.Companion.toStartArgs import com.hippo.ehviewer.ui.tools.LocalDialogState import com.hippo.ehviewer.ui.tools.animateFloatMergePredictiveBackAsState import com.hippo.ehviewer.ui.tools.normalizeSpan @@ -108,8 +102,8 @@ import com.hippo.ehviewer.util.ReadableTime import com.hippo.ehviewer.util.TextUrl import com.hippo.ehviewer.util.addTextToClipboard import com.hippo.ehviewer.util.findActivity -import com.hippo.ehviewer.util.getParcelableCompat import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext @@ -157,7 +151,7 @@ private val MinimumContentPaddingEditText = 88.dp @Destination @Composable -fun GalleryCommentsScreen(galleryDetail: GalleryDetail, navigator: NavController) { +fun GalleryCommentsScreen(galleryDetail: GalleryDetail, navigator: DestinationsNavigator) { val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val dialogState = LocalDialogState.current val coroutineScope = rememberCoroutineScope() @@ -374,7 +368,7 @@ fun GalleryCommentsScreen(galleryDetail: GalleryDetail, navigator: NavController mode = ListUrlBuilder.MODE_UPLOADER, mKeyword = item.user, ) - navigator.navAnimated(R.id.galleryListScene, lub.toStartArgs(), true) + navigator.navigate(GalleryListScreenDestination(lub)) }, onCardClick = { coroutineScope.launch { @@ -480,21 +474,3 @@ fun GalleryCommentsScreen(galleryDetail: GalleryDetail, navigator: NavController } } } - -class GalleryCommentsFragment : BaseScene() { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - return ComposeWithMD3 { - val galleryDetail = remember { requireArguments().getParcelableCompat(KEY_GALLERY_DETAIL)!! } - val navController = remember { findNavController() } - GalleryCommentsScreen(galleryDetail = galleryDetail, navigator = navController) - } - } - - companion object { - const val KEY_GALLERY_DETAIL = "gallery_detail" - } -} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryDetailFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryDetailFragment.kt index 64a1aedcc..25303bbdf 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryDetailFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryDetailFragment.kt @@ -5,13 +5,10 @@ import android.app.Dialog import android.app.DownloadManager import android.content.DialogInterface import android.net.Uri -import android.os.Bundle import android.os.Environment import android.os.Parcelable import android.text.TextUtils.TruncateAt.END -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.widget.ArrayAdapter import androidx.annotation.StringRes import androidx.compose.foundation.clickable @@ -22,6 +19,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -51,6 +49,7 @@ import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -77,10 +76,7 @@ import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.core.os.bundleOf import androidx.core.text.parseAsHtml -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import arrow.core.partially1 import coil.imageLoader import com.google.android.material.snackbar.Snackbar @@ -125,6 +121,10 @@ import com.hippo.ehviewer.spider.SpiderQueen.Companion.MODE_READ import com.hippo.ehviewer.ui.GalleryInfoBottomSheet import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.ui.confirmRemoveDownload +import com.hippo.ehviewer.ui.destinations.GalleryCommentsScreenDestination +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination +import com.hippo.ehviewer.ui.destinations.GalleryListScreenDestination +import com.hippo.ehviewer.ui.destinations.GalleryPreviewScreenDestination import com.hippo.ehviewer.ui.getFavoriteIcon import com.hippo.ehviewer.ui.jumpToReaderByPage import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder @@ -138,7 +138,6 @@ import com.hippo.ehviewer.ui.main.GalleryTags import com.hippo.ehviewer.ui.modifyFavorites import com.hippo.ehviewer.ui.navToReader import com.hippo.ehviewer.ui.openBrowser -import com.hippo.ehviewer.ui.scene.GalleryListFragment.Companion.toStartArgs import com.hippo.ehviewer.ui.startDownload import com.hippo.ehviewer.ui.tools.CrystalCard import com.hippo.ehviewer.ui.tools.FilledTertiaryIconButton @@ -152,10 +151,10 @@ import com.hippo.ehviewer.util.FavouriteStatusRouter import com.hippo.ehviewer.util.FileUtils import com.hippo.ehviewer.util.addTextToClipboard import com.hippo.ehviewer.util.findActivity -import com.hippo.ehviewer.util.getParcelableCompat import com.hippo.ehviewer.util.isAtLeastQ import com.hippo.ehviewer.util.requestPermission import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.withIOContext @@ -215,7 +214,7 @@ private fun List.getArtist(): String? { @Destination @Composable -fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) { +fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: DestinationsNavigator) { var galleryInfo by rememberSaveable { val casted = args as? GalleryInfoArgs mutableStateOf(casted?.galleryInfo) @@ -234,7 +233,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) val gi = galleryInfo if (page != 0 && gi != null) { Snackbar.make( - activity.findViewById(R.id.fragment_container), + activity.findViewById(R.id.content), context.getString(R.string.read_from, page), Snackbar.LENGTH_LONG, ).setAction(R.string.read) { context.navToReader(gi.findBaseInfo(), page) }.show() @@ -430,13 +429,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) fun navigateToPreview(nextPage: Boolean = false) { (galleryInfo as? GalleryDetail)?.let { - navigator.navAnimated( - R.id.galleryPreviewsScene, - bundleOf( - KEY_GALLERY_DETAIL to it, - KEY_NEXT_PAGE to nextPage, - ), - ) + navigator.navigate(GalleryPreviewScreenDestination(it, nextPage)) } } @@ -489,10 +482,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) else -> stringResource(R.string.more_comment) } fun onNavigateToCommentScene() { - navigator.navAnimated( - R.id.galleryCommentsScene, - bundleOf(GalleryCommentsFragment.KEY_GALLERY_DETAIL to galleryDetail), - ) + navigator.navigate(GalleryCommentsScreenDestination(galleryDetail)) } CrystalCard { commentsList.take(maxShowCount).forEach { item -> @@ -533,10 +523,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) it.title, it.posted, ) to { - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to TokenArgs(it.gid, it.token!!)), - ) + navigator.navigate(GalleryDetailScreenDestination(TokenArgs(it.gid, it.token!!))) } }.toTypedArray() val navAction = dialogState.showSelectItem(*items) @@ -610,31 +597,31 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) val keyword = EhUtils.extractTitle(galleryDetail.title) val artist = galleryDetail.tags.getArtist() if (null != keyword) { - navigator.navAnimated( - R.id.galleryListScene, - ListUrlBuilder( - mode = ListUrlBuilder.MODE_NORMAL, - mKeyword = "\"" + keyword + "\"", - ).toStartArgs(), - true, + navigator.navigate( + GalleryListScreenDestination( + ListUrlBuilder( + mode = ListUrlBuilder.MODE_NORMAL, + mKeyword = "\"" + keyword + "\"", + ), + ), ) } else if (artist != null) { - navigator.navAnimated( - R.id.galleryListScene, - ListUrlBuilder( - mode = ListUrlBuilder.MODE_TAG, - mKeyword = "artist:$artist", - ).toStartArgs(), - true, + navigator.navigate( + GalleryListScreenDestination( + ListUrlBuilder( + mode = ListUrlBuilder.MODE_TAG, + mKeyword = "artist:$artist", + ), + ), ) } else if (null != galleryDetail.uploader) { - navigator.navAnimated( - R.id.galleryListScene, - ListUrlBuilder( - mode = ListUrlBuilder.MODE_UPLOADER, - mKeyword = galleryDetail.uploader, - ).toStartArgs(), - true, + navigator.navigate( + GalleryListScreenDestination( + ListUrlBuilder( + mode = ListUrlBuilder.MODE_UPLOADER, + mKeyword = galleryDetail.uploader, + ), + ), ) } }, @@ -644,12 +631,13 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) text = stringResource(id = R.string.search_cover), onClick = { val key = galleryDetail.thumbKey.orEmpty() - navigator.navAnimated( - R.id.galleryListScene, - ListUrlBuilder( - mode = ListUrlBuilder.MODE_NORMAL, - hash = key.substringAfterLast('/').substringBefore('-'), - ).toStartArgs(), + navigator.navigate( + GalleryListScreenDestination( + ListUrlBuilder( + mode = ListUrlBuilder.MODE_NORMAL, + hash = key.substringAfterLast('/').substringBefore('-'), + ), + ), ) }, ) @@ -851,7 +839,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) val lub = ListUrlBuilder() lub.mode = ListUrlBuilder.MODE_TAG lub.keyword = it - navigator.navAnimated(R.id.galleryListScene, lub.toStartArgs(), true) + navigator.navigate(GalleryListScreenDestination(lub)) }, onTagLongClick = { translated, tag -> val index = tag.indexOf(':') @@ -943,7 +931,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) return } val lub = ListUrlBuilder(category = category) - navigator.navAnimated(R.id.galleryListScene, lub.toStartArgs(), true) + navigator.navigate(GalleryListScreenDestination(lub)) } fun onUploaderChipClick() { val uploader = galleryInfo.uploader @@ -954,12 +942,24 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) val lub = ListUrlBuilder() lub.mode = ListUrlBuilder.MODE_UPLOADER lub.keyword = uploader - navigator.navAnimated(R.id.galleryListScene, lub.toStartArgs(), true) + navigator.navigate(GalleryListScreenDestination(lub)) } + + var showBottomSheet by remember { mutableStateOf(false) } + + if (showBottomSheet && galleryDetail != null) { + ModalBottomSheet( + onDismissRequest = { showBottomSheet = false }, + windowInsets = WindowInsets(0, 0, 0, 0), + ) { + GalleryInfoBottomSheet(galleryDetail, navigator) + } + } + fun onGalleryInfoCardClick() { - galleryDetail ?: return - GalleryInfoBottomSheet(galleryDetail).show(activity.supportFragmentManager, "GalleryInfoBottomSheet") + showBottomSheet = true } + fun showFilterUploaderDialog() { val uploader = galleryInfo.uploader val disowned = uploader == "(Disowned)" @@ -1232,18 +1232,3 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: NavController) } } } - -class GalleryDetailFragment : BaseScene() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val args = requireNotNull(arguments) - val composeArgs = requireNotNull(args.getParcelableCompat(KEY_ARGS)) - return ComposeWithMD3 { - val navigator = remember { findNavController() } - GalleryDetailScreen(composeArgs, navigator) - } - } - - companion object { - const val KEY_ARGS = "args" - } -} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryListFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryListFragment.kt index 62d93f30c..8017aa24b 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryListFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryListFragment.kt @@ -2,11 +2,7 @@ package com.hippo.ehviewer.ui.scene import android.graphics.Bitmap import android.net.Uri -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View import android.view.ViewConfiguration -import android.view.ViewGroup import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateDpAsState @@ -93,10 +89,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastAny import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.lerp -import androidx.core.os.bundleOf import androidx.lifecycle.viewModelScope -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import androidx.paging.LoadState import androidx.paging.Pager import androidx.paging.PagingConfig @@ -133,6 +126,9 @@ import com.hippo.ehviewer.icons.EhIcons import com.hippo.ehviewer.icons.filled.GoTo import com.hippo.ehviewer.image.Image.Companion.decodeBitmap import com.hippo.ehviewer.ui.MainActivity +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination +import com.hippo.ehviewer.ui.destinations.GalleryListScreenDestination +import com.hippo.ehviewer.ui.destinations.ProgressScreenDestination import com.hippo.ehviewer.ui.doGalleryInfoAction import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder import com.hippo.ehviewer.ui.main.AdvancedSearchOption @@ -144,7 +140,6 @@ import com.hippo.ehviewer.ui.main.GalleryList import com.hippo.ehviewer.ui.main.ImageSearch import com.hippo.ehviewer.ui.main.NormalSearch import com.hippo.ehviewer.ui.main.SearchAdvanced -import com.hippo.ehviewer.ui.scene.GalleryListFragment.Companion.toStartArgs import com.hippo.ehviewer.ui.tools.Deferred import com.hippo.ehviewer.ui.tools.DragHandle import com.hippo.ehviewer.ui.tools.LocalDialogState @@ -155,9 +150,10 @@ import com.hippo.ehviewer.ui.tools.observed import com.hippo.ehviewer.ui.tools.rememberInVM import com.hippo.ehviewer.util.AppConfig import com.hippo.ehviewer.util.findActivity -import com.hippo.ehviewer.util.getParcelableCompat import com.hippo.ehviewer.util.pickVisualMedia import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator +import com.ramcosta.composedestinations.spec.Direction import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext @@ -177,7 +173,27 @@ import sh.calvin.reorderable.rememberReorderableLazyColumnState @Destination @Composable -fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { +fun HomePageScreen(navigator: DestinationsNavigator) = + GalleryListScreen(ListUrlBuilder(), navigator) + +@Destination +@Composable +fun SubscriptionScreen(navigator: DestinationsNavigator) = + GalleryListScreen(ListUrlBuilder(MODE_SUBSCRIPTION), navigator) + +@Destination +@Composable +fun WhatshotScreen(navigator: DestinationsNavigator) = + GalleryListScreen(ListUrlBuilder(MODE_WHATS_HOT), navigator) + +@Destination +@Composable +fun ToplistScreen(navigator: DestinationsNavigator) = + GalleryListScreen(ListUrlBuilder(MODE_TOPLIST, mKeyword = Settings.recentToplist), navigator) + +@Destination +@Composable +fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) { val searchFieldState = rememberTextFieldState() var urlBuilder by rememberSaveable(lub) { mutableStateOf(lub) } var searchBarOffsetY by remember { mutableStateOf(0) } @@ -453,7 +469,7 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { ListItem( modifier = Modifier.clickable { if (urlBuilder.mode == MODE_WHATS_HOT) { - navigator.navAnimated(R.id.galleryListScene, ListUrlBuilder(item).toStartArgs()) + navigator.navigate(GalleryListScreenDestination(ListUrlBuilder(item))) } else { urlBuilder = ListUrlBuilder(item) data.refresh() @@ -513,19 +529,17 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { override val keyword = openGalleryKeyword override val canOpenDirectly = true override fun onClick() { - navigator.navAnimated(destination, args) + navigator.navigate(destination) showSearchLayout = false } - abstract val destination: Int - abstract val args: Bundle + abstract val destination: Direction } class GalleryDetailUrlSuggestion( gid: Long, token: String, ) : UrlSuggestion() { - override val destination = R.id.galleryDetailScene - override val args = bundleOf(GalleryDetailFragment.KEY_ARGS to TokenArgs(gid, token)) + override val destination = GalleryDetailScreenDestination(TokenArgs(gid, token)) } class GalleryPageUrlSuggestion( @@ -533,12 +547,7 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { pToken: String, page: Int, ) : UrlSuggestion() { - override val destination = R.id.progressScene - override val args = bundleOf( - ProgressFragment.KEY_GID to gid, - ProgressFragment.KEY_PTOKEN to pToken, - ProgressFragment.KEY_PAGE to page, - ) + override val destination = ProgressScreenDestination(gid, pToken, page) } var expanded by remember { mutableStateOf(false) } @@ -603,7 +612,7 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { MODE_TOPLIST, MODE_WHATS_HOT -> { // Wait for search view to hide delay(300) - withUIContext { navigator.navAnimated(R.id.galleryListScene, builder.toStartArgs()) } + withUIContext { navigator.navigate(GalleryListScreenDestination(builder)) } } else -> { urlBuilder = builder @@ -754,10 +763,7 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { detailItemContent = { info -> GalleryInfoListItem( onClick = { - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to GalleryInfoArgs(info)), - ) + navigator.navigate(GalleryDetailScreenDestination(GalleryInfoArgs(info))) }, onLongClick = { coroutineScope.launch { @@ -774,10 +780,7 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { thumbItemContent = { info -> GalleryInfoGridItem( onClick = { - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to GalleryInfoArgs(info)), - ) + navigator.navigate(GalleryDetailScreenDestination(GalleryInfoArgs(info))) }, onLongClick = { coroutineScope.launch { @@ -793,7 +796,6 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { data.refresh() }, onLoading = { searchBarOffsetY = 0 }, - navigator = navigator, ) } @@ -865,37 +867,6 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: NavController) { } } -class GalleryListFragment : BaseScene() { - override val enableDrawerGestures = true - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val navController = findNavController() - val args = when (arguments?.getString(KEY_ACTION) ?: ACTION_HOMEPAGE) { - ACTION_HOMEPAGE -> ListUrlBuilder() - ACTION_SUBSCRIPTION -> ListUrlBuilder(MODE_SUBSCRIPTION) - ACTION_WHATS_HOT -> ListUrlBuilder(MODE_WHATS_HOT) - ACTION_TOP_LIST -> ListUrlBuilder(MODE_TOPLIST, mKeyword = Settings.recentToplist) - ACTION_LIST_URL_BUILDER -> arguments?.getParcelableCompat(KEY_LIST_URL_BUILDER)?.copy() ?: ListUrlBuilder() - else -> error("Wrong KEY_ACTION:${arguments?.getString(KEY_ACTION)} when handle args!") - } - return ComposeWithMD3 { GalleryListScreen(args, navController) } - } - - companion object { - const val KEY_ACTION = "action" - const val ACTION_HOMEPAGE = "action_homepage" - const val ACTION_SUBSCRIPTION = "action_subscription" - const val ACTION_WHATS_HOT = "action_whats_hot" - const val ACTION_TOP_LIST = "action_top_list" - const val ACTION_LIST_URL_BUILDER = "action_list_url_builder" - const val KEY_LIST_URL_BUILDER = "list_url_builder" - fun ListUrlBuilder.toStartArgs() = bundleOf( - KEY_ACTION to ACTION_LIST_URL_BUILDER, - KEY_LIST_URL_BUILDER to this, - ) - } -} - private const val TOPLIST_PAGES = 200 @Composable diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryPreviewFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryPreviewFragment.kt index 70d89857c..f580f3361 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryPreviewFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/GalleryPreviewFragment.kt @@ -1,9 +1,5 @@ package com.hippo.ehviewer.ui.scene -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells @@ -20,7 +16,6 @@ import androidx.compose.runtime.Composable 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.saveable.rememberSaveable import androidx.compose.runtime.setValue @@ -30,10 +25,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.fragment.app.Fragment import androidx.lifecycle.viewModelScope import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingSource @@ -56,13 +49,10 @@ import com.hippo.ehviewer.client.data.GalleryPreview import com.hippo.ehviewer.coil.justDownload import com.hippo.ehviewer.collectAsState import com.hippo.ehviewer.ktbuilder.imageRequest -import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.ui.main.EhPreviewItem import com.hippo.ehviewer.ui.navToReader import com.hippo.ehviewer.ui.tools.FastScrollLazyVerticalGrid import com.hippo.ehviewer.ui.tools.rememberInVM -import com.hippo.ehviewer.util.findActivity -import com.hippo.ehviewer.util.getParcelableCompat import com.ramcosta.composedestinations.annotation.Destination import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -157,22 +147,3 @@ fun GalleryPreviewScreen(galleryDetail: GalleryDetail, toNextPageArg: Boolean, n } } } - -class GalleryPreviewFragment : Fragment() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - return ComposeWithMD3 { - val galleryDetail = remember { requireArguments().getParcelableCompat(KEY_GALLERY_DETAIL)!! } - val toNextPage = remember { requireArguments().getBoolean(KEY_NEXT_PAGE) } - val navController = remember { findNavController() } - GalleryPreviewScreen(galleryDetail, toNextPage, navController) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - requireContext().findActivity().recompose() - } -} - -const val KEY_GALLERY_DETAIL = "gallery_detail" -const val KEY_NEXT_PAGE = "next_page" diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/HistoryFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/HistoryFragment.kt index 17a55c050..231d65ce9 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/HistoryFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/HistoryFragment.kt @@ -1,9 +1,5 @@ package com.hippo.ehviewer.ui.scene -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -27,7 +23,6 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberDismissState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -36,10 +31,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.core.os.bundleOf import androidx.lifecycle.viewModelScope -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.cachedIn @@ -51,6 +43,7 @@ import com.hippo.ehviewer.R import com.hippo.ehviewer.icons.EhIcons import com.hippo.ehviewer.icons.big.History import com.hippo.ehviewer.ui.MainActivity +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination import com.hippo.ehviewer.ui.doGalleryInfoAction import com.hippo.ehviewer.ui.main.GalleryInfoListItem import com.hippo.ehviewer.ui.tools.Deferred @@ -60,12 +53,13 @@ import com.hippo.ehviewer.ui.tools.SwipeToDismissBox2 import com.hippo.ehviewer.ui.tools.rememberInVM import com.hippo.ehviewer.util.findActivity import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchIO import kotlinx.coroutines.delay @Destination @Composable -fun HistoryScreen(navigator: NavController) { +fun HistoryScreen(navigator: DestinationsNavigator) { val context = LocalContext.current val dialogState = LocalDialogState.current val coroutineScope = rememberCoroutineScope() @@ -133,10 +127,7 @@ fun HistoryScreen(navigator: NavController) { ) { GalleryInfoListItem( onClick = { - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to GalleryInfoArgs(info)), - ) + navigator.navigate(GalleryDetailScreenDestination(GalleryInfoArgs(info))) }, onLongClick = { coroutineScope.launchIO { @@ -173,14 +164,3 @@ fun HistoryScreen(navigator: NavController) { } } } - -class HistoryFragment : BaseScene() { - override val enableDrawerGestures = true - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - return ComposeWithMD3 { - val navController = remember { findNavController() } - HistoryScreen(navController) - } - } -} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/MainNav.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/MainNav.kt index f5a0438a2..9d8daad74 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/MainNav.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/MainNav.kt @@ -1,65 +1,55 @@ package com.hippo.ehviewer.ui.scene -import android.annotation.SuppressLint -import android.os.Bundle import androidx.annotation.MainThread -import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment import androidx.navigation.NavController -import androidx.navigation.NavOptions -import androidx.navigation.fragment.findNavController -import com.hippo.ehviewer.R import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser import com.hippo.ehviewer.client.parser.GalleryListUrlParser import com.hippo.ehviewer.client.parser.GalleryPageUrlParser +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination +import com.hippo.ehviewer.ui.destinations.GalleryListScreenDestination +import com.hippo.ehviewer.ui.destinations.ProgressScreenDestination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator +import com.ramcosta.composedestinations.spec.Direction @MainThread -@SuppressLint("PrivateResource") -fun NavController.navAnimated(id: Int, args: Bundle?, singleTop: Boolean = false) { - val options: NavOptions = NavOptions.Builder().setLaunchSingleTop(singleTop) - .setEnterAnim(androidx.fragment.R.animator.fragment_open_enter) - .setExitAnim(androidx.fragment.R.animator.fragment_open_exit) - .setPopEnterAnim(androidx.fragment.R.animator.fragment_close_enter) - .setPopExitAnim(androidx.fragment.R.animator.fragment_close_exit) - .build() - navigate(id, args, options) -} - -@MainThread -fun NavController.navWithUrl(url: String): Boolean { +fun DestinationsNavigator.navWithUrl(url: String): Boolean { if (url.isEmpty()) return false GalleryListUrlParser.parse(url)?.let { - navAnimated( - R.id.galleryListScene, - bundleOf( - GalleryListFragment.KEY_ACTION to GalleryListFragment.ACTION_LIST_URL_BUILDER, - GalleryListFragment.KEY_LIST_URL_BUILDER to it, - ), - ) + navigate(GalleryListScreenDestination(it)) return true } GalleryDetailUrlParser.parse(url)?.apply { - navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to TokenArgs(gid, token)), - ) + navigate(GalleryDetailScreenDestination(TokenArgs(gid, token))) return true } GalleryPageUrlParser.parse(url)?.apply { - navAnimated( - R.id.progressScene, - bundleOf( - ProgressFragment.KEY_GID to gid, - ProgressFragment.KEY_PTOKEN to pToken, - ProgressFragment.KEY_PAGE to page, - ), - ) + navigate(ProgressScreenDestination(gid, pToken, page)) return true } return false } @MainThread -fun Fragment.navAnimated(id: Int, args: Bundle?, singleTop: Boolean = false) = findNavController().navAnimated(id, args, singleTop) +fun NavController.navWithUrl(url: String): Boolean { + if (url.isEmpty()) return false + GalleryListUrlParser.parse(url)?.let { + navigate(GalleryListScreenDestination(it)) + return true + } + + GalleryDetailUrlParser.parse(url)?.apply { + navigate(GalleryDetailScreenDestination(TokenArgs(gid, token))) + return true + } + + GalleryPageUrlParser.parse(url)?.apply { + navigate(ProgressScreenDestination(gid, pToken, page)) + return true + } + return false +} + +@MainThread +fun NavController.navigate(direction: Direction) = navigate(direction.route) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/ProgressFragment.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/ProgressFragment.kt index 6515fcb18..2345dbdcb 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/ProgressFragment.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/ProgressFragment.kt @@ -1,9 +1,5 @@ package com.hippo.ehviewer.ui.scene -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -17,33 +13,31 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.core.os.bundleOf -import androidx.navigation.NavController -import androidx.navigation.fragment.findNavController import com.hippo.ehviewer.R import com.hippo.ehviewer.client.EhEngine import com.hippo.ehviewer.icons.EhIcons import com.hippo.ehviewer.icons.big.SadAndroid +import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination import com.hippo.ehviewer.util.ExceptionUtils import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.withUIContext import moe.tarsin.coroutines.runSuspendCatching @Destination @Composable -fun ProgressScreen(gid: Long, token: String, page: Int, navigator: NavController) { +fun ProgressScreen(gid: Long, token: String, page: Int, navigator: DestinationsNavigator) { val wrong = stringResource(id = R.string.error_something_wrong_happened) var error by rememberSaveable { mutableStateOf("") } LaunchedEffect(error) { if (error.isEmpty()) { - if (gid == -1L || token == ProgressFragment.INVALID || page == -1) { + if (gid == -1L || token == "invalid" || page == -1) { error = wrong } else { runSuspendCatching { @@ -51,10 +45,7 @@ fun ProgressScreen(gid: Long, token: String, page: Int, navigator: NavController }.onSuccess { withUIContext { navigator.popBackStack() - navigator.navAnimated( - R.id.galleryDetailScene, - bundleOf(GalleryDetailFragment.KEY_ARGS to TokenArgs(gid, it, page)), - ) + navigator.navigate(GalleryDetailScreenDestination(TokenArgs(gid, it, page))) } }.onFailure { error = ExceptionUtils.getReadableString(it) @@ -84,22 +75,3 @@ fun ProgressScreen(gid: Long, token: String, page: Int, navigator: NavController } } } - -class ProgressFragment : BaseScene() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - return ComposeWithMD3 { - val gid = remember { requireArguments().getLong(KEY_GID, -1) } - val token = remember { requireArguments().getString(KEY_PTOKEN, INVALID) } - val page = remember { requireArguments().getInt(KEY_PAGE, -1) } - val navController = remember { findNavController() } - ProgressScreen(gid, token, page, navController) - } - } - - companion object { - const val KEY_GID = "gid" - const val KEY_PTOKEN = "ptoken" - const val KEY_PAGE = "page" - const val INVALID = "invalid" - } -} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/SceneCompose.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/SceneCompose.kt deleted file mode 100644 index 12dec4ac4..000000000 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/scene/SceneCompose.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.hippo.ehviewer.ui.scene - -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.fragment.app.Fragment -import com.hippo.ehviewer.ui.setMD3Content - -@Suppress("FunctionName") -inline fun Fragment.ComposeWithMD3(crossinline content: @Composable () -> Unit) = ComposeView(requireContext()).apply { - consumeWindowInsets = false - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnLifecycleDestroyed(viewLifecycleOwner)) - setMD3Content(content) -} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 3017a4934..000000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml deleted file mode 100644 index 86289f7b7..000000000 --- a/app/src/main/res/navigation/nav_graph.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2fad53884..cee754929 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,7 +56,6 @@ androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", androidx-lifecycle-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" } -androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" } androidx-navigation-ui = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" } androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "androidx-paging" } @@ -134,7 +133,7 @@ splitties-systemservices = { module = "com.louiscad.splitties:splitties-systemse [bundles] accompanist = ["accompanist-themeadapter-material3", "accompanist-webview"] -androidx-navigation = ["androidx-navigation-compose", "androidx-navigation-fragment", "androidx-navigation-ui"] +androidx-navigation = ["androidx-navigation-compose", "androidx-navigation-ui"] androidx-paging = ["androidx-paging-compose", "androidx-paging-runtime"] androidx-recyclerview = ["androidx-recyclerview", "androidx-recyclerview-selection"] coil = ["coil-compose", "coil-gif"]