pull/913/head
gedoor 4 years ago
parent e74a7cdb4f
commit 59cb14f0a1
  1. 4
      app/src/main/AndroidManifest.xml
  2. 20
      app/src/main/java/io/legado/app/help/permission/ActivitySource.kt
  3. 19
      app/src/main/java/io/legado/app/help/permission/FragmentSource.kt
  4. 7
      app/src/main/java/io/legado/app/help/permission/OnPermissionsDeniedCallback.kt
  5. 7
      app/src/main/java/io/legado/app/help/permission/OnPermissionsGrantedCallback.kt
  6. 9
      app/src/main/java/io/legado/app/help/permission/OnPermissionsResultCallback.kt
  7. 14
      app/src/main/java/io/legado/app/help/permission/OnRequestPermissionsResultCallback.kt
  8. 84
      app/src/main/java/io/legado/app/help/permission/PermissionActivity.kt
  9. 2
      app/src/main/java/io/legado/app/help/permission/Permissions.kt
  10. 94
      app/src/main/java/io/legado/app/help/permission/PermissionsCompat.kt
  11. 204
      app/src/main/java/io/legado/app/help/permission/Request.kt
  12. 69
      app/src/main/java/io/legado/app/help/permission/RequestManager.kt
  13. 20
      app/src/main/java/io/legado/app/help/permission/RequestPlugins.kt
  14. 12
      app/src/main/java/io/legado/app/help/permission/RequestSource.kt
  15. 6
      app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt
  16. 48
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt
  17. 19
      app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt
  18. 29
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  19. 18
      app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt
  20. 15
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  21. 72
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  22. 38
      app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt
  23. 2
      app/src/main/java/io/legado/app/ui/filepicker/FilePickerDialog.kt
  24. 2
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
  25. 19
      app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt

@ -171,6 +171,10 @@
<activity
android:name=".ui.audio.AudioPlayActivity"
android:launchMode="singleTask" />
<!-- 授权界面 -->
<activity
android:name=".help.permission.PermissionActivity"
android:theme="@style/Activity.Permission" />
<!-- 二维码扫描 -->
<activity
android:name=".ui.qrcode.QrCodeActivity"

@ -0,0 +1,20 @@
package io.legado.app.help.permission
import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import java.lang.ref.WeakReference
internal class ActivitySource(activity: AppCompatActivity) : RequestSource {
private val actRef: WeakReference<AppCompatActivity> = WeakReference(activity)
override val context: Context?
get() = actRef.get()
override fun startActivity(intent: Intent) {
actRef.get()?.startActivity(intent)
}
}

@ -0,0 +1,19 @@
package io.legado.app.help.permission
import android.content.Context
import android.content.Intent
import androidx.fragment.app.Fragment
import java.lang.ref.WeakReference
internal class FragmentSource(fragment: Fragment) : RequestSource {
private val fragRef: WeakReference<Fragment> = WeakReference(fragment)
override val context: Context?
get() = fragRef.get()?.requireContext()
override fun startActivity(intent: Intent) {
fragRef.get()?.startActivity(intent)
}
}

@ -0,0 +1,7 @@
package io.legado.app.help.permission
interface OnPermissionsDeniedCallback {
fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>)
}

@ -0,0 +1,7 @@
package io.legado.app.help.permission
interface OnPermissionsGrantedCallback {
fun onPermissionsGranted(requestCode: Int)
}

@ -0,0 +1,9 @@
package io.legado.app.help.permission
interface OnPermissionsResultCallback {
fun onPermissionsGranted(requestCode: Int)
fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>)
}

@ -0,0 +1,14 @@
package io.legado.app.help.permission
import android.content.Intent
interface OnRequestPermissionsResultCallback {
fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
)
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
}

