From bb77c4ecfc504824fbf559db65a513b097567798 Mon Sep 17 00:00:00 2001 From: tarsin Date: Tue, 6 Jun 2023 14:06:07 +0800 Subject: [PATCH] [DO NOT USE] Introduce LauncherPreference --- .../ehviewer/ui/settings/AdvancedScreen.kt | 117 ++++++++---------- .../ehviewer/ui/settings/PreferenceWidgets.kt | 26 ++++ 2 files changed, 79 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt index df3d228c6..8087bbdac 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt @@ -6,7 +6,6 @@ import android.content.Intent import android.net.Uri import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS import android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS -import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -41,12 +40,10 @@ import com.hippo.ehviewer.client.EhEngine import com.hippo.ehviewer.client.data.FavListUrlBuilder import com.hippo.ehviewer.client.systemDns import com.hippo.ehviewer.ui.compose.observed -import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder import com.hippo.ehviewer.ui.legacy.EditTextDialogBuilder import com.hippo.ehviewer.ui.login.LocalNavController import com.hippo.ehviewer.util.LogCat import com.hippo.ehviewer.util.ReadableTime -import eu.kanade.tachiyomi.util.lang.withUIContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -92,39 +89,38 @@ fun AdvancedScreen() { value = Settings::saveCrashLog, ) val dumpLogError = stringResource(id = R.string.settings_advanced_dump_logcat_failed) - val dumpLogcatLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("application/zip")) { uri -> + LauncherPreference( + title = stringResource(id = R.string.settings_advanced_dump_logcat), + summary = stringResource(id = R.string.settings_advanced_dump_logcat_summary), + contract = ActivityResultContracts.CreateDocument("application/zip"), + key = "log-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".zip", + ) { uri -> uri?.run { - coroutineScope.launch { - context.runCatching { - grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - contentResolver.openOutputStream(uri)?.use { outputStream -> - val files = ArrayList() - AppConfig.externalParseErrorDir?.listFiles()?.let { files.addAll(it) } - AppConfig.externalCrashDir?.listFiles()?.let { files.addAll(it) } - ZipOutputStream(outputStream).use { zipOs -> - files.forEach { file -> - if (!file.isFile) return@forEach - val entry = ZipEntry(file.name) - zipOs.putNextEntry(entry) - file.inputStream().use { it.copyTo(zipOs) } - } - val logcatEntry = ZipEntry("logcat-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt") - zipOs.putNextEntry(logcatEntry) - LogCat.save(zipOs) + context.runCatching { + grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + contentResolver.openOutputStream(uri)?.use { outputStream -> + val files = ArrayList() + AppConfig.externalParseErrorDir?.listFiles()?.let { files.addAll(it) } + AppConfig.externalCrashDir?.listFiles()?.let { files.addAll(it) } + ZipOutputStream(outputStream).use { zipOs -> + files.forEach { file -> + if (!file.isFile) return@forEach + val entry = ZipEntry(file.name) + zipOs.putNextEntry(entry) + file.inputStream().use { it.copyTo(zipOs) } } - launchSnackBar(getString(R.string.settings_advanced_dump_logcat_to, uri.toString())) + val logcatEntry = ZipEntry("logcat-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt") + zipOs.putNextEntry(logcatEntry) + LogCat.save(zipOs) } - }.onFailure { - launchSnackBar(dumpLogError) - it.printStackTrace() + launchSnackBar(getString(R.string.settings_advanced_dump_logcat_to, uri.toString())) } + }.onFailure { + launchSnackBar(dumpLogError) + it.printStackTrace() } } } - Preference( - title = stringResource(id = R.string.settings_advanced_dump_logcat), - summary = stringResource(id = R.string.settings_advanced_dump_logcat_summary), - ) { dumpLogcatLauncher.launch("log-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".zip") } SimpleMenuPreferenceInt( title = stringResource(id = R.string.settings_advanced_read_cache_size), entry = R.array.read_cache_size_entries, @@ -173,49 +169,42 @@ fun AdvancedScreen() { value = Settings::preloadThumbAggressively, ) val exportFailed = stringResource(id = R.string.settings_advanced_export_data_failed) - val exportLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("application/vnd.sqlite3")) { uri -> - uri?.let { - coroutineScope.launch { - val alertDialog = withUIContext { BaseDialogBuilder(context).setCancelable(false).setView(R.layout.preference_dialog_task).show() } - context.runCatching { - grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - EhDB.exportDB(context, uri) - launchSnackBar(getString(R.string.settings_advanced_export_data_to, uri.toString())) - }.onFailure { - it.printStackTrace() - launchSnackBar(exportFailed) - } - if (alertDialog.isShowing) alertDialog.dismiss() - } - } - } - Preference( + LauncherPreference( title = stringResource(id = R.string.settings_advanced_export_data), summary = stringResource(id = R.string.settings_advanced_export_data_summary), - ) { exportLauncher.launch(ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".db") } - - val importFailed = stringResource(id = R.string.cant_read_the_file) - val importSucceed = stringResource(id = R.string.settings_advanced_import_data_successfully) - val importLauncher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri -> + contract = ActivityResultContracts.CreateDocument("application/vnd.sqlite3"), + key = ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".db", + ) { uri -> uri?.let { - coroutineScope.launch { - val alertDialog = withUIContext { BaseDialogBuilder(context).setCancelable(false).setView(R.layout.preference_dialog_task).show() } - context.runCatching { - grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) - EhDB.importDB(context, uri) - launchSnackBar(importSucceed) - }.onFailure { - it.printStackTrace() - launchSnackBar(importFailed) - } - if (alertDialog.isShowing) alertDialog.dismiss() + context.runCatching { + grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + EhDB.exportDB(context, uri) + launchSnackBar(getString(R.string.settings_advanced_export_data_to, uri.toString())) + }.onFailure { + it.printStackTrace() + launchSnackBar(exportFailed) } } } - Preference( + val importFailed = stringResource(id = R.string.cant_read_the_file) + val importSucceed = stringResource(id = R.string.settings_advanced_import_data_successfully) + LauncherPreference( title = stringResource(id = R.string.settings_advanced_import_data), summary = stringResource(id = R.string.settings_advanced_import_data_summary), - ) { importLauncher.launch("application/octet-stream") } + contract = ActivityResultContracts.GetContent(), + key = "application/octet-stream", + ) { uri -> + uri?.let { + context.runCatching { + grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + EhDB.importDB(context, uri) + launchSnackBar(importSucceed) + }.onFailure { + it.printStackTrace() + launchSnackBar(importFailed) + } + } + } val backupNothing = stringResource(id = R.string.settings_advanced_backup_favorite_nothing) val backupFailed = stringResource(id = R.string.settings_advanced_backup_favorite_failed) val backupSucceed = stringResource(id = R.string.settings_advanced_backup_favorite_success) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt index 76e485235..59896858e 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/PreferenceWidgets.kt @@ -1,7 +1,10 @@ package com.hippo.ehviewer.ui.settings +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContract import androidx.annotation.ArrayRes import androidx.annotation.StringRes +import androidx.appcompat.app.AlertDialog import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -30,6 +33,7 @@ import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.dp +import arrow.atomic.Atomic import com.hippo.ehviewer.R import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder import com.hippo.ehviewer.ui.login.LocalNavController @@ -40,9 +44,12 @@ import com.jamal.composeprefs3.ui.prefs.SliderPref import com.jamal.composeprefs3.ui.prefs.SpannedTextPref import com.jamal.composeprefs3.ui.prefs.SwitchPref import com.jamal.composeprefs3.ui.prefs.TextPref +import eu.kanade.tachiyomi.util.lang.withUIContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine import kotlin.math.roundToInt import kotlin.reflect.KMutableProperty0 @@ -137,3 +144,22 @@ fun WorkPreference(title: String, summary: String? = null, work: suspend Corouti coroutineScope.launch(block = work).invokeOnCompletion { if (alertDialog.isShowing) alertDialog.dismiss() } } } + +@Composable +fun LauncherPreference(title: String, summary: String? = null, contract: ActivityResultContract, key: I, work: suspend CoroutineScope.(O) -> Unit) { + val coroutineScope = rememberCoroutineScope { Dispatchers.IO } + val context = LocalContext.current + val callback = remember { Atomic<(O) -> Unit> {} } + val launcher = rememberLauncherForActivityResult(contract = contract) { callback.getAndSet { }.invoke(it) } + Preference(title = title, summary = summary) { + var alertDialog: AlertDialog? = null + coroutineScope.launch { + val o = suspendCoroutine { cont -> + callback.set { cont.resume(it) } + launcher.launch(key) + } + alertDialog = withUIContext { BaseDialogBuilder(context).setCancelable(false).setView(R.layout.preference_dialog_task).show() } + work(o) + }.invokeOnCompletion { alertDialog?.dismiss() } + } +}