kunfei пре 3 година
родитељ
комит
997887d6fa
27 измењених фајлова са 221 додато и 239 уклоњено
  1. 24 0
      app/src/main/java/io/legado/app/base/BaseService.kt
  2. 0 20
      app/src/main/java/io/legado/app/lib/permission/ActivitySource.kt
  3. 0 19
      app/src/main/java/io/legado/app/lib/permission/FragmentSource.kt
  4. 60 28
      app/src/main/java/io/legado/app/lib/permission/PermissionActivity.kt
  5. 1 11
      app/src/main/java/io/legado/app/lib/permission/PermissionsCompat.kt
  6. 55 113
      app/src/main/java/io/legado/app/lib/permission/Request.kt
  7. 0 12
      app/src/main/java/io/legado/app/lib/permission/RequestSource.kt
  8. 1 1
      app/src/main/java/io/legado/app/service/AudioPlayService.kt
  9. 1 1
      app/src/main/java/io/legado/app/service/BaseReadAloudService.kt
  10. 1 1
      app/src/main/java/io/legado/app/service/CheckSourceService.kt
  11. 1 1
      app/src/main/java/io/legado/app/service/WebService.kt
  12. 1 1
      app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt
  13. 1 1
      app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt
  14. 2 2
      app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt
  15. 1 1
      app/src/main/java/io/legado/app/ui/document/HandleFileActivity.kt
  16. 1 1
      app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt
  17. 0 23
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  18. 54 1
      app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt
  19. 2 2
      app/src/main/java/io/legado/app/utils/UriExtensions.kt
  20. 8 0
      app/src/main/res/layout/activity_rss_source_edit.xml
  21. 1 0
      app/src/main/res/values-es-rES/strings.xml
  22. 1 0
      app/src/main/res/values-ja-rJP/strings.xml
  23. 1 0
      app/src/main/res/values-pt-rBR/strings.xml
  24. 1 0
      app/src/main/res/values-zh-rHK/strings.xml
  25. 1 0
      app/src/main/res/values-zh-rTW/strings.xml
  26. 1 0
      app/src/main/res/values-zh/strings.xml
  27. 1 0
      app/src/main/res/values/strings.xml

+ 24 - 0
app/src/main/java/io/legado/app/base/BaseService.kt

@@ -4,8 +4,11 @@ import android.content.Intent
 import android.os.IBinder
 import android.os.IBinder
 import androidx.annotation.CallSuper
 import androidx.annotation.CallSuper
 import androidx.lifecycle.LifecycleService
 import androidx.lifecycle.LifecycleService
+import io.legado.app.R
 import io.legado.app.help.LifecycleHelp
 import io.legado.app.help.LifecycleHelp
 import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.help.coroutine.Coroutine
+import io.legado.app.lib.permission.Permissions
+import io.legado.app.lib.permission.PermissionsCompat
 import kotlinx.coroutines.*
 import kotlinx.coroutines.*
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.CoroutineContext
 
 
@@ -22,6 +25,7 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() {
     override fun onCreate() {
     override fun onCreate() {
         super.onCreate()
         super.onCreate()
         LifecycleHelp.onServiceCreate(this)
         LifecycleHelp.onServiceCreate(this)
+        checkNotificationPermission()
     }
     }
 
 
     @CallSuper
     @CallSuper
@@ -41,4 +45,24 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() {
         cancel()
         cancel()
         LifecycleHelp.onServiceDestroy(this)
         LifecycleHelp.onServiceDestroy(this)
     }
     }
+
+    /**
+     * 更新通知
+     */
+    open fun upNotification() {
+
+    }
+
+    /**
+     * 检测通知权限
+     */
+    private fun checkNotificationPermission()  {
+        PermissionsCompat.Builder()
+            .addPermissions(Permissions.POST_NOTIFICATIONS)
+            .rationale(R.string.notification_permission_rationale)
+            .onGranted {
+                upNotification()
+            }
+            .request()
+    }
 }
 }

+ 0 - 20
app/src/main/java/io/legado/app/lib/permission/ActivitySource.kt

@@ -1,20 +0,0 @@
-package io.legado.app.lib.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 - 19
app/src/main/java/io/legado/app/lib/permission/FragmentSource.kt

@@ -1,19 +0,0 @@
-package io.legado.app.lib.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)
-    }
-}

+ 60 - 28
app/src/main/java/io/legado/app/lib/permission/PermissionActivity.kt

@@ -7,6 +7,7 @@ import android.os.Bundle
 import android.provider.Settings
 import android.provider.Settings
 import android.view.KeyEvent
 import android.view.KeyEvent
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.app.ActivityCompat
 import androidx.core.app.ActivityCompat
 import io.legado.app.R
 import io.legado.app.R