@ -0,0 +1,84 @@
package io.legado.app.help.permission
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.view.KeyEvent
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import io.legado.app.R
import io.legado.app.utils.toastOnUi
class PermissionActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) {
Request.TYPE_REQUEST_PERMISSION//权限请求
-> {
val requestCode = intent.getIntExtra(KEY_INPUT_PERMISSIONS_CODE, 1000)
val permissions = intent.getStringArrayExtra(KEY_INPUT_PERMISSIONS)
if (permissions != null) {
ActivityCompat.requestPermissions(this, permissions, requestCode)
} else {
finish()
}
}
Request.TYPE_REQUEST_SETTING//跳转到设置界面
-> try {
val settingIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
settingIntent.data = Uri.fromParts("package", packageName, null)
startActivityForResult(settingIntent, Request.TYPE_REQUEST_SETTING)
} catch (e: Exception) {
toastOnUi(R.string.tip_cannot_jump_setting_page)
finish()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
RequestPlugins.sRequestCallback?.onRequestPermissionsResult(
requestCode,
permissions,
grantResults
)
finish()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
RequestPlugins.sRequestCallback?.onActivityResult(requestCode, resultCode, data)
finish()
}
override fun startActivity(intent: Intent) {
super.startActivity(intent)
overridePendingTransition(0, 0)
}
override fun finish() {
super.finish()
overridePendingTransition(0, 0)
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
return if (keyCode == KeyEvent.KEYCODE_BACK) {
true
} else super.onKeyDown(keyCode, event)
}
companion object {
const val KEY_INPUT_REQUEST_TYPE = "KEY_INPUT_REQUEST_TYPE"
const val KEY_INPUT_PERMISSIONS_CODE = "KEY_INPUT_PERMISSIONS_CODE"
const val KEY_INPUT_PERMISSIONS = "KEY_INPUT_PERMISSIONS"
}
}

