Cleanup dialog api

This commit is contained in:
tarsin committed 2023-08-02 09:18:27 +08:00
1 parent cfe7ee7f9c
commit 39b896e1b9
10 files changed
+83 -101

No files matched your search

@@ -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,
@@ -88,7 +88,7 @@ fun CookieSignInScene(windowSizeClass: WindowSizeClass) {
var signInJob by remember { mutableStateOf<Job?>(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 = {
@@ -89,7 +89,7 @@ fun SignInScreen(windowSizeClass: WindowSizeClass) {
var signInJob by remember { mutableStateOf<Job?>(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 = {
@@ -407,7 +407,7 @@ class GalleryDetailScene : BaseScene() {
updateDownloadState()
}
}
dialogState.Handler()
dialogState.Intercept()
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
topBar = {
@@ -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
@@ -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
@@ -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)
@@ -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) }
}
@@ -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)
}
}
}
@@ -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<R> {
}
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 <R> dialog(crossinline block: @Composable (CancellableContinuation<R>) -> Unit) = suspendCancellableCoroutine<R> { cont ->
cont.invokeOnCancellation { dismiss() }
content = { block(cont) }
}
suspend fun <R> show(initial: R, @StringRes title: Int? = null, block: @Composable DialogScope<R>.() -> Unit): R {
return suspendCancellableCoroutine { cont ->
cont.invokeOnCancellation { dismiss() }
content = {
val state = remember(cont) { mutableStateOf(initial) }
val impl = remember(cont) { object : DialogScope<R> { override var expectedValue by state } }
AlertDialog(
onDismissRequest = {
cont.cancel()
return dialog { cont ->
val state = remember(cont) { mutableStateOf(initial) }
val impl = remember(cont) { object : DialogScope<R> { 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 <R> showNoButton(respectDefaultWidth: Boolean = true, block: @Composable DismissDialogScope<R>.() -> Unit): R {
return suspendCancellableCoroutine { cont ->
cont.invokeOnCancellation { dismiss() }
content = {
val impl = remember(cont) {
DismissDialogScope<R> {
dismiss()
cont.resume(it)
}
return dialog { cont ->
val impl = remember(cont) {
DismissDialogScope<R> {
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) },
)
},
)
}
}