From ccde68f4f88f3f2018c4f379fee21e96760418e2 Mon Sep 17 00:00:00 2001 From: Cuong-Tran Date: Mon, 29 Jul 2024 18:18:44 +0700 Subject: [PATCH] feat: request for writing storage permission when saving pictures (Android P & below) --- .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 24 +++++++++++- .../tachiyomi/ui/reader/ReaderActivity.kt | 39 ++++++++++++++++++- .../moko-resources/base/strings.xml | 1 + 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index 94cec671c..922c92654 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -1,7 +1,10 @@ package eu.kanade.tachiyomi.ui.manga +import android.Manifest import android.content.Context import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -462,12 +465,31 @@ class MangaScreen( if (it == null) return@rememberLauncherForActivityResult sm.editCover(context, it) } + // KMK --> + val externalStoragePermissionNotGranted = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && + context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == + PackageManager.PERMISSION_DENIED + val saveCoverPermissionRequester = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission(), + onResult = { + sm.saveCover(context) + }, + ) + // KMK <-- MangaCoverDialog( coverDataProvider = { manga!! }, snackbarHostState = sm.snackbarHostState, isCustomCover = remember(manga) { manga!!.hasCustomCover() }, onShareClick = { sm.shareCover(context) }, - onSaveClick = { sm.saveCover(context) }, + onSaveClick = { + // KMK --> + if (externalStoragePermissionNotGranted) { + saveCoverPermissionRequester.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } else { + // KMK <-- + sm.saveCover(context) + } + }, onEditClick = { when (it) { EditCoverAction.EDIT -> getContent.launch("image/*") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index c3b95f3dd..1b96c1e4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.ui.reader +import android.Manifest import android.annotation.SuppressLint import android.app.Activity import android.app.assist.AssistContent @@ -7,6 +8,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.content.res.Configuration import android.graphics.Color import android.graphics.ColorMatrix @@ -21,6 +23,8 @@ import android.view.View import android.view.View.LAYER_TYPE_HARDWARE import android.view.WindowManager import android.widget.Toast +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -39,6 +43,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.core.content.getSystemService import androidx.core.graphics.ColorUtils @@ -132,6 +137,7 @@ import tachiyomi.domain.manga.model.MangaCover import tachiyomi.domain.manga.model.asMangaCover import tachiyomi.domain.source.service.SourceManager import tachiyomi.i18n.MR +import tachiyomi.i18n.kmk.KMR import tachiyomi.i18n.sy.SYMR import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt @@ -420,6 +426,7 @@ class ReaderActivity : BaseActivity() { @Composable fun dialogRootContent() { + val context = LocalContext.current // KMK <-- val state by viewModel.state.collectAsState() val settingsScreenModel = remember { @@ -479,6 +486,18 @@ class ReaderActivity : BaseActivity() { } // SY <-- + // KMK --> + val externalStoragePermissionNotGranted = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && + context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == + PackageManager.PERMISSION_DENIED + val permissionRequester = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission(), + onResult = { + toast(KMR.strings.permission_writing_external_storage_succeed) + }, + ) + // KMK <-- + ReaderContentOverlay( brightness = state.brightnessOverlayValue, color = colorOverlay.takeIf { colorOverlayEnabled }, @@ -623,9 +642,25 @@ class ReaderActivity : BaseActivity() { onDismissRequest = onDismissRequest, onSetAsCover = viewModel::setAsCover, onShare = viewModel::shareImage, - onSave = viewModel::saveImage, + onSave = { extra -> + // KMK --> + if (externalStoragePermissionNotGranted) { + permissionRequester.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } else { + // KMK <-- + viewModel.saveImage(extra) + } + }, onShareCombined = viewModel::shareImages, - onSaveCombined = viewModel::saveImages, + onSaveCombined = { + // KMK --> + if (externalStoragePermissionNotGranted) { + permissionRequester.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } else { + // KMK <-- + viewModel.saveImages() + } + }, hasExtraPage = (state.dialog as? ReaderViewModel.Dialog.PageActions)?.extraPage != null, ) } diff --git a/i18n-kmk/src/commonMain/moko-resources/base/strings.xml b/i18n-kmk/src/commonMain/moko-resources/base/strings.xml index 907c34ca5..67ebf5ed0 100644 --- a/i18n-kmk/src/commonMain/moko-resources/base/strings.xml +++ b/i18n-kmk/src/commonMain/moko-resources/base/strings.xml @@ -70,6 +70,7 @@ Access media files permission Allow using custom covers in entry's Edit Info Allow saving covers & using custom covers in entry's Edit Info + Permission granted. Try action again. What\'s coming (soon)