@ -1,4 +1,4 @@
package io.legado.app.constant
package io.legado.app.help.permission
@Suppress("unused")
object Permissions {

@ -0,0 +1,94 @@
package io.legado.app.help.permission
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import java.util.*
@Suppress("unused")
class PermissionsCompat private constructor() {
private var request: Request? = null
fun request() {
RequestManager.pushRequest(request)
}
companion object {
// 检查权限, 如果已经拥有返回 true
fun check(activity: AppCompatActivity, vararg permissions: String): Boolean {
val request = Request(activity)
val pers = ArrayList<String>()
pers.addAll(listOf(*permissions))
val data = request.getDeniedPermissions(pers.toTypedArray())
return data == null
}
}
class Builder {
private val request: Request
constructor(activity: AppCompatActivity) {
request = Request(activity)
}
constructor(fragment: Fragment) {
request = Request(fragment)
}
fun addPermissions(vararg permissions: String): Builder {
request.addPermissions(*permissions)
return this
}
fun requestCode(requestCode: Int): Builder {
request.setRequestCode(requestCode)
return this
}
fun onGranted(callback: (requestCode: Int) -> Unit): Builder {
request.setOnGrantedCallback(object : OnPermissionsGrantedCallback {
override fun onPermissionsGranted(requestCode: Int) {
callback(requestCode)
}
})
return this
}
fun onDenied(callback: (requestCode: Int, deniedPermissions: Array<String>) -> Unit): Builder {
request.setOnDeniedCallback(object : OnPermissionsDeniedCallback {
override fun onPermissionsDenied(
requestCode: Int,
deniedPermissions: Array<String>
) {
callback(requestCode, deniedPermissions)
}
})
return this
}
fun rationale(rationale: CharSequence): Builder {
request.setRationale(rationale)
return this
}
fun rationale(@StringRes resId: Int): Builder {
request.setRationale(resId)
return this
}
fun build(): PermissionsCompat {
val compat = PermissionsCompat()
compat.request = request
return compat
}
fun request(): PermissionsCompat {
val compat = build()
compat.request = request
compat.request()
return compat
}
}
}

@ -0,0 +1,204 @@
package io.legado.app.help.permission
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import io.legado.app.R
import io.legado.app.utils.startActivity
import java.util.*
internal class Request : OnRequestPermissionsResultCallback {
internal val requestTime: Long
private var requestCode: Int = TYPE_REQUEST_PERMISSION
private var source: RequestSource? = null
private var permissions: ArrayList<String>? = null
private var grantedCallback: OnPermissionsGrantedCallback? = null
private var deniedCallback: OnPermissionsDeniedCallback? = null
private var rationaleResId: Int = 0
private var rationale: CharSequence? = null
private var rationaleDialog: AlertDialog? = null
private val deniedPermissions: Array<String>?
get() {
return getDeniedPermissions(this.permissions?.toTypedArray())
}
constructor(activity: AppCompatActivity) {
source = ActivitySource(activity)
permissions = ArrayList()
requestTime = System.currentTimeMillis()
}
constructor(fragment: Fragment) {
source = FragmentSource(fragment)
permissions = ArrayList()
requestTime = System.currentTimeMillis()
}
fun addPermissions(vararg permissions: String) {
this.permissions?.addAll(listOf(*permissions))
}
fun setRequestCode(requestCode: Int) {
this.requestCode = requestCode
}
fun setOnGrantedCallback(callback: OnPermissionsGrantedCallback) {
grantedCallback = callback
}
fun setOnDeniedCallback(callback: OnPermissionsDeniedCallback) {
deniedCallback = callback
}
fun setRationale(@StringRes resId: Int) {
rationaleResId = resId
rationale = null
}
fun setRationale(rationale: CharSequence) {
this.rationale = rationale
rationaleResId = 0
}
fun start() {
RequestPlugins.setOnRequestPermissionsCallback(this)
val deniedPermissions = deniedPermissions
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
if (deniedPermissions == null) {
onPermissionsGranted(requestCode)
} else {
val rationale =
if (rationaleResId != 0) source?.context?.getText(rationaleResId) else rationale
if (rationale != null) {
showSettingDialog(rationale) {
onPermissionsDenied(
requestCode,
deniedPermissions
)
}
} else {
onPermissionsDenied(requestCode, deniedPermissions)
}
}
} else {
if (deniedPermissions != null) {
source?.context?.startActivity<PermissionActivity> {
putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION)
putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
}
} else {
onPermissionsGranted(requestCode)
}
}
}
fun clear() {
grantedCallback = null
deniedCallback = null
}
fun getDeniedPermissions(permissions: Array<String>?): Array<String>? {
if (permissions != null) {
val deniedPermissionList = ArrayList<String>()
for (permission in permissions) {
if (source?.context?.let {
ContextCompat.checkSelfPermission(
it,
permission
)
} != PackageManager.PERMISSION_GRANTED
) {
deniedPermissionList.add(permission)
}
}
val size = deniedPermissionList.size
if (size > 0) {
return deniedPermissionList.toTypedArray()
}
}
return null
}
private fun showSettingDialog(rationale: CharSequence, cancel: () -> Unit) {
rationaleDialog?.dismiss()
source?.context?.let {
runCatching {
rationaleDialog = AlertDialog.Builder(it)
.setTitle(R.string.dialog_title)
.setMessage(rationale)
.setPositiveButton(R.string.dialog_setting) { _, _ ->
it.startActivity<PermissionActivity> {
putExtra(
PermissionActivity.KEY_INPUT_REQUEST_TYPE,
TYPE_REQUEST_SETTING
)
}
}
.setNegativeButton(R.string.dialog_cancel) { _, _ -> cancel() }
.show()
}
}
}
private fun onPermissionsGranted(requestCode: Int) {
try {
grantedCallback?.onPermissionsGranted(requestCode)
} catch (ignore: Exception) {
}
RequestPlugins.sResultCallback?.onPermissionsGranted(requestCode)
}
private fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>) {
try {
deniedCallback?.onPermissionsDenied(requestCode, deniedPermissions)
} catch (ignore: Exception) {
}
RequestPlugins.sResultCallback?.onPermissionsDenied(requestCode, deniedPermissions)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
val deniedPermissions = getDeniedPermissions(permissions)
if (deniedPermissions != null) {
val rationale =
if (rationaleResId != 0) source?.context?.getText(rationaleResId) else rationale
if (rationale != null) {
showSettingDialog(rationale) { onPermissionsDenied(requestCode, deniedPermissions) }
} else {
onPermissionsDenied(requestCode, deniedPermissions)
}
} else {
onPermissionsGranted(requestCode)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val deniedPermissions = deniedPermissions
if (deniedPermissions == null) {
onPermissionsGranted(this.requestCode)
} else {
onPermissionsDenied(this.requestCode, deniedPermissions)
}
}
companion object {
const val TYPE_REQUEST_PERMISSION = 1
const val TYPE_REQUEST_SETTING = 2
}
}

