diff --git a/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadManager.kt b/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadManager.kt index cbba05878..a1c85d07d 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadManager.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/download/DownloadManager.kt @@ -1029,7 +1029,7 @@ var downloadLocation: UniFile encodedQuery(downloadQuery) encodedFragment(downloadFragment) }.build() - uri.asUniFileOrNull() ?: requireNotNull(AppConfig.defaultDownloadDir).asUniFile() + uri.asUniFileOrNull() ?: AppConfig.defaultDownloadDir?.asUniFile() ?: UniFile.Stub } set(value) = with(value.uri) { Settings.edit { 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 630bdb4d0..aa620e0ce 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/CommonOperations.kt @@ -91,12 +91,14 @@ private fun ensureNoMediaFile(downloadDir: UniFile) { private val lck = Mutex() -suspend fun keepNoMediaFileStatus() { - lck.withLock { - if (Settings.mediaScan) { - removeNoMediaFile(downloadLocation) - } else { - ensureNoMediaFile(downloadLocation) +suspend fun keepNoMediaFileStatus(downloadDir: UniFile = downloadLocation) { + if (downloadDir.isDirectory) { + lck.withLock { + if (Settings.mediaScan) { + removeNoMediaFile(downloadDir) + } else { + ensureNoMediaFile(downloadDir) + } } } } 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 db89e298f..456123d07 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt @@ -100,6 +100,7 @@ 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.DownloadsScreenDestination import com.hippo.ehviewer.ui.destinations.FavouritesScreenDestination import com.hippo.ehviewer.ui.destinations.GalleryDetailScreenDestination @@ -223,9 +224,35 @@ class MainActivity : EhActivity() { callback() } + suspend fun DialogState.checkDownloadLocation() { + val valid = withIOContext { downloadLocation.ensureDir() } + if (!valid) { + awaitPermissionOrCancel( + confirmText = R.string.open_settings, + title = R.string.waring, + showCancelButton = false, + ) { + Text( + text = stringResource(id = R.string.invalid_download_location), + style = MaterialTheme.typography.titleMedium, + ) + } + navController.navigate(DownloadScreenDestination) + } + } + LaunchedEffect(Unit) { - launch { dialogState.checkDownloadLocation() }.join() - launch { dialogState.checkAppLinkVerify() } + runCatching { dialogState.checkDownloadLocation() } + runCatching { dialogState.checkAppLinkVerify() } + runSuspendCatching { + withIOContext { + AppUpdater.checkForUpdate()?.let { + dialogState.showNewVersion(this@MainActivity, it) + } + } + }.onFailure { + showTip(getString(R.string.update_failed, ExceptionUtils.getReadableString(it))) + } } val cannotParse = stringResource(R.string.error_cannot_parse_the_url) @@ -267,17 +294,6 @@ class MainActivity : EhActivity() { } } - LaunchedEffect(Unit) { - runSuspendCatching { - withIOContext { - AppUpdater.checkForUpdate()?.let { - dialogState.showNewVersion(this@MainActivity, it) - } - } - }.onFailure { - showTip(getString(R.string.update_failed, ExceptionUtils.getReadableString(it))) - } - } val snackbarState = remember { SnackbarHostState() } LaunchedEffect(Unit) { tipFlow.collectLatest { @@ -477,22 +493,6 @@ class MainActivity : EhActivity() { } } - private suspend fun DialogState.checkDownloadLocation() { - val valid = withIOContext { downloadLocation.ensureDir() } - if (!valid) { - awaitPermissionOrCancel( - confirmText = R.string.get_it, - title = R.string.waring, - showCancelButton = false, - ) { - Text( - text = stringResource(id = R.string.invalid_download_location), - style = MaterialTheme.typography.titleMedium, - ) - } - } - } - fun showTip(@StringRes id: Int, useToast: Boolean = false) { showTip(getString(id), useToast) } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt index 85c4924c3..edaa7489c 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/DownloadScreen.kt @@ -42,12 +42,11 @@ import com.hippo.ehviewer.spider.SpiderQueen.Companion.SPIDER_INFO_FILENAME import com.hippo.ehviewer.spider.readComicInfo import com.hippo.ehviewer.spider.readCompatFromUniFile import com.hippo.ehviewer.ui.keepNoMediaFileStatus -import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder import com.hippo.ehviewer.ui.tools.observed import com.hippo.ehviewer.ui.tools.rememberedAccessor -import com.hippo.ehviewer.util.AppConfig import com.hippo.unifile.UniFile import com.hippo.unifile.asUniFile +import com.hippo.unifile.toPathOrNull import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchNonCancellable @@ -88,7 +87,7 @@ fun DownloadScreen(navigator: DestinationsNavigator) { contentResolver.takePersistableUriPermission(treeUri, FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION) downloadLocationState = treeUri.asUniFile() coroutineScope.launchNonCancellable { - keepNoMediaFileStatus() + keepNoMediaFileStatus(downloadLocationState) } }.onFailure { launchSnackBar(cannotGetDownloadLocation) @@ -98,27 +97,9 @@ fun DownloadScreen(navigator: DestinationsNavigator) { } Preference( title = stringResource(id = R.string.settings_download_download_location), - summary = downloadLocationState.uri.toString(), + summary = downloadLocationState.uri.run { toPathOrNull() ?: toString() }, ) { - val file = downloadLocationState - if (!UniFile.isFileUri(downloadLocationState.uri)) { - BaseDialogBuilder(context) - .setTitle(R.string.settings_download_download_location) - .setMessage(file.uri.toString()) - .setPositiveButton(R.string.pick_new_download_location) { _, _ -> selectDownloadDirLauncher.launch(null) } - .setNeutralButton(R.string.reset_download_location) { _, _ -> - val uniFile = AppConfig.defaultDownloadDir?.asUniFile() - if (uniFile != null) { - downloadLocationState = uniFile - coroutineScope.launchNonCancellable { keepNoMediaFileStatus() } - } else { - launchSnackBar(cannotGetDownloadLocation) - } - } - .show() - } else { - selectDownloadDirLauncher.launch(null) - } + selectDownloadDirLauncher.launch(null) } val mediaScan = Settings::mediaScan.observed SwitchPreference( diff --git a/app/src/main/kotlin/com/hippo/ehviewer/util/AppConfig.kt b/app/src/main/kotlin/com/hippo/ehviewer/util/AppConfig.kt index e5fb24c88..e0a99b732 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/util/AppConfig.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/util/AppConfig.kt @@ -37,10 +37,11 @@ object AppConfig { return null } - private fun getDirInExternalAppDir(filename: String) = externalAppDir?.run { File(this, filename).takeIf { it.ensureDirectory() } } + private fun getDirInExternalAppDir(filename: String, create: Boolean = true) = + externalAppDir?.run { File(this, filename).takeIf { if (create) it.ensureDirectory() else it.isDirectory } } val defaultDownloadDir: File? - get() = getDirInExternalAppDir(DOWNLOAD) + get() = getDirInExternalAppDir(DOWNLOAD, false) val externalTempDir: File? get() = appCtx.externalCacheDir?.run { File(this, TEMP).takeIf { it.ensureDirectory() } } diff --git a/app/src/main/kotlin/com/hippo/unifile/UniFile.kt b/app/src/main/kotlin/com/hippo/unifile/UniFile.kt index ddd27524a..26d9ea276 100644 --- a/app/src/main/kotlin/com/hippo/unifile/UniFile.kt +++ b/app/src/main/kotlin/com/hippo/unifile/UniFile.kt @@ -235,11 +235,11 @@ abstract class UniFile internal constructor(private val parent: UniFile?) { companion object { fun fromFile(file: File) = RawFile(null, file) - fun fromSingleUri(singleUri: Uri) = SingleDocumentFile(null, singleUri) + private fun fromSingleUri(singleUri: Uri) = SingleDocumentFile(null, singleUri) - fun fromTreeUri(treeUri: Uri) = TreeDocumentFile(null, DocumentsContractApi21.prepareTreeUri(treeUri)) + private fun fromTreeUri(treeUri: Uri) = TreeDocumentFile(null, DocumentsContractApi21.prepareTreeUri(treeUri)) - fun fromMediaUri(mediaUri: Uri) = MediaFile(mediaUri) + private fun fromMediaUri(mediaUri: Uri) = MediaFile(mediaUri) fun fromUri(uri: Uri) = when { isFileUri(uri) -> fromFile(uri.toFile()) @@ -256,5 +256,7 @@ abstract class UniFile internal constructor(private val parent: UniFile?) { fun isTreeUri(uri: Uri) = DocumentsContractCompat.isTreeUri(uri) fun isMediaUri(uri: Uri) = null != MediaContract.getName(uri) + + val Stub = fromFile(File("")) } } diff --git a/app/src/main/kotlin/com/hippo/unifile/UniFileExtensions.kt b/app/src/main/kotlin/com/hippo/unifile/UniFileExtensions.kt index 99df7c8d2..cf0856555 100644 --- a/app/src/main/kotlin/com/hippo/unifile/UniFileExtensions.kt +++ b/app/src/main/kotlin/com/hippo/unifile/UniFileExtensions.kt @@ -1,8 +1,10 @@ package com.hippo.unifile import android.net.Uri +import android.os.Environment import android.os.ParcelFileDescriptor.AutoCloseInputStream import android.os.ParcelFileDescriptor.AutoCloseOutputStream +import android.provider.DocumentsContract import java.io.File import java.io.FileInputStream import java.io.FileOutputStream @@ -29,3 +31,18 @@ fun Path.asUniFile() = toFile().asUniFile() fun Uri.asUniFileOrNull() = UniFile.fromUri(this) fun Uri.asUniFile() = requireNotNull(asUniFileOrNull()) + +fun Uri.toPathOrNull(): String? { + if (UniFile.isFileUri(this)) { + return path + } + if (UniFile.isDocumentUri(this)) { + if (authority == "com.android.externalstorage.documents") { + val (type, id) = DocumentsContract.getDocumentId(this).split(":", limit = 2) + if (type == "primary") { + return Environment.getExternalStorageDirectory().absolutePath + "/" + id + } + } + } + return null +} diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index ed0cc98ab..6b5dd1065 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -145,7 +145,6 @@ Forrige år I går Legg til etikett - Tilbakestill til forvalg Ikke vis igjen %s (opplaster) Kopier oversettelse diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index a7b9b11ac..51d50b2d2 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -480,8 +480,6 @@ 定时请求新闻页面 隐藏 HV 事件通知 复制翻译 - 恢复默认路径 - 选择新路径 不再显示 打开设置 对于 Android 12 及更新的版本,您需要手动添加链接到已验证链接才能在 EhViewer 中打开 E-Hentai 链接。 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 37febc11d..51cfe06f0 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -475,8 +475,6 @@ 啟動時請求新聞頁面 隱藏 HV 事件通知 複製翻譯 - 恢復預設路徑 - 選擇新路徑 不再顯示 打開設定 對於 Android 12 及更新的版本,您需要手動增加連結到已驗證連結才能在 EhViewer 中打開 E-Hentai 連結。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 079f765dd..d98e792dd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -542,8 +542,6 @@ Timed request news page Hide HV event Notifications Copy translation - Reset to default - Pick a new location Don\'t show again Open settings For Android 12 and newer, you need to manually add link to verified links in order to open E-Hentai links in EhViewer.