mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 05:59:17 +01:00
Adding a popup to tell users to enable all files access on A11
For now I'm just committing this so translators can get a headstart, but it's too soon to tell if target/compile to sdk 30 in the last commit will stay
This commit is contained in:
parent
e2d3164c51
commit
47c2f5f97f
@ -1,6 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.data.download
|
package eu.kanade.tachiyomi.data.download
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
@ -141,7 +143,10 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
|
|
||||||
val title = download.manga.title.chop(15)
|
val title = download.manga.title.chop(15)
|
||||||
val quotedTitle = Pattern.quote(title)
|
val quotedTitle = Pattern.quote(title)
|
||||||
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
val chapter = download.chapter.name.replaceFirst(
|
||||||
|
"$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE),
|
||||||
|
""
|
||||||
|
)
|
||||||
setContentTitle("$title - $chapter".chop(30))
|
setContentTitle("$title - $chapter".chop(30))
|
||||||
setContentText(
|
setContentText(
|
||||||
context.getString(R.string.downloading_progress)
|
context.getString(R.string.downloading_progress)
|
||||||
@ -218,17 +223,36 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
* @param error string containing error information.
|
* @param error string containing error information.
|
||||||
* @param chapter string containing chapter title.
|
* @param chapter string containing chapter title.
|
||||||
*/
|
*/
|
||||||
fun onError(error: String? = null, chapter: String? = null) {
|
fun onError(
|
||||||
|
error: String? = null,
|
||||||
|
chapter: String? = null,
|
||||||
|
customIntent: Intent? = null
|
||||||
|
) {
|
||||||
// Create notification
|
// Create notification
|
||||||
with(notification) {
|
with(notification) {
|
||||||
setContentTitle(chapter ?: context.getString(R.string.download_error))
|
setContentTitle(chapter ?: context.getString(R.string.download_error))
|
||||||
setContentText(error ?: context.getString(R.string.could_not_download_unexpected_error))
|
setContentText(error ?: context.getString(R.string.could_not_download_unexpected_error))
|
||||||
setStyle(NotificationCompat.BigTextStyle().bigText(error ?: context.getString(R.string.could_not_download_unexpected_error)))
|
setStyle(
|
||||||
|
NotificationCompat.BigTextStyle().bigText(
|
||||||
|
error ?: context.getString(R.string.could_not_download_unexpected_error)
|
||||||
|
)
|
||||||
|
)
|
||||||
setSmallIcon(android.R.drawable.stat_sys_warning)
|
setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||||
setCategory(NotificationCompat.CATEGORY_ERROR)
|
setCategory(NotificationCompat.CATEGORY_ERROR)
|
||||||
clearActions()
|
clearActions()
|
||||||
setAutoCancel(true)
|
setAutoCancel(true)
|
||||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
if (customIntent != null) {
|
||||||
|
setContentIntent(
|
||||||
|
PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
customIntent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||||
|
}
|
||||||
color = ContextCompat.getColor(context, R.color.colorAccent)
|
color = ContextCompat.getColor(context, R.color.colorAccent)
|
||||||
setProgress(0, 0, false)
|
setProgress(0, 0, false)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
package eu.kanade.tachiyomi.data.download
|
package eu.kanade.tachiyomi.data.download
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.provider.Settings
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import com.jakewharton.rxrelay.BehaviorRelay
|
import com.jakewharton.rxrelay.BehaviorRelay
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
@ -298,7 +303,21 @@ class Downloader(
|
|||||||
notifier.onError(context.getString(R.string.couldnt_download_low_space), download.chapter.name)
|
notifier.onError(context.getString(R.string.couldnt_download_low_space), download.chapter.name)
|
||||||
return@defer Observable.just(download)
|
return@defer Observable.just(download)
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||||
|
!Environment.isExternalStorageManager()
|
||||||
|
) {
|
||||||
|
val intent = Intent(
|
||||||
|
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
|
||||||
|
"package:${context.packageName}".toUri()
|
||||||
|
)
|
||||||
|
|
||||||
|
notifier.onError(
|
||||||
|
context.getString(R.string.external_storage_download_notice),
|
||||||
|
download.chapter.name,
|
||||||
|
intent
|
||||||
|
)
|
||||||
|
return@defer Observable.just(download)
|
||||||
|
}
|
||||||
val chapterDirname = provider.getChapterDirName(download.chapter)
|
val chapterDirname = provider.getChapterDirName(download.chapter)
|
||||||
val tmpDir = mangaDir.createDirectory(chapterDirname + TMP_DIR_SUFFIX)
|
val tmpDir = mangaDir.createDirectory(chapterDirname + TMP_DIR_SUFFIX)
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.animation.AnimatorSet
|
import android.animation.AnimatorSet
|
||||||
@ -103,7 +102,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
|||||||
import eu.kanade.tachiyomi.util.view.activityBinding
|
import eu.kanade.tachiyomi.util.view.activityBinding
|
||||||
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||||
import eu.kanade.tachiyomi.util.view.getText
|
import eu.kanade.tachiyomi.util.view.getText
|
||||||
import eu.kanade.tachiyomi.util.view.requestPermissionsSafe
|
import eu.kanade.tachiyomi.util.view.requestFilePermissionsSafe
|
||||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||||
import eu.kanade.tachiyomi.util.view.setStyle
|
import eu.kanade.tachiyomi.util.view.setStyle
|
||||||
@ -215,7 +214,7 @@ class MangaDetailsController :
|
|||||||
presenter.onCreate()
|
presenter.onCreate()
|
||||||
binding.swipeRefresh.isRefreshing = presenter.isLoading
|
binding.swipeRefresh.isRefreshing = presenter.isLoading
|
||||||
binding.swipeRefresh.setOnRefreshListener { presenter.refreshAll() }
|
binding.swipeRefresh.setOnRefreshListener { presenter.refreshAll() }
|
||||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
requestFilePermissionsSafe(301)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if device is tablet, and use a second recycler to hold the details header if so */
|
/** Check if device is tablet, and use a second recycler to hold the details header if so */
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recents
|
package eu.kanade.tachiyomi.ui.recents
|
||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -52,7 +51,7 @@ import eu.kanade.tachiyomi.util.view.activityBinding
|
|||||||
import eu.kanade.tachiyomi.util.view.expand
|
import eu.kanade.tachiyomi.util.view.expand
|
||||||
import eu.kanade.tachiyomi.util.view.isCollapsed
|
import eu.kanade.tachiyomi.util.view.isCollapsed
|
||||||
import eu.kanade.tachiyomi.util.view.isExpanded
|
import eu.kanade.tachiyomi.util.view.isExpanded
|
||||||
import eu.kanade.tachiyomi.util.view.requestPermissionsSafe
|
import eu.kanade.tachiyomi.util.view.requestFilePermissionsSafe
|
||||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||||
import eu.kanade.tachiyomi.util.view.setStyle
|
import eu.kanade.tachiyomi.util.view.setStyle
|
||||||
@ -364,7 +363,7 @@ class RecentsController(bundle: Bundle? = null) :
|
|||||||
binding.downloadBottomSheet.dlBottomSheet.sheetBehavior?.expand()
|
binding.downloadBottomSheet.dlBottomSheet.sheetBehavior?.expand()
|
||||||
}
|
}
|
||||||
setPadding(binding.downloadBottomSheet.dlBottomSheet.sheetBehavior?.isHideable == true)
|
setPadding(binding.downloadBottomSheet.dlBottomSheet.sheetBehavior?.isHideable == true)
|
||||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
requestFilePermissionsSafe(301)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTitleAndMenu() {
|
fun updateTitleAndMenu() {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
@ -29,7 +28,7 @@ import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import eu.kanade.tachiyomi.util.system.getFilePicker
|
import eu.kanade.tachiyomi.util.system.getFilePicker
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.requestPermissionsSafe
|
import eu.kanade.tachiyomi.util.view.requestFilePermissionsSafe
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
@ -43,7 +42,7 @@ class SettingsBackupController : SettingsController() {
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 500)
|
requestFilePermissionsSafe(500)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.ui.source
|
package eu.kanade.tachiyomi.ui.source
|
||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
@ -48,7 +47,7 @@ import eu.kanade.tachiyomi.util.view.collapse
|
|||||||
import eu.kanade.tachiyomi.util.view.expand
|
import eu.kanade.tachiyomi.util.view.expand
|
||||||
import eu.kanade.tachiyomi.util.view.isCollapsed
|
import eu.kanade.tachiyomi.util.view.isCollapsed
|
||||||
import eu.kanade.tachiyomi.util.view.isExpanded
|
import eu.kanade.tachiyomi.util.view.isExpanded
|
||||||
import eu.kanade.tachiyomi.util.view.requestPermissionsSafe
|
import eu.kanade.tachiyomi.util.view.requestFilePermissionsSafe
|
||||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
@ -159,7 +158,7 @@ class BrowseController :
|
|||||||
updateTitleAndMenu()
|
updateTitleAndMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
requestFilePermissionsSafe(301)
|
||||||
binding.bottomSheet.root.onCreate(this)
|
binding.bottomSheet.root.onCreate(this)
|
||||||
|
|
||||||
binding.shadow.alpha =
|
binding.shadow.alpha =
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package eu.kanade.tachiyomi.util.view
|
package eu.kanade.tachiyomi.util.view
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.provider.Settings
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -18,6 +22,7 @@ import androidx.core.net.toUri
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.bluelinelabs.conductor.Controller
|
import com.bluelinelabs.conductor.Controller
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
@ -480,6 +485,42 @@ fun Controller.requestPermissionsSafe(permissions: Array<String>, requestCode: I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Controller.requestFilePermissionsSafe(requestCode: Int) {
|
||||||
|
val activity = activity ?: return
|
||||||
|
val permissions = mutableListOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
|
permissions.forEach { permission ->
|
||||||
|
if (ContextCompat.checkSelfPermission(
|
||||||
|
activity,
|
||||||
|
permission
|
||||||
|
) != PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
|
requestPermissions(arrayOf(permission), requestCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||||
|
!Environment.isExternalStorageManager()
|
||||||
|
) {
|
||||||
|
MaterialDialog(activity)
|
||||||
|
.title(R.string.all_files_permission_required)
|
||||||
|
.message(R.string.external_storage_permission_notice)
|
||||||
|
.cancelOnTouchOutside(false)
|
||||||
|
.positiveButton(android.R.string.ok) {
|
||||||
|
val intent = Intent(
|
||||||
|
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
|
||||||
|
"package:${activity.packageName}".toUri()
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
activity.startActivity(intent)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
val intent2 = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
|
||||||
|
activity.startActivity(intent2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.negativeButton(android.R.string.cancel)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Controller.withFadeTransaction(): RouterTransaction {
|
fun Controller.withFadeTransaction(): RouterTransaction {
|
||||||
return RouterTransaction.with(this)
|
return RouterTransaction.with(this)
|
||||||
.pushChangeHandler(OneWayFadeChangeHandler())
|
.pushChangeHandler(OneWayFadeChangeHandler())
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
<string name="app_name" translatable="false">TachiyomiJ2K</string>
|
<string name="app_name" translatable="false">TachiyomiJ2K</string>
|
||||||
<string name="app_short_name" translatable="false">TachiJ2K</string>
|
<string name="app_short_name" translatable="false">TachiJ2K</string>
|
||||||
|
|
||||||
|
<string name="all_files_permission_required">File permissions required</string>
|
||||||
|
<string name="external_storage_permission_notice">TachiyomiJ2K requires access to all files in Android 11 to download chapters, create automatic backups, and read local manga. \n\nOn the next screen, enable \"Allow access to manage all files.\"</string>
|
||||||
|
<string name="external_storage_download_notice">TachiyomiJ2K requires access to all files to download chapters. Tap here, then enable \"Allow access to manage all files.\"</string>
|
||||||
|
|
||||||
<!--Models-->
|
<!--Models-->
|
||||||
|
|
||||||
<!-- Manga Type -->
|
<!-- Manga Type -->
|
||||||
|
Loading…
Reference in New Issue
Block a user