@ -0,0 +1,69 @@
package io.legado.app.help.permission
import android.os.Handler
import android.os.Looper
import java.util.*
internal object RequestManager : OnPermissionsResultCallback {
private var requests: Stack<Request>? = null
private var request: Request? = null
private val handler = Handler(Looper.getMainLooper())
private val requestRunnable = Runnable {
request?.start()
}
private val isCurrentRequestInvalid: Boolean
get() = request?.let { System.currentTimeMillis() - it.requestTime > 5 * 1000L } ?: true
init {
RequestPlugins.setOnPermissionsResultCallback(this)
}
fun pushRequest(request: Request?) {
if (request == null) return
if (requests == null) {
requests = Stack()
}
requests?.let {
val index = it.indexOf(request)
if (index >= 0) {
val to = it.size - 1
if (index != to) {
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
Collections.swap(requests, index, to)
}
} else {
it.push(request)
}
if (!it.empty() && isCurrentRequestInvalid) {
this.request = it.pop()
handler.post(requestRunnable)
}
}
}
private fun startNextRequest() {
request?.clear()
request = null
requests?.let {
request = if (it.empty()) null else it.pop()
request?.let { handler.post(requestRunnable) }
}
}
override fun onPermissionsGranted(requestCode: Int) {
startNextRequest()
}
override fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>) {
startNextRequest()
}
}

@ -0,0 +1,20 @@
package io.legado.app.help.permission
internal object RequestPlugins {
@Volatile
var sRequestCallback: OnRequestPermissionsResultCallback? = null
@Volatile
var sResultCallback: OnPermissionsResultCallback? = null
fun setOnRequestPermissionsCallback(callback: OnRequestPermissionsResultCallback) {
sRequestCallback = callback
}
fun setOnPermissionsResultCallback(callback: OnPermissionsResultCallback) {
sResultCallback = callback
}
}

@ -0,0 +1,12 @@
package io.legado.app.help.permission
import android.content.Context
import android.content.Intent
interface RequestSource {
val context: Context?
fun startActivity(intent: Intent)
}

@ -68,7 +68,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
toastOnUi(R.string.error_get_book_info)
}
} ?: let {
chapterListData.postValue(emptyList())
chapterListData.postValue(null)
toastOnUi(R.string.error_no_source)
}
}
@ -104,11 +104,11 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
toastOnUi(R.string.chapter_list_empty)
}
}.onError {
chapterListData.postValue(emptyList())
chapterListData.postValue(null)
toastOnUi(R.string.error_get_chapter_list)
}
} ?: let {
chapterListData.postValue(emptyList())
chapterListData.postValue(null)
toastOnUi(R.string.error_no_source)
}
}

@ -1,18 +1,19 @@
package io.legado.app.ui.book.info.edit
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.documentfile.provider.DocumentFile
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.Permissions
import io.legado.app.data.entities.Book
import io.legado.app.databinding.ActivityBookInfoEditBinding
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.ui.book.changecover.ChangeCoverDialog
import io.legado.app.utils.*
import java.io.File
@ -21,9 +22,7 @@ class BookInfoEditActivity :
VMBaseActivity<ActivityBookInfoEditBinding, BookInfoEditViewModel>(),
ChangeCoverDialog.CallBack {
private val selectCover = registerForActivityResult(ActivityResultContracts.GetContent()) {
coverChangeTo(it)
}
private val resultSelectCover = 132
override val viewModel: BookInfoEditViewModel
by viewModels()
@ -61,7 +60,7 @@ class BookInfoEditActivity :
}
}
tvSelectCover.setOnClickListener {
selectCover.launch("image/*")
selectImage()
}
tvRefreshCover.setOnClickListener {
viewModel.book?.customCoverUrl = tieCoverUrl.text?.toString()
@ -97,6 +96,13 @@ class BookInfoEditActivity :
}
}
private fun selectImage() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, resultSelectCover)
}
override fun coverChangeTo(coverUrl: String) {
viewModel.book?.customCoverUrl = coverUrl
binding.tieCoverUrl.setText(coverUrl)
@ -117,15 +123,13 @@ class BookInfoEditActivity :
} ?: toastOnUi("获取文件出错")
}
} else {
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
var hasPermission = true
it.forEach { (t, u) ->
if (!u) {
hasPermission = false
toastOnUi(t)
}
}
if (hasPermission) {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.onGranted {
RealPathUtil.getPath(this, uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
@ -136,8 +140,20 @@ class BookInfoEditActivity :
}
}
}
}.launch(Permissions.Group.STORAGE)
.request()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
resultSelectCover -> {
if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
coverChangeTo(uri)
}
}
}
}
}
}

