Refine storage permission request
This commit is contained in:
1 parent
3ee4b4a61e
commit
498129314a
4 files changed
+84
-114
No files matched your search
@@ -21,10 +21,8 @@ import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.app.DownloadManager
|
||||
import android.content.DialogInterface
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.view.LayoutInflater
|
||||
@@ -32,7 +30,6 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
@@ -96,7 +93,6 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidViewBinding
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
@@ -170,7 +166,10 @@ import com.hippo.ehviewer.util.IntList
|
||||
import com.hippo.ehviewer.util.ReadableTime
|
||||
import com.hippo.ehviewer.util.addTextToClipboard
|
||||
import com.hippo.ehviewer.util.getParcelableCompat
|
||||
import com.hippo.ehviewer.util.isAtLeastQ
|
||||
import com.hippo.ehviewer.util.requestPermission
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CancellationException
|
||||
@@ -197,20 +196,6 @@ class GalleryDetailScene : BaseScene() {
|
||||
private var getDetailError by mutableStateOf("")
|
||||
|
||||
private var mTorrentList: TorrentResult? = null
|
||||
private var requestStoragePermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission(),
|
||||
) { result: Boolean ->
|
||||
if (result && composeBindingGD != null) {
|
||||
val helper = TorrentListDialogHelper()
|
||||
val binding = DialogTorrentListBinding.inflate(layoutInflater)
|
||||
val dialog: Dialog = BaseDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.torrents)
|
||||
.setView(binding.root)
|
||||
.setOnDismissListener(helper)
|
||||
.show()
|
||||
helper.setDialog(dialog, binding, composeBindingGD!!.torrentUrl)
|
||||
}
|
||||
}
|
||||
private var mArchiveFormParamOr: String? = null
|
||||
private var mArchiveList: List<ArchiveParser.Archive>? = null
|
||||
private var mCurrentFunds: HomeParser.Funds? = null
|
||||
@@ -1113,21 +1098,20 @@ class GalleryDetailScene : BaseScene() {
|
||||
|
||||
private fun showTorrentDialog() {
|
||||
val galleryDetail = composeBindingGD ?: return
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(
|
||||
requireActivity(),
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
requestStoragePermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
} else {
|
||||
val helper = TorrentListDialogHelper()
|
||||
val binding = DialogTorrentListBinding.inflate(layoutInflater)
|
||||
val dialog: Dialog = BaseDialogBuilder(requireContext())
|
||||
.setTitle(R.string.torrents)
|
||||
.setView(binding.root)
|
||||
.setOnDismissListener(helper)
|
||||
.show()
|
||||
helper.setDialog(dialog, binding, galleryDetail.torrentUrl)
|
||||
viewLifecycleOwner.lifecycleScope.launchUI {
|
||||
val granted = isAtLeastQ || requireContext().requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
if (granted) {
|
||||
val helper = TorrentListDialogHelper()
|
||||
val binding = DialogTorrentListBinding.inflate(layoutInflater)
|
||||
val dialog: Dialog = BaseDialogBuilder(requireContext())
|
||||
.setTitle(R.string.torrents)
|
||||
.setView(binding.root)
|
||||
.setOnDismissListener(helper)
|
||||
.show()
|
||||
helper.setDialog(dialog, binding, galleryDetail.torrentUrl)
|
||||
} else {
|
||||
showTip(getString(R.string.permission_denied), LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.content.ClipData
|
||||
import android.content.ContentValues
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
@@ -43,7 +42,6 @@ import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.ChecksSdkIntAtLeast
|
||||
@@ -52,7 +50,6 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.WindowCompat
|
||||
@@ -82,7 +79,9 @@ import com.hippo.ehviewer.util.getParcelableExtraCompat
|
||||
import com.hippo.ehviewer.util.getValue
|
||||
import com.hippo.ehviewer.util.isAtLeastO
|
||||
import com.hippo.ehviewer.util.isAtLeastP
|
||||
import com.hippo.ehviewer.util.isAtLeastQ
|
||||
import com.hippo.ehviewer.util.lazyMut
|
||||
import com.hippo.ehviewer.util.requestPermission
|
||||
import com.hippo.ehviewer.util.sendTo
|
||||
import com.hippo.ehviewer.util.setValue
|
||||
import com.hippo.unifile.UniFile
|
||||
@@ -95,6 +94,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale
|
||||
import eu.kanade.tachiyomi.util.system.isNightMode
|
||||
@@ -170,17 +170,6 @@ class ReaderActivity : EhActivity() {
|
||||
}
|
||||
var mGalleryProvider by lazyMut { vm::galleryProvider }
|
||||
private var mCurrentIndex: Int = 0
|
||||
private var mSavingPage = -1
|
||||
private var requestStoragePermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission(),
|
||||
) { result ->
|
||||
if (result!! && mSavingPage != -1) {
|
||||
saveImage(mSavingPage)
|
||||
} else {
|
||||
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
mSavingPage = -1
|
||||
}
|
||||
|
||||
private val galleryDetailUrl: String?
|
||||
get() {
|
||||
@@ -455,78 +444,73 @@ class ReaderActivity : EhActivity() {
|
||||
}
|
||||
|
||||
fun saveImage(page: Int) {
|
||||
if (null == mGalleryProvider) {
|
||||
return
|
||||
}
|
||||
mGalleryProvider ?: return
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
mSavingPage = page
|
||||
requestStoragePermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
return
|
||||
}
|
||||
lifecycleScope.launchUI {
|
||||
val granted = isAtLeastQ || requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
if (granted) {
|
||||
val filename = mGalleryProvider!!.getImageFilenameWithExtension(page)
|
||||
var mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
||||
MimeTypeMap.getFileExtensionFromUrl(filename),
|
||||
)
|
||||
if (mimeType.isNullOrEmpty()) {
|
||||
mimeType = "image/jpeg"
|
||||
}
|
||||
|
||||
val filename = mGalleryProvider!!.getImageFilenameWithExtension(page)
|
||||
var mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
||||
MimeTypeMap.getFileExtensionFromUrl(filename),
|
||||
)
|
||||
if (mimeType.isNullOrEmpty()) {
|
||||
mimeType = "image/jpeg"
|
||||
}
|
||||
val realPath: String
|
||||
val resolver = contentResolver
|
||||
val values = ContentValues()
|
||||
values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
|
||||
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
|
||||
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
|
||||
if (isAtLeastQ) {
|
||||
values.put(
|
||||
MediaStore.MediaColumns.RELATIVE_PATH,
|
||||
Environment.DIRECTORY_PICTURES + File.separator + AppConfig.APP_DIRNAME,
|
||||
)
|
||||
values.put(MediaStore.MediaColumns.IS_PENDING, 1)
|
||||
realPath = Environment.DIRECTORY_PICTURES + File.separator + AppConfig.APP_DIRNAME
|
||||
} else {
|
||||
val path = File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
|
||||
AppConfig.APP_DIRNAME,
|
||||
)
|
||||
realPath = path.toString()
|
||||
if (!FileUtils.ensureDirectory(path)) {
|
||||
Toast.makeText(this@ReaderActivity, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show()
|
||||
return@launchUI
|
||||
}
|
||||
values.put(MediaStore.MediaColumns.DATA, path.toString() + File.separator + filename)
|
||||
}
|
||||
val imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
|
||||
if (imageUri == null) {
|
||||
Toast.makeText(this@ReaderActivity, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show()
|
||||
return@launchUI
|
||||
}
|
||||
if (!mGalleryProvider!!.save(page, UniFile.fromMediaUri(this@ReaderActivity, imageUri))) {
|
||||
try {
|
||||
resolver.delete(imageUri, null, null)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
val realPath: String
|
||||
val resolver = contentResolver
|
||||
val values = ContentValues()
|
||||
values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
|
||||
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
|
||||
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
values.put(
|
||||
MediaStore.MediaColumns.RELATIVE_PATH,
|
||||
Environment.DIRECTORY_PICTURES + File.separator + AppConfig.APP_DIRNAME,
|
||||
)
|
||||
values.put(MediaStore.MediaColumns.IS_PENDING, 1)
|
||||
realPath = Environment.DIRECTORY_PICTURES + File.separator + AppConfig.APP_DIRNAME
|
||||
} else {
|
||||
val path = File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
|
||||
AppConfig.APP_DIRNAME,
|
||||
)
|
||||
realPath = path.toString()
|
||||
if (!FileUtils.ensureDirectory(path)) {
|
||||
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
Toast.makeText(this@ReaderActivity, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show()
|
||||
return@launchUI
|
||||
} else if (isAtLeastQ) {
|
||||
val contentValues = ContentValues()
|
||||
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
|
||||
resolver.update(imageUri, contentValues, null, null)
|
||||
}
|
||||
|
||||
Toast.makeText(
|
||||
this@ReaderActivity,
|
||||
getString(R.string.image_saved, realPath + File.separator + filename),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
} else {
|
||||
Toast.makeText(this@ReaderActivity, R.string.permission_denied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
values.put(MediaStore.MediaColumns.DATA, path.toString() + File.separator + filename)
|
||||
}
|
||||
val imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
|
||||
if (imageUri == null) {
|
||||
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
if (!mGalleryProvider!!.save(page, UniFile.fromMediaUri(this, imageUri))) {
|
||||
try {
|
||||
resolver.delete(imageUri, null, null)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val contentValues = ContentValues()
|
||||
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
|
||||
resolver.update(imageUri, contentValues, null, null)
|
||||
}
|
||||
|
||||
Toast.makeText(
|
||||
this,
|
||||
getString(R.string.image_saved, realPath + File.separator + filename),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
|
||||
fun saveImageTo(page: Int) {
|
||||
|
||||
@@ -533,6 +533,7 @@
|
||||
<string name="update_frequency_monthly">每月</string>
|
||||
<string name="new_version_available">有新版本!</string>
|
||||
<string name="already_latest_version">已是最新版本</string>
|
||||
<string name="permission_denied">权限被拒</string>
|
||||
<!-- Tachiyomi Reader Start-->
|
||||
<string name="action_settings">设置</string>
|
||||
<string name="action_retry">重试</string>
|
||||
|
||||
@@ -597,6 +597,7 @@
|
||||
<string name="update_frequency_monthly">Monthly</string>
|
||||
<string name="new_version_available">New version available!</string>
|
||||
<string name="already_latest_version">Already the latest version</string>
|
||||
<string name="permission_denied">Permission denied</string>
|
||||
<!-- Tachiyomi Reader Start-->
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="pref_rotation_type">Default rotation type</string>
|
||||
|
||||
Reference in new issue
Block a user