diff --git a/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt b/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt index 0065d047f..f820f426b 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt @@ -300,7 +300,8 @@ suspend fun DialogState.doGalleryInfoAction(info: BaseGalleryInfo, context: Cont 0 -> navToReader(info) 1 -> withUIContext { if (downloaded) { - if (confirmRemoveDownload(info)) DownloadManager.deleteDownload(info.gid) + confirmRemoveDownload(info) + DownloadManager.deleteDownload(info.gid) } else { CommonOperations.startDownload(this@with, info, false) } @@ -330,7 +331,7 @@ suspend fun DialogState.doGalleryInfoAction(info: BaseGalleryInfo, context: Cont private const val MAX_FAVNOTE_CHAR = 200 -suspend fun DialogState.confirmRemoveDownload(info: GalleryInfo): Boolean = show( +suspend fun DialogState.confirmRemoveDownload(info: GalleryInfo) = awaitPermissionOrCancel( confirmText = android.R.string.ok, dismissText = android.R.string.cancel, title = R.string.download_remove_dialog_title, diff --git a/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt index 0057855c6..cd9f92c59 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt @@ -88,7 +88,7 @@ fun CookieSignInScene(windowSizeClass: WindowSizeClass) { var signInJob by remember { mutableStateOf(null) } val dialogState = rememberDialogState() - dialogState.Handler() + dialogState.Intercept() val noCookies = stringResource(R.string.from_clipboard_error) @@ -129,7 +129,7 @@ fun CookieSignInScene(windowSizeClass: WindowSizeClass) { withUIContext { navController.navigate(if (canEx) SELECT_SITE_ROUTE_NAME else FINISH_ROUTE_NAME) } }.onFailure { EhCookieStore.signOut() - dialogState.show( + dialogState.awaitPermissionOrCancel( confirmText = R.string.get_it, title = R.string.sign_in_failed, text = { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt index 115e794ff..f79806083 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt @@ -89,7 +89,7 @@ fun SignInScreen(windowSizeClass: WindowSizeClass) { var signInJob by remember { mutableStateOf(null) } val dialogState = rememberDialogState() - dialogState.Handler() + dialogState.Intercept() BackHandler { (context as Activity).moveTaskToBack(true) @@ -119,7 +119,7 @@ fun SignInScreen(windowSizeClass: WindowSizeClass) { }.onFailure { withUIContext { focusManager.clearFocus() - dialogState.show( + dialogState.awaitPermissionOrCancel( confirmText = R.string.get_it, title = R.string.sign_in_failed, text = { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt index b6b7bf8ef..bbfbc7f52 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt @@ -407,7 +407,7 @@ class GalleryDetailScene : BaseScene() { updateDownloadState() } } - dialogState.Handler() + dialogState.Intercept() val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() Scaffold( topBar = { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt index d71c07631..c20539759 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt @@ -313,7 +313,7 @@ class GalleryListScene : SearchBarScene() { savedInstanceState: Bundle?, ): View { _binding = SceneGalleryListBinding.inflate(inflater, container!!) - container.addView(ComposeView(inflater.context).apply { setMD3Content { dialogState.Handler() } }) + container.addView(ComposeView(inflater.context).apply { setMD3Content { dialogState.Intercept() } }) checkForUpdates() requireActivity().onBackPressedDispatcher.addCallback(stateBackPressedCallback) mHideActionFabSlop = ViewConfiguration.get(requireContext()).scaledTouchSlop diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt index a98f8b92b..727b8efc2 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt @@ -76,7 +76,7 @@ class GalleryPreviewScreen : Fragment() { val columnCount = calculateSuitableSpanCount() val state = rememberLazyGridState() val dialogState = rememberDialogState() - dialogState.Handler() + dialogState.Intercept() val coroutineScope = rememberCoroutineScope { Dispatchers.IO } val pages = galleryDetail.pages val pgSize = galleryDetail.previewList.size diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt index c94e419aa..052796abc 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt @@ -76,7 +76,7 @@ class HistoryScene : BaseScene() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = ComposeView(inflater.context).apply { setMD3Content { val dialogState = rememberDialogState() - dialogState.Handler() + dialogState.Intercept() val coroutineScope = rememberCoroutineScope() val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val historyData = remember { Pager(PagingConfig(20, jumpThreshold = 40)) { EhDB.historyLazyList }.flow.cachedIn(lifecycleScope) }.collectAsLazyPagingItems() @@ -93,12 +93,12 @@ class HistoryScene : BaseScene() { actions = { IconButton(onClick = { coroutineScope.launchIO { - val clear = dialogState.show( + dialogState.awaitPermissionOrCancel( confirmText = R.string.clear_all, dismissText = android.R.string.cancel, text = { Text(text = stringResource(id = R.string.clear_all_history)) }, ) - if (clear) EhDB.clearHistoryInfo() + EhDB.clearHistoryInfo() } }) { Icon(imageVector = Icons.Default.ClearAll, contentDescription = null) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt index 3fe851117..c3afab38a 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt @@ -68,7 +68,7 @@ fun AboutScreen() { val snackbarHostState = remember { SnackbarHostState() } val coroutineScope = rememberCoroutineScope { Dispatchers.IO } val dialogState = rememberDialogState() - dialogState.Handler() + dialogState.Intercept() fun launchSnackBar(content: String) = coroutineScope.launch { snackbarHostState.showSnackbar(content) } Scaffold( topBar = { @@ -133,7 +133,7 @@ fun AboutScreen() { } suspend fun DialogState.showNewVersion(context: Context, release: Release) { - val download = show( + awaitPermissionOrCancel( confirmText = R.string.download, dismissText = android.R.string.cancel, title = R.string.new_version_available, @@ -148,9 +148,7 @@ suspend fun DialogState.showNewVersion(context: Context, release: Release) { } } // TODO: Download in the background and show progress in notification - if (download) { - val file = File(AppConfig.tempDir, "update.apk").apply { delete() } - AppUpdater.downloadUpdate(release.downloadLink, file) - withUIContext { context.installPackage(file) } - } + val file = File(AppConfig.tempDir, "update.apk").apply { delete() } + AppUpdater.downloadUpdate(release.downloadLink, file) + withUIContext { context.installPackage(file) } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt index bab2b9117..4657c369d 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/PrivacyScreen.kt @@ -38,7 +38,7 @@ fun PrivacyScreen() { val coroutineScope = rememberCoroutineScope { Dispatchers.IO } fun launchSnackBar(content: String) = coroutineScope.launch { snackbarHostState.showSnackbar(content) } val dialogState = rememberDialogState() - dialogState.Handler() + dialogState.Intercept() Scaffold( topBar = { TopAppBar( @@ -79,15 +79,13 @@ fun PrivacyScreen() { summary = stringResource(id = R.string.clear_search_history_summary), ) { coroutineScope.launch { - val confirmed = dialogState.show( + dialogState.awaitPermissionOrCancel( confirmText = R.string.clear_all, dismissText = android.R.string.cancel, title = R.string.clear_search_history_confirm, ) - if (confirmed) { - searchDatabase.searchDao().clear() - launchSnackBar(searchHistoryCleared) - } + searchDatabase.searchDao().clear() + launchSnackBar(searchHistoryCleared) } } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt b/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt index ddb513e2f..d1ee6c179 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt @@ -45,6 +45,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.resume @@ -57,106 +58,90 @@ fun interface DismissDialogScope { } class DialogState { - private var content: (@Composable () -> Unit)? by mutableStateOf(null) + var content: (@Composable () -> Unit)? by mutableStateOf(null) @Composable - fun Handler() = content?.invoke() + fun Intercept() = content?.invoke() fun dismiss() { content = null } + suspend inline fun dialog(crossinline block: @Composable (CancellableContinuation) -> Unit) = suspendCancellableCoroutine { cont -> + cont.invokeOnCancellation { dismiss() } + content = { block(cont) } + } + suspend fun show(initial: R, @StringRes title: Int? = null, block: @Composable DialogScope.() -> Unit): R { - return suspendCancellableCoroutine { cont -> - cont.invokeOnCancellation { dismiss() } - content = { - val state = remember(cont) { mutableStateOf(initial) } - val impl = remember(cont) { object : DialogScope { override var expectedValue by state } } - AlertDialog( - onDismissRequest = { - cont.cancel() + return dialog { cont -> + val state = remember(cont) { mutableStateOf(initial) } + val impl = remember(cont) { object : DialogScope { override var expectedValue by state } } + AlertDialog( + onDismissRequest = { cont.cancel() }, + confirmButton = { + TextButton(onClick = { dismiss() - }, - confirmButton = { - TextButton(onClick = { - dismiss() - cont.resume(state.value) - }) { - Text(text = stringResource(id = android.R.string.ok)) - } - }, - title = title?.let { { Text(text = stringResource(id = title)) } }, - text = { block(impl) }, - ) - } + cont.resume(state.value) + }) { + Text(text = stringResource(id = android.R.string.ok)) + } + }, + title = title?.let { { Text(text = stringResource(id = title)) } }, + text = { block(impl) }, + ) } } - suspend fun show( + suspend fun awaitPermissionOrCancel( @StringRes confirmText: Int? = null, @StringRes dismissText: Int? = null, @StringRes title: Int? = null, text: (@Composable () -> Unit)? = null, - ): Boolean { - return suspendCancellableCoroutine { cont -> - cont.invokeOnCancellation { dismiss() } - content = { - AlertDialog( - onDismissRequest = { + ) { + return dialog { cont -> + AlertDialog( + onDismissRequest = { cont.cancel() }, + confirmButton = { + TextButton(onClick = { dismiss() - cont.resume(false) - }, - confirmButton = { - TextButton(onClick = { - dismiss() - cont.resume(true) - }) { - Text(text = stringResource(id = confirmText ?: android.R.string.ok)) + cont.resume(Unit) + }) { + Text(text = stringResource(id = confirmText ?: android.R.string.ok)) + } + }, + dismissButton = dismissText?.let { + { + TextButton(onClick = { cont.cancel() }) { + Text(text = stringResource(id = dismissText)) } - }, - dismissButton = dismissText?.let { - { - TextButton(onClick = { - dismiss() - cont.resume(false) - }) { - Text(text = stringResource(id = dismissText)) - } - } - }, - title = title?.let { { Text(text = stringResource(id = title)) } }, - text = text, - ) - } + } + }, + title = title?.let { { Text(text = stringResource(id = title)) } }, + text = text, + ) } } private suspend fun showNoButton(respectDefaultWidth: Boolean = true, block: @Composable DismissDialogScope.() -> Unit): R { - return suspendCancellableCoroutine { cont -> - cont.invokeOnCancellation { dismiss() } - content = { - val impl = remember(cont) { - DismissDialogScope { - dismiss() - cont.resume(it) - } + return dialog { cont -> + val impl = remember(cont) { + DismissDialogScope { + dismiss() + cont.resume(it) } - AlertDialog( - onDismissRequest = { - cont.cancel() - dismiss() - }, - content = { - Surface( - modifier = with(Modifier) { if (!respectDefaultWidth) defaultMinSize(280.dp) else width(280.dp) }, - shape = AlertDialogDefaults.shape, - color = AlertDialogDefaults.containerColor, - tonalElevation = AlertDialogDefaults.TonalElevation, - content = { block(impl) }, - ) - }, - ) } + AlertDialog( + onDismissRequest = { cont.cancel() }, + content = { + Surface( + modifier = with(Modifier) { if (!respectDefaultWidth) defaultMinSize(280.dp) else width(280.dp) }, + shape = AlertDialogDefaults.shape, + color = AlertDialogDefaults.containerColor, + tonalElevation = AlertDialogDefaults.TonalElevation, + content = { block(impl) }, + ) + }, + ) } }