@ -8,7 +8,6 @@ import android.os.Bundle
import android.provider.DocumentsContract
import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.widget.PopupMenu
import androidx.documentfile.provider.DocumentFile
@ -16,10 +15,11 @@ import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.Permissions
import io.legado.app.data.appDb
import io.legado.app.databinding.ActivityImportBookBinding
import io.legado.app.help.AppConfig
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.ui.filepicker.FilePicker
import io.legado.app.ui.filepicker.FilePickerDialog
@ -148,21 +148,16 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
}
else -> {
binding.tvEmptyMsg.visible()
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
var hasPermission = true
it.forEach { (t, u) ->
if (!u) {
hasPermission = false
toastOnUi(t)
}
}
if (hasPermission) {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
rootDoc = null
subDocs.clear()
path = lastPath
upPath()
}
}.launch(Permissions.Group.STORAGE)
.request()
}
}
}

@ -8,17 +8,17 @@ import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.view.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import com.jaredrummler.android.colorpicker.ColorPickerDialog
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.constant.EventBus
import io.legado.app.constant.Permissions
import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.databinding.DialogReadBgTextBinding
import io.legado.app.databinding.ItemBgImageBinding
import io.legado.app.help.ReadBookConfig
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.theme.bottomBackground
import io.legado.app.lib.theme.getPrimaryTextColor
@ -40,6 +40,7 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack {
}
private val binding by viewBinding(DialogReadBgTextBinding::bind)
private val requestCodeBg = 123
private val requestCodeExport = 131
private val requestCodeImport = 132
private val configFileName = "readConfig.zip"
@ -190,9 +191,10 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack {
}
private fun selectImage() {
registerForActivityResult(ActivityResultContracts.GetContent()) {
setBgFromUri(it)
}.launch("image/*")
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, requestCodeBg)
}
@Suppress("BlockingMethodInNonBlockingContext")
@ -369,7 +371,13 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
requestCodeBg -> if (resultCode == RESULT_OK) {
data?.data?.let { uri ->
setBgFromUri(uri)
}
}
requestCodeImport -> if (resultCode == RESULT_OK) {
data?.data?.let { uri ->
importConfig(uri)
@ -399,13 +407,20 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack {
} ?: toastOnUi("获取文件出错")
}
} else {
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.onGranted {
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
ReadBookConfig.durConfig.setCurBg(2, path)
ReadBookConfig.upBg()
postEvent(EventBus.UP_CONFIG, false)
}
}.launch(Permissions.READ_EXTERNAL_STORAGE)
}
.request()
}
}
}

@ -7,10 +7,11 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import io.legado.app.R
import io.legado.app.constant.Permissions
import io.legado.app.constant.PreferKey
import io.legado.app.help.AppConfig
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.BookWebDav
import io.legado.app.help.storage.ImportOldData
@ -56,15 +57,10 @@ object BackupRestoreUi {
fragment: Fragment,
path: String
) {
fragment.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
var hasPermission = true
it.forEach { (t, u) ->
if (!u) {
hasPermission = false
fragment.toastOnUi(t)
}
}
if (hasPermission) {
PermissionsCompat.Builder(fragment)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
Coroutine.async {
AppConfig.backupPath = path
Backup.backup(fragment.requireContext(), path)
@ -72,7 +68,7 @@ object BackupRestoreUi {
fragment.toastOnUi(R.string.backup_success)
}
}
}.launch(Permissions.Group.STORAGE)
.request()
}
fun selectBackupFolder(fragment: Fragment, requestCode: Int = selectFolderRequestCode) {

@ -10,18 +10,18 @@ import android.net.Uri
import android.os.Bundle
import android.os.Process
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.preference.ListPreference
import androidx.preference.Preference
import io.legado.app.R
import io.legado.app.base.BasePreferenceFragment
import io.legado.app.constant.EventBus
import io.legado.app.constant.Permissions
import io.legado.app.constant.PreferKey
import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.help.AppConfig
import io.legado.app.help.BookHelp
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.theme.ATH
@ -224,7 +224,13 @@ class OtherConfigFragment : BasePreferenceFragment(),
} ?: toastOnUi("获取文件出错")
}
} else {
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.onGranted {
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
@ -235,7 +241,8 @@ class OtherConfigFragment : BasePreferenceFragment(),
CoverImageView.upDefaultCover()
}
}
}.launch(Permissions.Group.STORAGE)
}
.request()
}
}

