diff --git a/app/src/main/kotlin/com/hippo/ehviewer/EhDB.kt b/app/src/main/kotlin/com/hippo/ehviewer/EhDB.kt index 782d6eea48..b6838c6acd 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/EhDB.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/EhDB.kt @@ -273,23 +273,25 @@ object EhDB { db.filterDao().update(filter) } - fun exportDB(context: Context, file: Path) { + context(Context) + fun exportDB(file: Path) { db.query("PRAGMA wal_checkpoint(FULL)", null).use { it.moveToNext() } - val dbFile = context.getDatabasePath(DB_NAME) + val dbFile = getDatabasePath(DB_NAME) dbFile.toOkioPath() sendTo file } - suspend fun importDB(context: Context, uri: Uri) { + context(Context) + suspend fun importDB(uri: Uri) { val tempDBName = "tmp.db" resource { - context.deleteDatabase(tempDBName) + deleteDatabase(tempDBName) roomDb(tempDBName) { - createFromInputStream { context.contentResolver.openInputStream(uri) } + createFromInputStream { contentResolver.openInputStream(uri) } addMigrations(Schema17to18()) } } release { it.close() - context.deleteDatabase(tempDBName) + deleteDatabase(tempDBName) } use { oldDB -> db.galleryDao().insertOrIgnore(oldDB.galleryDao().list()) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt index 54856f2a63..998378c15b 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/EhUtils.kt @@ -17,7 +17,6 @@ package com.hippo.ehviewer.client import android.app.DownloadManager import android.content.ActivityNotFoundException -import android.content.Context import android.content.Intent import android.os.Environment import androidx.compose.material3.MaterialTheme @@ -32,6 +31,7 @@ import com.hippo.ehviewer.client.data.GalleryDetail import com.hippo.ehviewer.client.data.GalleryInfo import com.hippo.ehviewer.client.parser.Archive import com.hippo.ehviewer.spider.SpiderDen +import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.util.AppConfig import com.hippo.ehviewer.util.FileUtils import com.hippo.ehviewer.util.addTextToClipboard @@ -193,7 +193,7 @@ object EhUtils { return title.substringBeforeLast('|').trim().ifEmpty { null } } - context(Context) + context(MainActivity) suspend fun downloadArchive(galleryDetail: GalleryDetail, archive: Archive) { val gid = galleryDetail.gid EhEngine.downloadArchive(gid, galleryDetail.token, archive.res, archive.isHAtH)?.let { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt index e9a1ec57cc..cf72bd37ac 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt @@ -56,11 +56,11 @@ import com.hippo.ehviewer.download.downloadLocation import com.hippo.ehviewer.download.tempDownloadDir import com.hippo.ehviewer.ui.destinations.ReaderScreenDestination import com.hippo.ehviewer.ui.reader.ReaderScreenArgs +import com.hippo.ehviewer.ui.screen.implicit import com.hippo.ehviewer.ui.tools.DialogState import com.hippo.ehviewer.ui.tools.LabeledCheckbox import com.hippo.ehviewer.util.FavouriteStatusRouter import com.hippo.ehviewer.util.bgWork -import com.hippo.ehviewer.util.findActivity import com.hippo.ehviewer.util.isAtLeastT import com.hippo.ehviewer.util.mapToLongArray import com.hippo.ehviewer.util.requestPermission @@ -108,11 +108,9 @@ suspend fun keepNoMediaFileStatus(downloadDir: Path = downloadLocation) { fun getFavoriteIcon(favorited: Boolean) = if (favorited) Icons.Default.Favorite else Icons.Default.FavoriteBorder -suspend fun DialogState.startDownload( - context: Context, - forceDefault: Boolean, - vararg galleryInfos: BaseGalleryInfo, -) = with(context) { +context(MainActivity) +suspend fun DialogState.startDownload(forceDefault: Boolean, vararg galleryInfos: BaseGalleryInfo) { + val context = implicit() if (isAtLeastT) { requestPermission(Manifest.permission.POST_NOTIFICATIONS) } @@ -125,9 +123,7 @@ suspend fun DialogState.startDownload( ContextCompat.startForegroundService(context, intent) } if (toAdd.isEmpty()) { - return with(findActivity()) { - showTip(R.string.added_to_download_list) - } + return showTip(R.string.added_to_download_list) } var justStart = forceDefault var label: String? = null @@ -151,9 +147,7 @@ suspend fun DialogState.startDownload( ContextCompat.startForegroundService(context, intent) } // Notify - with(findActivity()) { - showTip(R.string.added_to_download_list) - } + showTip(R.string.added_to_download_list) } else { // Let use chose label val list = DownloadManager.labelList @@ -184,9 +178,7 @@ suspend fun DialogState.startDownload( } else { Settings.hasDefaultDownloadLabel = false } - with(context.findActivity()) { - showTip(R.string.added_to_download_list) - } + showTip(R.string.added_to_download_list) } } @@ -286,7 +278,7 @@ fun DestinationsNavigator.navToReader(uri: Uri) = navToReader(ReaderScreenArgs.A private fun DestinationsNavigator.navToReader(args: ReaderScreenArgs) = navigate(ReaderScreenDestination(args)) { launchSingleTop = true } -context(DialogState, Context, DestinationsNavigator) +context(DialogState, MainActivity, DestinationsNavigator) suspend fun doGalleryInfoAction(info: BaseGalleryInfo) { val downloaded = DownloadManager.getDownloadState(info.gid) != DownloadInfo.STATE_INVALID val favorited = info.favoriteSlot != NOT_FAVORITED @@ -308,41 +300,37 @@ suspend fun doGalleryInfoAction(info: BaseGalleryInfo) { add(Icons.AutoMirrored.Default.DriveFileMove to R.string.download_move_dialog_title) } } - val selected = awaitSelectItemWithIcon(items, EhUtils.getSuitableTitle(info)) - with(findActivity()) { - when (selected) { - 0 -> { - EhDB.putHistoryInfo(info) - navToReader(info) - } - - 1 -> withUIContext { - if (downloaded) { - confirmRemoveDownload(info) - } else { - startDownload(this@with, false, info) - } - } + when (awaitSelectItemWithIcon(items, EhUtils.getSuitableTitle(info))) { + 0 -> { + EhDB.putHistoryInfo(info) + navToReader(info) + } - 2 -> if (favorited) { - runSuspendCatching { - removeFromFavorites(info) - showTip(R.string.remove_from_favorite_success) - }.onFailure { - showTip(R.string.remove_from_favorite_failure) - } + 1 -> withUIContext { + if (downloaded) { + confirmRemoveDownload(info) } else { - runSuspendCatching { - modifyFavorites(info) - showTip(R.string.add_to_favorite_success) - }.onFailure { - showTip(R.string.add_to_favorite_failure) - } + startDownload(false, info) } + } - 3 -> showMoveDownloadLabel(info) + 2 -> if (favorited) { + runSuspendCatching { + removeFromFavorites(info) + showTip(R.string.remove_from_favorite_success) + }.onFailure { + showTip(R.string.remove_from_favorite_failure) + } + } else { + runSuspendCatching { + modifyFavorites(info) + showTip(R.string.add_to_favorite_success) + }.onFailure { + showTip(R.string.add_to_favorite_failure) + } } - true + + 3 -> showMoveDownloadLabel(info) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/ComposeDefault.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/ComposeDefault.kt index 37cd04f661..93a9d1bfc0 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/ComposeDefault.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/ComposeDefault.kt @@ -1,19 +1,17 @@ package com.hippo.ehviewer.ui +import androidx.activity.compose.LocalActivity import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.SharedTransitionScope import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.platform.LocalContext import com.hippo.ehviewer.ui.screen.implicit import com.hippo.ehviewer.ui.tools.DialogState import com.hippo.ehviewer.ui.tools.LocalDialogState import com.hippo.ehviewer.ui.tools.NoopTransitionsVisibilityScope import com.hippo.ehviewer.ui.tools.TransitionsVisibilityScope import com.hippo.ehviewer.ui.tools.togetherWith -import com.hippo.ehviewer.util.findActivity import com.ramcosta.composedestinations.navigation.DestinationsNavigator import kotlinx.coroutines.CoroutineScope @@ -25,7 +23,7 @@ inline fun AnimatedVisibilityScope.composing( ) = with(NoopTransitionsVisibilityScope) { togetherWith(implicit()) { block( - with(LocalContext.current) { remember { findActivity() } }, + activity(), LocalSnackBarHostState.current, LocalDialogState.current, LocalSharedTransitionScope.current, @@ -35,3 +33,6 @@ inline fun AnimatedVisibilityScope.composing( ) } } + +@Composable +fun activity() = LocalActivity.current as MainActivity 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 f33abd09aa..cbc4b176be 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/GalleryInfoBottomSheet.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/GalleryInfoBottomSheet.kt @@ -1,6 +1,5 @@ package com.hippo.ehviewer.ui -import android.content.Context import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -62,7 +61,7 @@ private fun GalleryDetail.generateContent() = arrayOf( R.string.favorite_name to favoriteName, ) -context(Context, DestinationsNavigator) +context(MainActivity, DestinationsNavigator) @Composable fun GalleryInfoBottomSheet(detail: GalleryDetail) { Column(modifier = Modifier.fillMaxWidth()) { 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 2c8e0e5bac..4ade60ea89 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt @@ -258,7 +258,7 @@ class MainActivity : EhActivity() { runSuspendCatching { withIOContext { AppUpdater.checkForUpdate()?.let { - dialogState.showNewVersion(this@MainActivity, it) + dialogState.showNewVersion(it) } } }.onFailure { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/PageActions.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/PageActions.kt index da5b19afae..ceb577ed98 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/PageActions.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/PageActions.kt @@ -18,6 +18,7 @@ import com.hippo.ehviewer.client.EhUrl import com.hippo.ehviewer.client.data.GalleryInfo import com.hippo.ehviewer.gallery.Page import com.hippo.ehviewer.gallery.PageLoader +import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.util.AppConfig import com.hippo.ehviewer.util.FileUtils import com.hippo.ehviewer.util.awaitActivityResult @@ -82,7 +83,7 @@ suspend fun copy(page: Page) { } } -context(SnackbarHostState, Context, PageLoader) +context(SnackbarHostState, MainActivity, PageLoader) suspend fun save(page: Page) { val granted = isAtLeastQ || requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) val cannotSave = getString(R.string.error_cant_save_image) @@ -136,7 +137,7 @@ suspend fun save(page: Page) { } } -context(SnackbarHostState, Context, PageLoader) +context(SnackbarHostState, MainActivity, PageLoader) suspend fun saveTo(page: Page) { val filename = getImageFilename(page.index) if (filename == null) { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt index bbf1c2ac77..053853539c 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt @@ -384,7 +384,7 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator) = onClick(Icons.Default.Download) { val info = checkedInfoMap.takeAndClear() runSwallowingWithUI { - startDownload(implicit(), false, *info.toTypedArray()) + startDownload(false, *info.toTypedArray()) } } onClick(Icons.Default.Delete) { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt index 09e15cfd86..ed098a3009 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailContent.kt @@ -237,7 +237,7 @@ fun GalleryDetailContent( fun onDownloadButtonClick() { galleryDetail ?: return if (DownloadManager.getDownloadState(galleryDetail.gid) == DownloadInfo.STATE_INVALID) { - launchUI { startDownload(implicit(), false, galleryDetail.galleryInfo) } + launchUI { startDownload(false, galleryDetail.galleryInfo) } } else { launch { confirmRemoveDownload(galleryDetail) } } @@ -376,7 +376,7 @@ fun GalleryDetailContent( } } -context(Context, CoroutineScope, DestinationsNavigator, DialogState, SnackbarHostState) +context(MainActivity, CoroutineScope, DestinationsNavigator, DialogState, SnackbarHostState) @Composable fun BelowHeader(galleryDetail: GalleryDetail) { @Composable diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AboutScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AboutScreen.kt index a73bc7d820..bd443201ca 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AboutScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AboutScreen.kt @@ -1,6 +1,6 @@ package com.hippo.ehviewer.ui.settings -import android.content.Context +import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -21,10 +21,8 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.fromHtml @@ -34,9 +32,10 @@ import com.hippo.ehviewer.EhDB import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings import com.hippo.ehviewer.download.downloadLocation +import com.hippo.ehviewer.ui.MainActivity +import com.hippo.ehviewer.ui.composing import com.hippo.ehviewer.ui.destinations.LicenseScreenDestination import com.hippo.ehviewer.ui.tools.DialogState -import com.hippo.ehviewer.ui.tools.LocalDialogState import com.hippo.ehviewer.ui.tools.observed import com.hippo.ehviewer.updater.AppUpdater import com.hippo.ehviewer.updater.Release @@ -49,7 +48,6 @@ import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.withUIContext import java.io.File -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import moe.tarsin.coroutines.runSuspendCatching @@ -66,13 +64,10 @@ private fun author() = AnnotatedString.fromHtml(stringResource(R.string.settings @Destination @Composable -fun AboutScreen(navigator: DestinationsNavigator) { - val context = LocalContext.current +fun AnimatedVisibilityScope.AboutScreen(navigator: DestinationsNavigator) = composing(navigator) { val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val snackbarHostState = remember { SnackbarHostState() } - val coroutineScope = rememberCoroutineScope { Dispatchers.IO } - val dialogState = LocalDialogState.current - fun launchSnackBar(content: String) = coroutineScope.launch { snackbarHostState.showSnackbar(content) } + fun launchSnackBar(content: String) = launch { snackbarHostState.showSnackbar(content) } Scaffold( topBar = { TopAppBar( @@ -125,20 +120,20 @@ fun AboutScreen(navigator: DestinationsNavigator) { entryValueRes = R.array.update_frequency_values, value = Settings::updateIntervalDays.observed, ) + val latestVersion = stringResource(id = R.string.already_latest_version) WorkPreference(title = stringResource(id = R.string.settings_about_check_for_updates)) { runSuspendCatching { - AppUpdater.checkForUpdate(true)?.let { - dialogState.showNewVersion(context, it) - } ?: launchSnackBar(context.getString(R.string.already_latest_version)) + AppUpdater.checkForUpdate(true)?.let { showNewVersion(it) } ?: launchSnackBar(latestVersion) }.onFailure { - launchSnackBar(context.getString(R.string.update_failed, it.displayString())) + launchSnackBar(getString(R.string.update_failed, it.displayString())) } } } } } -suspend fun DialogState.showNewVersion(context: Context, release: Release) { +context(MainActivity) +suspend fun DialogState.showNewVersion(release: Release) { awaitConfirmationOrCancel( confirmText = R.string.download, title = R.string.new_version_available, @@ -154,10 +149,10 @@ suspend fun DialogState.showNewVersion(context: Context, release: Release) { } if (Settings.backupBeforeUpdate) { val time = ReadableTime.getFilenamableTime() - EhDB.exportDB(context, (downloadLocation / "$time.db")) + EhDB.exportDB(downloadLocation / "$time.db") } // TODO: Download in the background and show progress in notification val file = File(AppConfig.tempDir, "update.apk").apply { delete() } AppUpdater.downloadUpdate(release.downloadLink, file) - withUIContext { context.installPackage(file) } + withUIContext { installPackage(file) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt index fb975d91ff..08652fd7e5 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt @@ -213,7 +213,7 @@ fun AdvancedScreen(navigator: DestinationsNavigator) { uri?.let { context.runCatching { grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - EhDB.exportDB(context, uri.toOkioPath()) + EhDB.exportDB(uri.toOkioPath()) launchSnackBar(getString(R.string.settings_advanced_export_data_to, uri.displayPath)) }.onFailure { logcat(it) @@ -232,7 +232,7 @@ fun AdvancedScreen(navigator: DestinationsNavigator) { uri?.let { context.runCatching { grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) - EhDB.importDB(context, uri) + EhDB.importDB(uri) launchSnackBar(importSucceed) }.onFailure { logcat(it) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/BBCodeTextToolbar.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/BBCodeTextToolbar.kt index 714808f693..9569b630f0 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/BBCodeTextToolbar.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/tools/BBCodeTextToolbar.kt @@ -3,15 +3,12 @@ package com.hippo.ehviewer.ui.tools import android.view.ActionMode import android.view.Menu import android.view.MenuItem -import androidx.activity.ComponentActivity import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Rect -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.TextToolbar import androidx.compose.ui.platform.TextToolbarStatus @@ -28,13 +25,14 @@ import androidx.compose.ui.text.input.getTextBeforeSelection import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.withStyle import com.hippo.ehviewer.R -import com.hippo.ehviewer.util.findActivity +import com.hippo.ehviewer.ui.MainActivity import com.hippo.ehviewer.util.toRangeSet import io.github.petertrr.diffutils.diffInline import io.github.petertrr.diffutils.patch.ChangeDelta import io.github.petertrr.diffutils.patch.DeleteDelta import io.github.petertrr.diffutils.patch.EqualDelta import io.github.petertrr.diffutils.patch.InsertDelta +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import moe.tarsin.kt.unreachable @@ -142,20 +140,18 @@ fun AnnotatedString.toBBCode() = buildString { } } +context(MainActivity, CoroutineScope) @Composable fun rememberBBCodeTextToolbar(textFieldValue: MutableState): TextToolbar { var tfv by textFieldValue val view = LocalView.current - val context = LocalContext.current - val activity = remember { context.findActivity() } - val coroutineScope = rememberCoroutineScope() - val toolbar = remember { + return remember { object : TextToolbar { private var actionMode: ActionMode? = null private val callback = object : TextActionModeCallback() { override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { super.onCreateActionMode(mode, menu) - activity.menuInflater.inflate(R.menu.context_comment, menu) + menuInflater.inflate(R.menu.context_comment, menu) return true } @@ -213,7 +209,7 @@ fun rememberBBCodeTextToolbar(textFieldValue: MutableState): Tex }, selection = TextRange(end), ) - coroutineScope.launch { + launch { // Hacky: Let TextField recompose first delay(100) tfv = tfv.copy(annotatedString = annotatedString) @@ -257,5 +253,4 @@ fun rememberBBCodeTextToolbar(textFieldValue: MutableState): Tex } } } - return toolbar } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/util/ClipboardUtil.kt b/app/src/main/kotlin/com/hippo/ehviewer/util/ClipboardUtil.kt index 820c39f9b5..94aeb28786 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/util/ClipboardUtil.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/util/ClipboardUtil.kt @@ -38,12 +38,11 @@ fun copyTextToClipboard(text: CharSequence?, isSensitive: Boolean) { ) } -fun Context.addTextToClipboard(text: CharSequence?, useToast: Boolean = false) { +fun MainActivity.addTextToClipboard(text: CharSequence?, useToast: Boolean = false) { copyTextToClipboard(text, false) // Avoid double notify user since system have done that on Tiramisu above if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - val activity = findActivity() - activity.showTip(R.string.copied_to_clipboard, useToast) + showTip(R.string.copied_to_clipboard, useToast) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/util/ContextUtil.kt b/app/src/main/kotlin/com/hippo/ehviewer/util/ContextUtil.kt index de9785e653..8724d43629 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/util/ContextUtil.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/util/ContextUtil.kt @@ -1,22 +1,8 @@ package com.hippo.ehviewer.util -import android.app.Activity import android.content.Context -import android.content.ContextWrapper import android.content.Intent -/** - * Find the closest Activity in a given Context. - */ -inline fun Context.findActivity(): T { - var context = this - while (context is ContextWrapper) { - if (context is Activity) return context as T - context = context.baseContext - } - throw IllegalStateException("findActivity() should be called in the context of an Activity") -} - fun Context.restartApplication() { packageManager.getLaunchIntentForPackage(packageName)?.let { startActivity(Intent.makeRestartActivityTask(it.component)) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/util/LauncherUtils.kt b/app/src/main/kotlin/com/hippo/ehviewer/util/LauncherUtils.kt index 88fa64b5bb..f899109297 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/util/LauncherUtils.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/util/LauncherUtils.kt @@ -1,14 +1,11 @@ package com.hippo.ehviewer.util import android.Manifest -import android.content.Context -import android.content.ContextWrapper import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.provider.Settings -import androidx.activity.ComponentActivity import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContract @@ -19,32 +16,21 @@ import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver -import androidx.lifecycle.LifecycleOwner -import arrow.atomic.AtomicInt +import arrow.atomic.value import com.hippo.ehviewer.R +import com.hippo.ehviewer.ui.MainActivity import eu.kanade.tachiyomi.util.lang.withUIContext import java.io.File +import java.util.concurrent.atomic.AtomicInteger import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine // Fuck off the silly Android launcher and callback :) -private val atomicInteger = AtomicInt() +private var id by AtomicInteger()::value -private val Context.lifecycle: Lifecycle - get() { - var context: Context? = this - while (true) { - when (context) { - is LifecycleOwner -> return context.lifecycle - !is ContextWrapper -> error("This should never happen!") - else -> context = context.baseContext - } - } - } - -suspend fun Context.awaitActivityResult(contract: ActivityResultContract, input: I): O { - val key = "activity_rq#${atomicInteger.getAndIncrement()}" +suspend fun MainActivity.awaitActivityResult(contract: ActivityResultContract, input: I): O { + val key = "activity_rq#${++id}" var launcher: ActivityResultLauncher? = null var observer: LifecycleEventObserver? = null observer = LifecycleEventObserver { _, event -> @@ -59,8 +45,7 @@ suspend fun Context.awaitActivityResult(contract: ActivityResultContract< lifecycle.addObserver(observer) suspendCoroutine { cont -> // No cancellation support here since we cannot cancel a launched Intent - val activity = findActivity() - launcher = activity.activityResultRegistry.register(key, contract) { + launcher = activityResultRegistry.register(key, contract) { launcher?.unregister() lifecycle.removeObserver(observer) cont.resume(it) @@ -69,15 +54,15 @@ suspend fun Context.awaitActivityResult(contract: ActivityResultContract< } } -suspend fun Context.requestPermission(key: String): Boolean { +suspend fun MainActivity.requestPermission(key: String): Boolean { if (ContextCompat.checkSelfPermission(this, key) == PackageManager.PERMISSION_GRANTED) return true return awaitActivityResult(ActivityResultContracts.RequestPermission(), key) } -suspend fun Context.pickVisualMedia(type: VisualMediaType): Uri? = awaitActivityResult(ActivityResultContracts.PickVisualMedia(), PickVisualMediaRequest(mediaType = type)) +suspend fun MainActivity.pickVisualMedia(type: VisualMediaType): Uri? = awaitActivityResult(ActivityResultContracts.PickVisualMedia(), PickVisualMediaRequest(mediaType = type)) @RequiresApi(Build.VERSION_CODES.O) -suspend fun Context.requestInstallPermission(): Boolean { +suspend fun MainActivity.requestInstallPermission(): Boolean { if (packageManager.canRequestPackageInstalls()) return true val granted = requestPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES) if (!granted) { @@ -93,7 +78,7 @@ suspend fun Context.requestInstallPermission(): Boolean { return packageManager.canRequestPackageInstalls() } -suspend fun Context.installPackage(file: File) { +suspend fun MainActivity.installPackage(file: File) { val canInstall = !isAtLeastO || requestInstallPermission() check(canInstall) { getString(R.string.permission_denied) } val contentUri = FileProvider.getUriForFile(this, "$packageName.fileprovider", file)