@@ -15,6 +16,8 @@ import io.legado.app.utils.toastOnUi
 
 
 class PermissionActivity : AppCompatActivity() {
 class PermissionActivity : AppCompatActivity() {
 
 
+    private var rationaleDialog: AlertDialog? = null
+
     private val settingActivityResult =
     private val settingActivityResult =
         registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
         registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
             RequestPlugins.sRequestCallback?.onSettingActivityResult()
             RequestPlugins.sRequestCallback?.onSettingActivityResult()
@@ -23,42 +26,45 @@ class PermissionActivity : AppCompatActivity() {
 
 
     override fun onCreate(savedInstanceState: Bundle?) {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         super.onCreate(savedInstanceState)
+        val rationale = intent.getStringExtra(KEY_RATIONALE)
         val requestCode = intent.getIntExtra(KEY_INPUT_PERMISSIONS_CODE, 1000)
         val requestCode = intent.getIntExtra(KEY_INPUT_PERMISSIONS_CODE, 1000)
-        val permissions = intent.getStringArrayExtra(KEY_INPUT_PERMISSIONS)
+        val permissions = intent.getStringArrayExtra(KEY_INPUT_PERMISSIONS)!!
         when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) {
         when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) {
             //权限请求
             //权限请求
-            Request.TYPE_REQUEST_PERMISSION -> {
-                if (permissions != null) {
-                    ActivityCompat.requestPermissions(this, permissions, requestCode)
-                } else {
-                    finish()
-                }
+            Request.TYPE_REQUEST_PERMISSION -> showSettingDialog(permissions, rationale){
+                ActivityCompat.requestPermissions(this, permissions, requestCode)
             }
             }
             //跳转到设置界面
             //跳转到设置界面
-            Request.TYPE_REQUEST_SETTING -> openSettingsActivity()
+            Request.TYPE_REQUEST_SETTING -> showSettingDialog(permissions, rationale) {
+                openSettingsActivity()
+            }
             //所有文件的管理权限
             //所有文件的管理权限
-            Request.TYPE_MANAGE_ALL_FILES_ACCESS_PERMISSION -> try {
-                if (Permissions.isManageExternalStorage()) {
-                    val settingIntent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
-                    settingActivityResult.launch(settingIntent)
-                } else {
-                    throw NoStackTraceException("no MANAGE_ALL_FILES_ACCESS_PERMISSION")
+            Request.TYPE_MANAGE_ALL_FILES_ACCESS -> showSettingDialog(permissions, rationale) {
+                try {
+                    if (Permissions.isManageExternalStorage()) {
+                        val settingIntent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
+                        settingActivityResult.launch(settingIntent)
+                    } else {
+                        throw NoStackTraceException("no MANAGE_ALL_FILES_ACCESS_PERMISSION")
+                    }
+                } catch (e: Exception) {
+                    toastOnUi(e.localizedMessage)
+                    RequestPlugins.sRequestCallback?.onError(e)
+                    finish()
                 }
                 }
-            } catch (e: Exception) {
-                toastOnUi(e.localizedMessage)
-                RequestPlugins.sRequestCallback?.onError(e)
-                finish()
             }
             }
-            Request.TYPE_REQUEST_NOTIFICATIONS -> kotlin.runCatching {
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                    //这种方案适用于 API 26, 即8.0(含8.0)以上可以用
-                    val intent = Intent()
-                    intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
-                    intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
-                    intent.putExtra(Settings.EXTRA_CHANNEL_ID, applicationInfo.uid)
-                    settingActivityResult.launch(intent)
-                } else {
-                    openSettingsActivity()
+            Request.TYPE_REQUEST_NOTIFICATIONS -> showSettingDialog(permissions, rationale) {
+                kotlin.runCatching {
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                        //这种方案适用于 API 26, 即8.0(含8.0)以上可以用
+                        val intent = Intent()
+                        intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
+                        intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
+                        intent.putExtra(Settings.EXTRA_CHANNEL_ID, applicationInfo.uid)
+                        settingActivityResult.launch(intent)
+                    } else {
+                        openSettingsActivity()
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -106,8 +112,34 @@ class PermissionActivity : AppCompatActivity() {
         } else super.onKeyDown(keyCode, event)
         } else super.onKeyDown(keyCode, event)
     }
     }
 
 
+    private fun showSettingDialog(
+        permissions: Array<String>,
+        rationale: CharSequence?,
+        onOk: () -> Unit
+    ) {
+        rationaleDialog?.dismiss()
+        if (rationale.isNullOrEmpty()) {
+
+            return
+        }
+        rationaleDialog = AlertDialog.Builder(this)
+            .setTitle(R.string.dialog_title)
+            .setMessage(rationale)
+            .setPositiveButton(R.string.dialog_setting) { _, _ ->
+                onOk.invoke()
+            }
+            .setNegativeButton(R.string.dialog_cancel) { _, _ ->
+                RequestPlugins.sRequestCallback?.onRequestPermissionsResult(
+                    permissions,
+                    IntArray(0)
+                )
+            }
+            .show()
+    }
+
     companion object {
     companion object {
 
 
+        const val KEY_RATIONALE = "KEY_RATIONALE"
         const val KEY_INPUT_REQUEST_TYPE = "KEY_INPUT_REQUEST_TYPE"
         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_CODE = "KEY_INPUT_PERMISSIONS_CODE"
         const val KEY_INPUT_PERMISSIONS = "KEY_INPUT_PERMISSIONS"
         const val KEY_INPUT_PERMISSIONS = "KEY_INPUT_PERMISSIONS"

+ 1 - 11
app/src/main/java/io/legado/app/lib/permission/PermissionsCompat.kt

@@ -1,8 +1,6 @@
 package io.legado.app.lib.permission
 package io.legado.app.lib.permission
 
 
 import androidx.annotation.StringRes
 import androidx.annotation.StringRes
-import androidx.appcompat.app.AppCompatActivity
-import androidx.fragment.app.Fragment
 
 
 @Suppress("unused")
 @Suppress("unused")
 class PermissionsCompat private constructor() {
 class PermissionsCompat private constructor() {
@@ -14,15 +12,7 @@ class PermissionsCompat private constructor() {
     }
     }
 
 
     class Builder {
     class Builder {
-        private val request: Request
-
-        constructor(activity: AppCompatActivity) {
-            request = Request(activity)
-        }
-
-        constructor(fragment: Fragment) {
-            request = Request(fragment)
-        }
+        private val request: Request = Request()
 
 
         fun addPermissions(vararg permissions: String): Builder {
         fun addPermissions(vararg permissions: String): Builder {
             request.addPermissions(*permissions)
             request.addPermissions(*permissions)

+ 55 - 113
app/src/main/java/io/legado/app/lib/permission/Request.kt

@@ -4,48 +4,29 @@ import android.content.pm.PackageManager
 import android.os.Build
 import android.os.Build
 import android.os.Environment
 import android.os.Environment
 import androidx.annotation.StringRes
 import androidx.annotation.StringRes
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.app.AppCompatActivity
 import androidx.core.app.NotificationManagerCompat
 import androidx.core.app.NotificationManagerCompat
 import androidx.core.content.ContextCompat
 import androidx.core.content.ContextCompat
-import androidx.fragment.app.Fragment
-import io.legado.app.R
 import io.legado.app.utils.startActivity
 import io.legado.app.utils.startActivity
 import splitties.init.appCtx
 import splitties.init.appCtx
 
 
 @Suppress("MemberVisibilityCanBePrivate")
 @Suppress("MemberVisibilityCanBePrivate")
 internal class Request : OnRequestPermissionsResultCallback {
 internal class Request : OnRequestPermissionsResultCallback {
 
 
-    internal val requestTime: Long
+    internal val requestTime: Long = System.currentTimeMillis()
     private var requestCode: Int = TYPE_REQUEST_PERMISSION
     private var requestCode: Int = TYPE_REQUEST_PERMISSION
-    private var source: RequestSource? = null
-    private var permissions: ArrayList<String>? = null
+    private var permissions: ArrayList<String> = ArrayList()
     private var grantedCallback: OnPermissionsGrantedCallback? = null
     private var grantedCallback: OnPermissionsGrantedCallback? = null
     private var deniedCallback: OnPermissionsDeniedCallback? = null
     private var deniedCallback: OnPermissionsDeniedCallback? = null
     private var errorCallback: OnErrorCallback? = null
     private var errorCallback: OnErrorCallback? = null
     private var rationale: CharSequence? = null
     private var rationale: CharSequence? = null
 
 
-    private var rationaleDialog: AlertDialog? = null
-
     private val deniedPermissions: Array<String>?
     private val deniedPermissions: Array<String>?
         get() {
         get() {
-            return getDeniedPermissions(this.permissions?.toTypedArray())
+            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) {
     fun addPermissions(vararg permissions: String) {
-        this.permissions?.addAll(listOf(*permissions))
+        this.permissions.addAll(listOf(*permissions))
     }
     }
 
 
     fun setOnGrantedCallback(callback: OnPermissionsGrantedCallback) {
     fun setOnGrantedCallback(callback: OnPermissionsGrantedCallback) {
@@ -61,7 +42,7 @@ internal class Request : OnRequestPermissionsResultCallback {
     }
     }
 
 
     fun setRationale(@StringRes resId: Int) {
     fun setRationale(@StringRes resId: Int) {
-        rationale = source?.context?.getString(resId)
+        rationale = appCtx.getString(resId)
     }
     }
 
 
     fun setRationale(rationale: CharSequence) {
     fun setRationale(rationale: CharSequence) {
@@ -82,22 +63,16 @@ internal class Request : OnRequestPermissionsResultCallback {
             return
             return
         }
         }
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
-            showSettingDialog(deniedPermissions, rationale) {
-                toSetting()
-            }
+            toSetting()
         } else {
         } else {
             if (deniedPermissions.contains(Permissions.MANAGE_EXTERNAL_STORAGE)) {
             if (deniedPermissions.contains(Permissions.MANAGE_EXTERNAL_STORAGE)) {
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
-                    showSettingDialog(deniedPermissions, rationale) {
-                        toManageFileSetting()
-                    }
+                    toManageFileSetting()
                 }
                 }
             } else if (deniedPermissions.contains(Permissions.POST_NOTIFICATIONS)) {
             } else if (deniedPermissions.contains(Permissions.POST_NOTIFICATIONS)) {
-                showSettingDialog(deniedPermissions, rationale) {
-                    toNotificationSetting()
-                }
+                toNotificationSetting()
             } else if (deniedPermissions.size > 1) {
             } else if (deniedPermissions.size > 1) {
-                source?.context?.startActivity<PermissionActivity> {
+                appCtx.startActivity<PermissionActivity> {
                     putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION)
                     putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION)
                     putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
                     putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
                     putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
                     putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
@@ -111,66 +86,59 @@ internal class Request : OnRequestPermissionsResultCallback {
         deniedCallback = null
         deniedCallback = null
     }
     }
 
 
-    fun getDeniedPermissions(permissions: Array<String>?): Array<String>? {
-        val context = source?.context ?: return permissions
-        if (permissions != null) {
-            val deniedPermissionList = ArrayList<String>()
-            for (permission in permissions) {
-                when (permission) {
-                    Permissions.POST_NOTIFICATIONS -> {
-                        if (!NotificationManagerCompat.from(appCtx).areNotificationsEnabled()) {
-                            deniedPermissionList.add(permission)
-                        }
-                    }
-                    Permissions.MANAGE_EXTERNAL_STORAGE -> {
-                        if (Permissions.isManageExternalStorage()) {
-                            if (!Environment.isExternalStorageManager()) {
-                                deniedPermissionList.add(permission)
-                            }
-                        }
+    fun getDeniedPermissions(permissions: Array<String>): Array<String>? {
+        val deniedPermissionList = ArrayList<String>()
+        for (permission in permissions) {
+            when (permission) {
+                Permissions.POST_NOTIFICATIONS -> {
+                    if (!NotificationManagerCompat.from(appCtx).areNotificationsEnabled()) {
+                        deniedPermissionList.add(permission)
                     }
                     }
-                    else -> {
-                        if (
-                            ContextCompat.checkSelfPermission(context, permission)
-                            != PackageManager.PERMISSION_GRANTED
-                        ) {
+                }
+                Permissions.MANAGE_EXTERNAL_STORAGE -> {
+                    if (Permissions.isManageExternalStorage()) {
+                        if (!Environment.isExternalStorageManager()) {
                             deniedPermissionList.add(permission)
                             deniedPermissionList.add(permission)
                         }
                         }
                     }
                     }
                 }
                 }
-            }
-            val size = deniedPermissionList.size
-            if (size > 0) {
-                return deniedPermissionList.toTypedArray()
+                else -> {
+                    if (
+                        ContextCompat.checkSelfPermission(appCtx, permission)
+                        != PackageManager.PERMISSION_GRANTED
+                    ) {
+                        deniedPermissionList.add(permission)
+                    }
+                }
             }
             }
         }
         }
+        val size = deniedPermissionList.size
+        if (size > 0) {
+            return deniedPermissionList.toTypedArray()
+        }
         return null
         return null
     }
     }
 
 
-    private fun showSettingDialog(
-        permissions: Array<String>,
-        rationale: CharSequence,
-        onOk: () -> Unit
-    ) {
-        rationaleDialog?.dismiss()
-        source?.context?.let {
-            runCatching {
-                rationaleDialog = AlertDialog.Builder(it)
-                    .setTitle(R.string.dialog_title)
-                    .setMessage(rationale)
-                    .setPositiveButton(R.string.dialog_setting) { _, _ ->
-                        onOk.invoke()
-                    }
-                    .setNegativeButton(R.string.dialog_cancel) { _, _ ->
-                        onPermissionsDenied(permissions)
-                    }
-                    .show()
-            }
+    private fun onPermissionsGranted() {
+        try {
+            grantedCallback?.onPermissionsGranted()
+        } catch (ignore: Exception) {
+        }
+
+        RequestPlugins.sResultCallback?.onPermissionsGranted()
+    }
+
+    private fun onPermissionsDenied(deniedPermissions: Array<String>) {
+        try {
+            deniedCallback?.onPermissionsDenied(deniedPermissions)
+        } catch (ignore: Exception) {
         }
         }
+
+        RequestPlugins.sResultCallback?.onPermissionsDenied(deniedPermissions)
     }
     }
 
 
     private fun toSetting() {
     private fun toSetting() {
-        source?.context?.startActivity<PermissionActivity> {
+        appCtx.startActivity<PermissionActivity> {
             putExtra(
             putExtra(
                 PermissionActivity.KEY_INPUT_REQUEST_TYPE,
                 PermissionActivity.KEY_INPUT_REQUEST_TYPE,
                 TYPE_REQUEST_SETTING
                 TYPE_REQUEST_SETTING
@@ -179,56 +147,30 @@ internal class Request : OnRequestPermissionsResultCallback {
     }
     }
 
 
     private fun toManageFileSetting() {
     private fun toManageFileSetting() {
-        source?.context?.startActivity<PermissionActivity> {
-            putExtra(
-                PermissionActivity.KEY_INPUT_REQUEST_TYPE,
-                TYPE_MANAGE_ALL_FILES_ACCESS_PERMISSION
-            )
+        appCtx.startActivity<PermissionActivity> {
+            putExtra(PermissionActivity.KEY_RATIONALE, rationale)
+            putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_MANAGE_ALL_FILES_ACCESS)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
         }
         }
     }
     }
 
 
     private fun toNotificationSetting() {
     private fun toNotificationSetting() {
-        source?.context?.startActivity<PermissionActivity> {
+        appCtx.startActivity<PermissionActivity> {
+            putExtra(PermissionActivity.KEY_RATIONALE, rationale)
             putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_NOTIFICATIONS)
             putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_NOTIFICATIONS)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
             putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
         }
         }
     }
     }
 
 
-    private fun onPermissionsGranted() {
-        try {
-            grantedCallback?.onPermissionsGranted()
-        } catch (ignore: Exception) {
-        }
-
-        RequestPlugins.sResultCallback?.onPermissionsGranted()
-    }
-
-    private fun onPermissionsDenied(deniedPermissions: Array<String>) {
-        try {
-            deniedCallback?.onPermissionsDenied(deniedPermissions)
-        } catch (ignore: Exception) {
-        }
-
-        RequestPlugins.sResultCallback?.onPermissionsDenied(deniedPermissions)
-    }
-
     override fun onRequestPermissionsResult(
     override fun onRequestPermissionsResult(
         permissions: Array<String>,
         permissions: Array<String>,
         grantResults: IntArray
         grantResults: IntArray
     ) {
     ) {
         val deniedPermissions = getDeniedPermissions(permissions)
         val deniedPermissions = getDeniedPermissions(permissions)
         if (deniedPermissions != null) {
         if (deniedPermissions != null) {
-            val rationale = this.rationale
-            if (rationale != null) {
-                showSettingDialog(deniedPermissions, rationale) {
-
-                }
-            } else {
-                onPermissionsDenied(deniedPermissions)
-            }
+            onPermissionsDenied(deniedPermissions)
         } else {
         } else {
             onPermissionsGranted()
             onPermissionsGranted()
         }
         }
@@ -251,7 +193,7 @@ internal class Request : OnRequestPermissionsResultCallback {
     companion object {
     companion object {
         const val TYPE_REQUEST_PERMISSION = 1
         const val TYPE_REQUEST_PERMISSION = 1
         const val TYPE_REQUEST_SETTING = 2
         const val TYPE_REQUEST_SETTING = 2
-        const val TYPE_MANAGE_ALL_FILES_ACCESS_PERMISSION = 3
+        const val TYPE_MANAGE_ALL_FILES_ACCESS = 3
         const val TYPE_REQUEST_NOTIFICATIONS = 4
         const val TYPE_REQUEST_NOTIFICATIONS = 4
     }
     }
 }
 }

+ 0 - 12
app/src/main/java/io/legado/app/lib/permission/RequestSource.kt

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

+ 1 - 1
app/src/main/java/io/legado/app/service/AudioPlayService.kt

@@ -495,7 +495,7 @@ class AudioPlayService : BaseService(),
     /**
     /**
      * 更新通知
      * 更新通知
      */
      */
-    private fun upNotification() {
+    override fun upNotification() {
         execute {
         execute {
             var nTitle: String = when {
             var nTitle: String = when {
                 pause -> getString(R.string.audio_pause)
                 pause -> getString(R.string.audio_pause)

+ 1 - 1
app/src/main/java/io/legado/app/service/BaseReadAloudService.kt

@@ -355,7 +355,7 @@ abstract class BaseReadAloudService : BaseService(),
     /**
     /**
      * 更新通知
      * 更新通知
      */
      */
-    private fun upNotification() {
+    override fun upNotification() {
         execute {
         execute {
             var nTitle: String = when {
             var nTitle: String = when {
                 pause -> getString(R.string.read_aloud_pause)
                 pause -> getString(R.string.read_aloud_pause)

+ 1 - 1
app/src/main/java/io/legado/app/service/CheckSourceService.kt

@@ -260,7 +260,7 @@ class CheckSourceService : BaseService() {
     /**
     /**
      * 更新通知
      * 更新通知
      */
      */
-    private fun upNotification() {
+    override fun upNotification() {
         notificationBuilder.setContentText(notificationMsg)
         notificationBuilder.setContentText(notificationMsg)
         notificationBuilder.setProgress(allIds.size, checkedIds.size, false)
         notificationBuilder.setProgress(allIds.size, checkedIds.size, false)
         postEvent(EventBus.CHECK_SOURCE, notificationMsg)
         postEvent(EventBus.CHECK_SOURCE, notificationMsg)

+ 1 - 1
app/src/main/java/io/legado/app/service/WebService.kt

@@ -144,7 +144,7 @@ class WebService : BaseService() {
     /**
     /**
      * 更新通知
      * 更新通知
      */
      */
-    private fun upNotification() {
+    override fun upNotification() {
         val builder = NotificationCompat.Builder(this, AppConst.channelIdWeb)
         val builder = NotificationCompat.Builder(this, AppConst.channelIdWeb)
             .setSmallIcon(R.drawable.ic_web_service_noti)
             .setSmallIcon(R.drawable.ic_web_service_noti)
             .setOngoing(true)
             .setOngoing(true)

+ 1 - 1
app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt

@@ -109,7 +109,7 @@ class FileAssociationActivity :
             if (data.isContentScheme()) {
             if (data.isContentScheme()) {
                 viewModel.dispatchIndent(data)
                 viewModel.dispatchIndent(data)
             } else if (!AppConst.isPlayChannel || Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
             } else if (!AppConst.isPlayChannel || Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
-                PermissionsCompat.Builder(this)
+                PermissionsCompat.Builder()
                     .addPermissions(*Permissions.Group.STORAGE)
                     .addPermissions(*Permissions.Group.STORAGE)
                     .rationale(R.string.tip_perm_request_storage)
                     .rationale(R.string.tip_perm_request_storage)
                     .onGranted {
                     .onGranted {

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt

@@ -189,7 +189,7 @@ class ImportBookActivity : BaseImportBookActivity<ActivityImportBookBinding, Imp
 
 
     private fun initRootPath(path: String) {
     private fun initRootPath(path: String) {
         binding.tvEmptyMsg.visible()
         binding.tvEmptyMsg.visible()
-        PermissionsCompat.Builder(this)
+        PermissionsCompat.Builder()
             .addPermissions(*Permissions.Group.STORAGE)
             .addPermissions(*Permissions.Group.STORAGE)
             .rationale(R.string.tip_perm_request_storage)
             .rationale(R.string.tip_perm_request_storage)
             .onGranted {
             .onGranted {

+ 2 - 2
app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt

@@ -295,7 +295,7 @@ class BackupConfigFragment : PreferenceFragment(),
     }
     }
 
 
     private fun backupUsePermission(path: String) {
     private fun backupUsePermission(path: String) {
-        PermissionsCompat.Builder(this)
+        PermissionsCompat.Builder()
             .addPermissions(*Permissions.Group.STORAGE)
             .addPermissions(*Permissions.Group.STORAGE)
             .rationale(R.string.tip_perm_request_storage)
             .rationale(R.string.tip_perm_request_storage)
             .onGranted {
             .onGranted {
@@ -366,7 +366,7 @@ class BackupConfigFragment : PreferenceFragment(),
     }
     }
 
 
     private fun restoreUsePermission(path: String) {
     private fun restoreUsePermission(path: String) {
-        PermissionsCompat.Builder(this)
+        PermissionsCompat.Builder()
             .addPermissions(*Permissions.Group.STORAGE)
             .addPermissions(*Permissions.Group.STORAGE)
             .rationale(R.string.tip_perm_request_storage)
             .rationale(R.string.tip_perm_request_storage)
             .onGranted {
             .onGranted {

+ 1 - 1
app/src/main/java/io/legado/app/ui/document/HandleFileActivity.kt

@@ -182,7 +182,7 @@ class HandleFileActivity :
     }
     }
 
 
     private fun checkPermissions(success: (() -> Unit)? = null) {
     private fun checkPermissions(success: (() -> Unit)? = null) {
-        PermissionsCompat.Builder(this)
+        PermissionsCompat.Builder()
             .addPermissions(*Permissions.Group.STORAGE)
             .addPermissions(*Permissions.Group.STORAGE)
             .rationale(R.string.tip_perm_request_storage)
             .rationale(R.string.tip_perm_request_storage)
             .onGranted {
             .onGranted {

+ 1 - 1
app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt

@@ -127,7 +127,7 @@ class FontSelectDialog : BaseDialogFragment(R.layout.dialog_font_select),
     }
     }
 
 
     private fun loadFontFilesByPermission(path: String) {
     private fun loadFontFilesByPermission(path: String) {
-        PermissionsCompat.Builder(this@FontSelectDialog)
+        PermissionsCompat.Builder()
             .addPermissions(*Permissions.Group.STORAGE)
             .addPermissions(*Permissions.Group.STORAGE)
             .rationale(R.string.tip_perm_request_storage)
             .rationale(R.string.tip_perm_request_storage)
             .onGranted {
             .onGranted {

+ 0 - 23
app/src/main/java/io/legado/app/ui/main/MainActivity.kt

@@ -28,8 +28,6 @@ import io.legado.app.help.config.LocalConfig
 import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.help.storage.Backup
 import io.legado.app.help.storage.Backup
 import io.legado.app.lib.dialogs.alert
 import io.legado.app.lib.dialogs.alert
-import io.legado.app.lib.permission.Permissions
-import io.legado.app.lib.permission.PermissionsCompat
 import io.legado.app.lib.theme.elevation
 import io.legado.app.lib.theme.elevation
 import io.legado.app.lib.theme.primaryColor
 import io.legado.app.lib.theme.primaryColor
 import io.legado.app.service.BaseReadAloudService
 import io.legado.app.service.BaseReadAloudService
@@ -94,8 +92,6 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
             if (!privacyPolicy()) return@launch
             if (!privacyPolicy()) return@launch
             //版本更新
             //版本更新
             upVersion()
             upVersion()
-            //检测通知权限
-            checkNotificationPermission()
             //备份同步
             //备份同步
             backupSync()
             backupSync()
             //自动更新书籍
             //自动更新书籍
@@ -198,25 +194,6 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
         }
         }
     }
     }
 
 
-    /**
-     * 检测通知权限
-     */
-    private suspend fun checkNotificationPermission() = suspendCoroutine { block ->
-        PermissionsCompat.Builder(this)
-            .addPermissions(Permissions.POST_NOTIFICATIONS)
-            .rationale(R.string.notification_permission_rationale)
-            .onDenied {
-                block.resume(null)
-            }
-            .onGranted {
-                block.resume(null)
-            }
-            .onError {
-                block.resume(null)
-            }
-            .request()
-    }
-
     /**
     /**
      * 备份同步
      * 备份同步
      */
      */

+ 54 - 1
app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt

@@ -6,6 +6,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.view.MenuItem
 import android.widget.EditText
 import android.widget.EditText
 import androidx.activity.viewModels
 import androidx.activity.viewModels
+import com.google.android.material.tabs.TabLayout
 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
 import io.legado.app.R
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.base.VMBaseActivity
@@ -14,6 +15,8 @@ import io.legado.app.databinding.ActivityRssSourceEditBinding
 import io.legado.app.help.config.LocalConfig
 import io.legado.app.help.config.LocalConfig
 import io.legado.app.lib.dialogs.SelectItem
 import io.legado.app.lib.dialogs.SelectItem
 import io.legado.app.lib.dialogs.alert
 import io.legado.app.lib.dialogs.alert
+import io.legado.app.lib.theme.accentColor
+import io.legado.app.lib.theme.backgroundColor
 import io.legado.app.lib.theme.primaryColor
 import io.legado.app.lib.theme.primaryColor
 import io.legado.app.ui.document.HandleFileContract
 import io.legado.app.ui.document.HandleFileContract
 import io.legado.app.ui.login.SourceLoginActivity
 import io.legado.app.ui.login.SourceLoginActivity
@@ -37,6 +40,8 @@ class RssSourceEditActivity :
     }
     }
     private val adapter by lazy { RssSourceEditAdapter() }
     private val adapter by lazy { RssSourceEditAdapter() }
     private val sourceEntities: ArrayList<EditEntity> = ArrayList()
     private val sourceEntities: ArrayList<EditEntity> = ArrayList()
+    private val listEntities: ArrayList<EditEntity> = ArrayList()
+    private val webViewEntities: ArrayList<EditEntity> = ArrayList()
     private val selectDoc = registerForActivityResult(HandleFileContract()) {
     private val selectDoc = registerForActivityResult(HandleFileContract()) {
         it.uri?.let { uri ->
         it.uri?.let { uri ->
             if (uri.isContentScheme()) {
             if (uri.isContentScheme()) {
@@ -148,8 +153,41 @@ class RssSourceEditActivity :
     }
     }
 
 
     private fun initView() {
     private fun initView() {
+        binding.tabLayout.addTab(binding.tabLayout.newTab().apply {
+            setText(R.string.source_tab_base)
+        })
+        binding.tabLayout.addTab(binding.tabLayout.newTab().apply {
+            setText(R.string.source_tab_list)
+        })
+        binding.tabLayout.addTab(binding.tabLayout.newTab().apply {
+            text = "WEB_VIEW"
+        })
         binding.recyclerView.setEdgeEffectColor(primaryColor)
         binding.recyclerView.setEdgeEffectColor(primaryColor)
         binding.recyclerView.adapter = adapter
         binding.recyclerView.adapter = adapter
+        binding.tabLayout.setBackgroundColor(backgroundColor)
+        binding.tabLayout.setSelectedTabIndicatorColor(accentColor)
+        binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+            override fun onTabReselected(tab: TabLayout.Tab?) {
+
+            }
+
+            override fun onTabUnselected(tab: TabLayout.Tab?) {
+
+            }
+
+            override fun onTabSelected(tab: TabLayout.Tab?) {
+                setEditEntities(tab?.position)
+            }
+        })
+    }
+
+    private fun setEditEntities(tabPosition: Int?) {
+        when (tabPosition) {
+            1 -> adapter.editEntities = listEntities
+            2 -> adapter.editEntities = webViewEntities
+            else -> adapter.editEntities = sourceEntities
+        }
+        binding.recyclerView.scrollToPosition(0)
     }
     }
 
 
     private fun upSourceView(rs: RssSource? = viewModel.rssSource) {
     private fun upSourceView(rs: RssSource? = viewModel.rssSource) {
@@ -175,6 +213,9 @@ class RssSourceEditActivity :
             add(EditEntity("variableComment", rs?.variableComment, R.string.variable_comment))
             add(EditEntity("variableComment", rs?.variableComment, R.string.variable_comment))
             add(EditEntity("concurrentRate", rs?.concurrentRate, R.string.concurrent_rate))
             add(EditEntity("concurrentRate", rs?.concurrentRate, R.string.concurrent_rate))
             add(EditEntity("sortUrl", rs?.sortUrl, R.string.sort_url))
             add(EditEntity("sortUrl", rs?.sortUrl, R.string.sort_url))
+        }
+        listEntities.clear()
+        listEntities.apply {
             add(EditEntity("ruleArticles", rs?.ruleArticles, R.string.r_articles))
             add(EditEntity("ruleArticles", rs?.ruleArticles, R.string.r_articles))
             add(EditEntity("ruleNextPage", rs?.ruleNextPage, R.string.r_next))
             add(EditEntity("ruleNextPage", rs?.ruleNextPage, R.string.r_next))
             add(EditEntity("ruleTitle", rs?.ruleTitle, R.string.r_title))
             add(EditEntity("ruleTitle", rs?.ruleTitle, R.string.r_title))
@@ -182,13 +223,17 @@ class RssSourceEditActivity :
             add(EditEntity("ruleDescription", rs?.ruleDescription, R.string.r_description))
             add(EditEntity("ruleDescription", rs?.ruleDescription, R.string.r_description))
             add(EditEntity("ruleImage", rs?.ruleImage, R.string.r_image))
             add(EditEntity("ruleImage", rs?.ruleImage, R.string.r_image))
             add(EditEntity("ruleLink", rs?.ruleLink, R.string.r_link))
             add(EditEntity("ruleLink", rs?.ruleLink, R.string.r_link))
+        }
+        webViewEntities.clear()
+        webViewEntities.apply {
             add(EditEntity("ruleContent", rs?.ruleContent, R.string.r_content))
             add(EditEntity("ruleContent", rs?.ruleContent, R.string.r_content))
             add(EditEntity("style", rs?.style, R.string.r_style))
             add(EditEntity("style", rs?.style, R.string.r_style))
             add(EditEntity("injectJs", rs?.injectJs, R.string.r_inject_js))
             add(EditEntity("injectJs", rs?.injectJs, R.string.r_inject_js))
             add(EditEntity("contentWhitelist", rs?.contentWhitelist, R.string.c_whitelist))
             add(EditEntity("contentWhitelist", rs?.contentWhitelist, R.string.c_whitelist))
             add(EditEntity("contentBlacklist", rs?.contentBlacklist, R.string.c_blacklist))
             add(EditEntity("contentBlacklist", rs?.contentBlacklist, R.string.c_blacklist))
         }
         }
-        adapter.editEntities = sourceEntities
+        binding.tabLayout.selectTab(binding.tabLayout.getTabAt(0))
+        setEditEntities(0)
     }
     }
 
 
     private fun getRssSource(): RssSource {
     private fun getRssSource(): RssSource {
@@ -213,6 +258,10 @@ class RssSourceEditActivity :
                 "variableComment" -> source.variableComment = it.value
                 "variableComment" -> source.variableComment = it.value
                 "concurrentRate" -> source.concurrentRate = it.value
                 "concurrentRate" -> source.concurrentRate = it.value
                 "sortUrl" -> source.sortUrl = it.value
                 "sortUrl" -> source.sortUrl = it.value
+            }
+        }
+        listEntities.forEach {
+            when (it.key) {
                 "ruleArticles" -> source.ruleArticles = it.value
                 "ruleArticles" -> source.ruleArticles = it.value
                 "ruleNextPage" -> source.ruleNextPage =
                 "ruleNextPage" -> source.ruleNextPage =
                     viewModel.ruleComplete(it.value, source.ruleArticles, 2)
                     viewModel.ruleComplete(it.value, source.ruleArticles, 2)
@@ -226,6 +275,10 @@ class RssSourceEditActivity :
                     viewModel.ruleComplete(it.value, source.ruleArticles, 3)
                     viewModel.ruleComplete(it.value, source.ruleArticles, 3)
                 "ruleLink" -> source.ruleLink =
                 "ruleLink" -> source.ruleLink =
                     viewModel.ruleComplete(it.value, source.ruleArticles)
                     viewModel.ruleComplete(it.value, source.ruleArticles)
+            }
+        }
+        webViewEntities.forEach {
+            when (it.key) {
                 "ruleContent" -> source.ruleContent =
                 "ruleContent" -> source.ruleContent =
                     viewModel.ruleComplete(it.value, source.ruleArticles)
                     viewModel.ruleComplete(it.value, source.ruleArticles)
                 "style" -> source.style = it.value
                 "style" -> source.style = it.value

+ 2 - 2
app/src/main/java/io/legado/app/utils/UriExtensions.kt

@@ -41,7 +41,7 @@ fun AppCompatActivity.readUri(
                 success.invoke(fileDoc, inputStream)
                 success.invoke(fileDoc, inputStream)
             }
             }
         } else {
         } else {
-            PermissionsCompat.Builder(this)
+            PermissionsCompat.Builder()
                 .addPermissions(
                 .addPermissions(
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.WRITE_EXTERNAL_STORAGE
                     Permissions.WRITE_EXTERNAL_STORAGE
@@ -81,7 +81,7 @@ fun Fragment.readUri(uri: Uri?, success: (fileDoc: FileDoc, inputStream: InputSt
                 success.invoke(fileDoc, inputStream)
                 success.invoke(fileDoc, inputStream)
             }
             }
         } else {
         } else {
-            PermissionsCompat.Builder(this)
+            PermissionsCompat.Builder()
                 .addPermissions(
                 .addPermissions(
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.WRITE_EXTERNAL_STORAGE
                     Permissions.WRITE_EXTERNAL_STORAGE

+ 8 - 0
app/src/main/res/layout/activity_rss_source_edit.xml

@@ -87,6 +87,14 @@
 
 
     </LinearLayout>
     </LinearLayout>
 
 
+    <com.google.android.material.tabs.TabLayout
+        android:id="@+id/tab_layout"
+        android:layout_width="match_parent"
+        android:layout_height="36dp"
+        android:background="@color/background"
+        android:elevation="3dp"
+        tools:ignore="SpeakableTextPresentCheck" />
+
     <androidx.recyclerview.widget.RecyclerView
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/recycler_view"
         android:id="@+id/recycler_view"
         android:layout_width="match_parent"
         android:layout_width="match_parent"

+ 1 - 0
app/src/main/res/values-es-rES/strings.xml

@@ -1071,4 +1071,5 @@
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
+    <string name="source_tab_list">列表</string>
 </resources>
 </resources>

+ 1 - 0
app/src/main/res/values-ja-rJP/strings.xml

@@ -1074,4 +1074,5 @@
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
+    <string name="source_tab_list">列表</string>
 </resources>
 </resources>

+ 1 - 0
app/src/main/res/values-pt-rBR/strings.xml

@@ -1074,4 +1074,5 @@
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
+    <string name="source_tab_list">列表</string>
 </resources>
 </resources>

+ 1 - 0
app/src/main/res/values-zh-rHK/strings.xml

@@ -1071,4 +1071,5 @@
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
+    <string name="source_tab_list">列表</string>
 </resources>
 </resources>

+ 1 - 0
app/src/main/res/values-zh-rTW/strings.xml

@@ -1073,4 +1073,5 @@
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
+    <string name="source_tab_list">列表</string>
 </resources>
 </resources>

+ 1 - 0
app/src/main/res/values-zh/strings.xml

@@ -1073,4 +1073,5 @@
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="jump_to_another_app">跳转其它应用</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
+    <string name="source_tab_list">列表</string>
 </resources>
 </resources>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -1074,4 +1074,5 @@
     <string name="jump_to_another_app">Jump to another app</string>
     <string name="jump_to_another_app">Jump to another app</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data">清除 WebView 数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
     <string name="clear_webview_data_summary">清除内置浏览器所有数据</string>
+    <string name="source_tab_list">List</string>
 </resources>
 </resources>