@ -1,6 +1,8 @@
package io.legado.app.ui.config
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
@ -9,19 +11,19 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.preference.Preference
import io.legado.app.R
import io.legado.app.base.BasePreferenceFragment
import io.legado.app.constant.AppConst
import io.legado.app.constant.EventBus
import io.legado.app.constant.Permissions
import io.legado.app.constant.PreferKey
import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.help.AppConfig
import io.legado.app.help.LauncherIconHelp
import io.legado.app.help.ThemeConfig
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.theme.ATH
@ -36,17 +38,8 @@ import java.io.File
class ThemeConfigFragment : BasePreferenceFragment(),
SharedPreferences.OnSharedPreferenceChangeListener {
private val setLightBgImage = registerForActivityResult(ActivityResultContracts.GetContent()) {
setBgFromUri(it, PreferKey.bgImage) {
upTheme(false)
}
}
private val setDarkBgImage = registerForActivityResult(ActivityResultContracts.GetContent()) {
setBgFromUri(it, PreferKey.bgImageN) {
upTheme(false)
}
}
private val requestCodeBgImage = 234
private val requestCodeBgImageN = 342
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_config_theme)
@ -193,26 +186,26 @@ class ThemeConfigFragment : BasePreferenceFragment(),
"themeList" -> ThemeListDialog().show(childFragmentManager, "themeList")
"saveDayTheme", "saveNightTheme" -> saveThemeAlert(key)
PreferKey.bgImage -> if (getPrefString(PreferKey.bgImage).isNullOrEmpty()) {
setLightBgImage.launch("image/*")
selectImage(requestCodeBgImage)
} else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) {
removePref(PreferKey.bgImage)
upTheme(false)
} else {
setLightBgImage.launch("image/*")
selectImage(requestCodeBgImage)
}
}
}
PreferKey.bgImageN -> if (getPrefString(PreferKey.bgImageN).isNullOrEmpty()) {
setDarkBgImage.launch("image/*")
selectImage(requestCodeBgImageN)
} else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) {
removePref(PreferKey.bgImageN)
upTheme(true)
} else {
setDarkBgImage.launch("image/*")
selectImage(requestCodeBgImageN)
}
}
}
@ -220,6 +213,13 @@ class ThemeConfigFragment : BasePreferenceFragment(),
return super.onPreferenceTreeClick(preference)
}
private fun selectImage(requestCode: Int) {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, requestCode)
}
@SuppressLint("InflateParams")
private fun saveThemeAlert(key: String) {
alert(R.string.theme_name) {
@ -279,15 +279,13 @@ class ThemeConfigFragment : BasePreferenceFragment(),
} ?: toastOnUi("获取文件出错")
}
} else {
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
var hasPermission = true
it.forEach { (t, u) ->
if (!u) {
hasPermission = false
toastOnUi(t)
}
}
if (hasPermission) {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.onGranted {
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
@ -300,7 +298,27 @@ class ThemeConfigFragment : BasePreferenceFragment(),
}
}
}
}.launch(Permissions.Group.STORAGE)
.request()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
requestCodeBgImage -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
setBgFromUri(uri, PreferKey.bgImage) {
upTheme(false)
}
}
}
requestCodeBgImageN -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
setBgFromUri(uri, PreferKey.bgImageN) {
upTheme(true)
}
}
}
}
}

@ -5,6 +5,8 @@ import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import io.legado.app.R
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.lib.dialogs.alert
@Suppress("unused")
@ -32,6 +34,7 @@ object FilePicker {
val intent = createSelectDirIntent()
activity.startActivityForResult(intent, requestCode)
}.onFailure {
checkPermissions(activity) {
FilePickerDialog.show(
activity.supportFragmentManager,
requestCode,
@ -39,14 +42,17 @@ object FilePicker {
)
}
}
}
else -> {
val selectText = selectList[index]
if (selectText == activity.getString(R.string.app_folder_picker)) {
checkPermissions(activity) {
FilePickerDialog.show(
activity.supportFragmentManager,
requestCode,
mode = FilePickerDialog.DIRECTORY
)
}
} else {
otherFun?.invoke(selectText)
}
@ -78,6 +84,7 @@ object FilePicker {
val intent = createSelectDirIntent()
fragment.startActivityForResult(intent, requestCode)
}.onFailure {
checkPermissions(fragment) {
FilePickerDialog.show(
fragment.childFragmentManager,
requestCode,
@ -85,14 +92,17 @@ object FilePicker {
)
}
}
}
else -> {
val selectText = selectList[index]
if (selectText == fragment.getString(R.string.app_folder_picker)) {
checkPermissions(fragment) {
FilePickerDialog.show(
fragment.childFragmentManager,
requestCode,
mode = FilePickerDialog.DIRECTORY
)
}
} else {
otherFun?.invoke(selectText)
}
@ -129,6 +139,7 @@ object FilePicker {
)
activity.startActivityForResult(intent, requestCode)
}.onFailure {
checkPermissions(activity) {
FilePickerDialog.show(
activity.supportFragmentManager,
requestCode,
@ -137,15 +148,18 @@ object FilePicker {
)
}
}
}
else -> {
val selectText = selectList[index]
if (selectText == activity.getString(R.string.app_file_picker)) {
checkPermissions(activity) {
FilePickerDialog.show(
activity.supportFragmentManager,
requestCode,
mode = FilePickerDialog.FILE,
allowExtensions = allowExtensions
)
}
} else {
otherFun?.invoke(selectText)
}
@ -182,6 +196,7 @@ object FilePicker {
)
fragment.startActivityForResult(intent, requestCode)
}.onFailure {
checkPermissions(fragment) {
FilePickerDialog.show(
fragment.childFragmentManager,
requestCode,
@ -190,15 +205,18 @@ object FilePicker {
)
}
}
}
else -> {
val selectText = selectList[index]
if (selectText == fragment.getString(R.string.app_file_picker)) {
checkPermissions(fragment) {
FilePickerDialog.show(
fragment.childFragmentManager,
requestCode,
mode = FilePickerDialog.FILE,
allowExtensions = allowExtensions
)
}
} else {
otherFun?.invoke(selectText)
}
@ -228,6 +246,26 @@ object FilePicker {
return intent
}
private fun checkPermissions(fragment: Fragment, success: (() -> Unit)? = null) {
PermissionsCompat.Builder(fragment)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
success?.invoke()
}
.request()
}
private fun checkPermissions(activity: AppCompatActivity, success: (() -> Unit)? = null) {
PermissionsCompat.Builder(activity)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
success?.invoke()
}
.request()
}
private fun typesOfExtensions(allowExtensions: Array<String>): Array<String> {
val types = hashSetOf<String>()
if (allowExtensions.isNullOrEmpty()) {

@ -15,8 +15,8 @@ import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.constant.Permissions
import io.legado.app.databinding.DialogFileChooserBinding
import io.legado.app.help.permission.Permissions
import io.legado.app.lib.theme.primaryColor
import io.legado.app.ui.filepicker.adapter.FileAdapter
import io.legado.app.ui.filepicker.adapter.PathAdapter

@ -53,7 +53,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
rssArticle = rssStar?.toRssArticle() ?: appDb.rssArticleDao.get(origin, link)
rssArticle?.let { rssArticle ->
if (!rssArticle.description.isNullOrBlank()) {
contentLiveData.postValue(rssArticle.description!!)
contentLiveData.postValue(rssArticle.description)
} else {
rssSource?.let {
val ruleContent = it.ruleContent

@ -8,16 +8,16 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.Toolbar
import androidx.documentfile.provider.DocumentFile
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.constant.Permissions
import io.legado.app.constant.PreferKey
import io.legado.app.databinding.DialogFontSelectBinding
import io.legado.app.help.AppConfig
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.theme.primaryColor
import io.legado.app.ui.filepicker.FilePicker
@ -162,18 +162,13 @@ class FontSelectDialog : BaseDialogFragment(),
}
private fun loadFontFilesByPermission(path: String) {
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
var hasPermission = true
it.forEach { (t, u) ->
if (!u) {
hasPermission = false
toastOnUi(t)
}
}
if (hasPermission) {
PermissionsCompat.Builder(this@FontSelectDialog)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
loadFontFiles(path)
}
}.launch(Permissions.Group.STORAGE)
.request()
}
private fun loadFontFiles(path: String) {

Loading…
Cancel
Save