From fa92195933b5456019a82bdb8d6e3004fe02e21f Mon Sep 17 00:00:00 2001 From: gedoor Date: Mon, 29 Mar 2021 22:46:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=BC=83=E7=94=A8=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 6 + .../java/io/legado/app/base/BaseActivity.kt | 4 +- .../legado/app/ui/book/cache/CacheActivity.kt | 54 ++-- .../app/ui/book/local/ImportBookActivity.kt | 55 ++-- .../ui/book/read/config/BgTextConfigDialog.kt | 67 ++-- .../source/edit/BookSourceEditActivity.kt | 52 ++- .../book/source/manage/BookSourceActivity.kt | 92 +++--- .../app/ui/config/BackupConfigFragment.kt | 173 +++++++++- .../legado/app/ui/config/BackupRestoreUi.kt | 195 ------------ .../io/legado/app/ui/filepicker/FilePicker.kt | 297 ++---------------- .../app/ui/filepicker/FilePickerActivity.kt | 145 +++++++++ .../app/ui/filepicker/FilePickerDialog.kt | 46 +-- .../ui/main/bookshelf/BookshelfFragment.kt | 33 +- .../io/legado/app/ui/main/my/MyFragment.kt | 10 +- .../io/legado/app/ui/qrcode/QrCodeResult.kt | 23 ++ .../app/ui/replace/ReplaceRuleActivity.kt | 100 +++--- .../legado/app/ui/rss/read/ReadRssActivity.kt | 30 +- .../ui/rss/source/manage/RssSourceActivity.kt | 95 +++--- .../app/ui/widget/font/FontSelectDialog.kt | 76 ++--- .../io/legado/app/utils/FragmentExtensions.kt | 11 - 20 files changed, 651 insertions(+), 913 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt create mode 100644 app/src/main/java/io/legado/app/ui/filepicker/FilePickerActivity.kt create mode 100644 app/src/main/java/io/legado/app/ui/qrcode/QrCodeResult.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 86b75894f..ac44b67eb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -294,6 +294,12 @@ android:name=".ui.about.ReadRecordActivity" android:configChanges="orientation|screenSize" android:hardwareAccelerated="true" /> + + ( } if (AppConfig.isGooglePlay) { ThemeConfig.getBgImage(this)?.let { - window.decorView.background = it + kotlin.runCatching { + window.decorView.background = it + } } } } diff --git a/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt b/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt index 015c30399..2e193d785 100644 --- a/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt @@ -1,6 +1,5 @@ package io.legado.app.ui.book.cache -import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.Menu @@ -26,7 +25,7 @@ import io.legado.app.help.BookHelp import io.legado.app.lib.dialogs.alert import io.legado.app.service.help.CacheBook import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.filepicker.FilePickerParam import io.legado.app.ui.widget.dialog.TextListDialog import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers @@ -36,11 +35,25 @@ import kotlinx.coroutines.withContext import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CopyOnWriteArraySet - class CacheActivity : VMBaseActivity(), - FilePickerDialog.CallBack, CacheAdapter.CallBack { - private val exportRequestCode = 32 + + private val exportDir = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + ACache.get(this@CacheActivity).put(exportBookPathKey, uri.toString()) + startExport(uri.toString()) + } else { + uri.path?.let { path -> + ACache.get(this@CacheActivity).put(exportBookPathKey, path) + startExport(path) + } + } + } private val exportBookPathKey = "exportBookPath" lateinit var adapter: CacheAdapter private var groupLiveData: LiveData>? = null @@ -215,9 +228,11 @@ class CacheActivity : VMBaseActivity() if (!path.isNullOrEmpty()) { default.add(path) } - FilePicker.selectFolder(this, exportRequestCode, otherActions = default) { - startExport(it) - } + exportDir.launch( + FilePickerParam( + otherActions = default.toTypedArray() + ) + ) } private fun startExport(path: String) { @@ -244,27 +259,4 @@ class CacheActivity : VMBaseActivity() }.show() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - exportRequestCode -> if (resultCode == Activity.RESULT_OK) { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - contentResolver.takePersistableUriPermission( - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - ACache.get(this@CacheActivity).put(exportBookPathKey, uri.toString()) - startExport(uri.toString()) - } else { - uri.path?.let { path -> - ACache.get(this@CacheActivity).put(exportBookPathKey, path) - startExport(path) - } - } - } - } - - } - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt index ea5858eda..4959a2560 100644 --- a/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt @@ -1,6 +1,5 @@ package io.legado.app.ui.book.local -import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Build @@ -22,7 +21,6 @@ import io.legado.app.lib.permission.Permissions import io.legado.app.lib.permission.PermissionsCompat import io.legado.app.lib.theme.backgroundColor import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog import io.legado.app.ui.widget.SelectActionBar import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers.IO @@ -36,17 +34,31 @@ import java.util.* * 导入本地书籍界面 */ class ImportBookActivity : VMBaseActivity(), - FilePickerDialog.CallBack, PopupMenu.OnMenuItemClickListener, - SelectActionBar.CallBack, - ImportBookAdapter.CallBack { - private val requestCodeSelectFolder = 342 + ImportBookAdapter.CallBack, + SelectActionBar.CallBack { private var rootDoc: DocumentFile? = null private val subDocs = arrayListOf() private lateinit var adapter: ImportBookAdapter private var localUriLiveData: LiveData>? = null private var sdPath = FileUtils.getSdCardPath() private var path = sdPath + private val selectFolder = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + AppConfig.importBookPath = uri.toString() + initRootDoc() + } else { + uri.path?.let { path -> + AppConfig.importBookPath = path + initRootDoc() + } + } + } override val viewModel: ImportBookViewModel by viewModels() @@ -69,7 +81,7 @@ class ImportBookActivity : VMBaseActivity FilePicker.selectFolder(this, requestCodeSelectFolder) + R.id.menu_select_folder -> selectFolder.launch(null) R.id.menu_scan_folder -> scanFolder() } return super.onCompatOptionsItemSelected(item) @@ -129,14 +141,14 @@ class ImportBookActivity : VMBaseActivity { binding.tvEmptyMsg.visible() - FilePicker.selectFolder(this, requestCodeSelectFolder) + selectFolder.launch(null) } lastPath.isContentScheme() -> { val rootUri = Uri.parse(lastPath) rootDoc = DocumentFile.fromTreeUri(this, rootUri) if (rootDoc == null) { binding.tvEmptyMsg.visible() - FilePicker.selectFolder(this, requestCodeSelectFolder) + selectFolder.launch(null) } else { subDocs.clear() upPath() @@ -144,7 +156,7 @@ class ImportBookActivity : VMBaseActivity Build.VERSION_CODES.Q -> { binding.tvEmptyMsg.visible() - FilePicker.selectFolder(this, requestCodeSelectFolder) + selectFolder.launch(null) } else -> { binding.tvEmptyMsg.visible() @@ -274,29 +286,6 @@ class ImportBookActivity : VMBaseActivity if (resultCode == Activity.RESULT_OK) { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - contentResolver.takePersistableUriPermission( - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - AppConfig.importBookPath = uri.toString() - initRootDoc() - } else { - uri.path?.let { path -> - AppConfig.importBookPath = path - initRootDoc() - } - } - } - } - } - } - @Synchronized override fun nextDoc(uri: Uri) { if (uri.toString().isContentScheme()) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt index ce648bede..e3ae1463d 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt @@ -1,9 +1,7 @@ package io.legado.app.ui.book.read.config import android.annotation.SuppressLint -import android.app.Activity.RESULT_OK import android.content.DialogInterface -import android.content.Intent import android.graphics.Color import android.net.Uri import android.os.Bundle @@ -26,14 +24,14 @@ import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.lib.theme.getSecondaryTextColor import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.filepicker.FilePickerParam import io.legado.app.utils.* import io.legado.app.utils.viewbindingdelegate.viewBinding import rxhttp.wrapper.param.RxHttp import rxhttp.wrapper.param.toByteArray import java.io.File -class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { +class BgTextConfigDialog : BaseDialogFragment() { companion object { const val TEXT_COLOR = 121 @@ -41,15 +39,27 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { } private val binding by viewBinding(DialogReadBgTextBinding::bind) - private val requestCodeExport = 131 - private val requestCodeImport = 132 private val configFileName = "readConfig.zip" private lateinit var adapter: BgAdapter private var primaryTextColor = 0 private var secondaryTextColor = 0 + private val importFormNet = "网络导入" private val selectBgImage = registerForActivityResult(ActivityResultContracts.GetContent()) { setBgFromUri(it) } + private val selectExportDir = registerForActivityResult(FilePicker()) { + it?.let { + exportConfig(it) + } + } + private val selectImportDoc = registerForActivityResult(FilePicker()) { + it ?: return@registerForActivityResult + if (it.toString() == importFormNet) { + importNetConfigAlert() + } else { + importConfig(it) + } + } override fun onStart() { super.onStart() @@ -164,25 +174,20 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { .show(requireActivity()) } binding.ivImport.setOnClickListener { - val importFormNet = "网络导入" - val otherActions = arrayListOf(importFormNet) - FilePicker.selectFile( - this@BgTextConfigDialog, - requestCodeImport, - title = getString(R.string.import_str), - allowExtensions = arrayOf("zip"), - otherActions = otherActions - ) { action -> - when (action) { - importFormNet -> importNetConfigAlert() - } - } + selectImportDoc.launch( + FilePickerParam( + mode = FilePicker.FILE, + title = getString(R.string.import_str), + allowExtensions = arrayOf("zip"), + otherActions = arrayOf(importFormNet) + ) + ) } binding.ivExport.setOnClickListener { - FilePicker.selectFolder( - this@BgTextConfigDialog, - requestCodeExport, - title = getString(R.string.export_str) + selectExportDir.launch( + FilePickerParam( + title = getString(R.string.export_str) + ) ) } binding.ivDelete.setOnClickListener { @@ -368,22 +373,6 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - requestCodeImport -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - importConfig(uri) - } - } - requestCodeExport -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - exportConfig(uri) - } - } - } - } - private fun setBgFromUri(uri: Uri) { if (uri.toString().isContentScheme()) { val doc = DocumentFile.fromSingleUri(requireContext(), uri) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index 0e6db0c39..2a26cacd0 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -1,7 +1,6 @@ package io.legado.app.ui.book.source.edit import android.app.Activity -import android.content.Intent import android.graphics.Rect import android.os.Bundle import android.view.Gravity @@ -26,9 +25,9 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.backgroundColor import io.legado.app.ui.book.source.debug.BookSourceDebugActivity import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.filepicker.FilePickerParam import io.legado.app.ui.login.SourceLogin -import io.legado.app.ui.qrcode.QrCodeActivity +import io.legado.app.ui.qrcode.QrCodeResult import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.utils.* @@ -36,13 +35,10 @@ import kotlin.math.abs class BookSourceEditActivity : VMBaseActivity(false), - FilePickerDialog.CallBack, KeyboardToolPop.CallBack { override val viewModel: BookSourceEditViewModel by viewModels() - private val qrRequestCode = 101 - private val selectPathRequestCode = 102 private val adapter = BookSourceEditAdapter() private val sourceEntities: ArrayList = ArrayList() private val searchEntities: ArrayList = ArrayList() @@ -50,6 +46,20 @@ class BookSourceEditActivity : private val infoEntities: ArrayList = ArrayList() private val tocEntities: ArrayList = ArrayList() private val contentEntities: ArrayList = ArrayList() + private val qrCodeResult = registerForActivityResult(QrCodeResult()) { + it ?: return@registerForActivityResult + viewModel.importSource(it) { source -> + upRecyclerView(source) + } + } + private val selectDoc = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + sendText(uri.toString()) + } else { + sendText(uri.path.toString()) + } + } private var mSoftKeyboardTool: PopupWindow? = null private var mIsSoftKeyBoardShowing = false @@ -98,7 +108,7 @@ class BookSourceEditActivity : } R.id.menu_copy_source -> sendToClip(GSON.toJson(getSource())) R.id.menu_paste_source -> viewModel.pasteSource { upRecyclerView(it) } - R.id.menu_qr_code_camera -> startActivityForResult(qrRequestCode) + R.id.menu_qr_code_camera -> qrCodeResult.launch(null) R.id.menu_share_str -> share(GSON.toJson(getSource())) R.id.menu_share_qr -> shareWithQr( GSON.toJson(getSource()), @@ -397,7 +407,11 @@ class BookSourceEditActivity : 0 -> insertText(AppConst.urlOption) 1 -> showRuleHelp() 2 -> showRegexHelp() - 3 -> FilePicker.selectFile(this, selectPathRequestCode) + 3 -> selectDoc.launch( + FilePickerParam( + mode = FilePicker.FILE + ) + ) } } } @@ -425,28 +439,6 @@ class BookSourceEditActivity : mSoftKeyboardTool?.dismiss() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - qrRequestCode -> if (resultCode == RESULT_OK) { - data?.getStringExtra("result")?.let { - viewModel.importSource(it) { source -> - upRecyclerView(source) - } - } - } - selectPathRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - sendText(uri.toString()) - } else { - sendText(uri.path.toString()) - } - } - } - } - } - private inner class KeyboardOnGlobalChangeListener : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { val rect = Rect() diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index f9655fdb8..127780d52 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -1,7 +1,6 @@ package io.legado.app.ui.book.source.manage import android.annotation.SuppressLint -import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.Menu @@ -32,8 +31,8 @@ import io.legado.app.ui.association.ImportBookSourceActivity import io.legado.app.ui.book.source.debug.BookSourceDebugActivity import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog -import io.legado.app.ui.qrcode.QrCodeActivity +import io.legado.app.ui.filepicker.FilePickerParam +import io.legado.app.ui.qrcode.QrCodeResult import io.legado.app.ui.widget.SelectActionBar import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.ui.widget.recycler.DragSelectTouchHelper @@ -45,15 +44,11 @@ import java.io.File class BookSourceActivity : VMBaseActivity(), PopupMenu.OnMenuItemClickListener, BookSourceAdapter.CallBack, - FilePickerDialog.CallBack, SelectActionBar.CallBack, SearchView.OnQueryTextListener { override val viewModel: BookSourceViewModel by viewModels() private val importRecordKey = "bookSourceRecordKey" - private val qrRequestCode = 101 - private val importRequestCode = 132 - private val exportRequestCode = 65 private lateinit var adapter: BookSourceAdapter private lateinit var searchView: SearchView private var bookSourceLiveDate: LiveData>? = null @@ -62,6 +57,37 @@ class BookSourceActivity : VMBaseActivity { + putExtra("source", it) + } + } + private val importDoc = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + try { + uri.readText(this)?.let { + val dataKey = IntentDataHelp.putData(it) + startActivity { + putExtra("dataKey", dataKey) + } + } + } catch (e: Exception) { + toastOnUi("readTextError:${e.localizedMessage}") + } + } + private val exportDir = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + DocumentFile.fromTreeUri(this, uri)?.let { + viewModel.exportSelection(adapter.getSelection(), it) + } + } else { + uri.path?.let { + viewModel.exportSelection(adapter.getSelection(), File(it)) + } + } + } override fun getViewBinding(): ActivityBookSourceBinding { return ActivityBookSourceBinding.inflate(layoutInflater) @@ -95,14 +121,18 @@ class BookSourceActivity : VMBaseActivity startActivity() - R.id.menu_import_source_qr -> startActivityForResult(qrRequestCode) + R.id.menu_import_source_qr -> qrResult.launch(null) R.id.menu_share_source -> viewModel.shareSelection(adapter.getSelection()) { startActivity(Intent.createChooser(it, getString(R.string.share_selected_source))) } R.id.menu_group_manage -> GroupManageDialog().show(supportFragmentManager, "groupManage") - R.id.menu_import_source_local -> FilePicker - .selectFile(this, importRequestCode, allowExtensions = arrayOf("txt", "json")) + R.id.menu_import_source_local -> importDoc.launch( + FilePickerParam( + mode = FilePicker.FILE, + allowExtensions = arrayOf("txt", "json") + ) + ) R.id.menu_import_source_onLine -> showImportDialog() R.id.menu_sort_manual -> { item.isChecked = true @@ -292,7 +322,7 @@ class BookSourceActivity : VMBaseActivity viewModel.bottomSource(*adapter.getSelection().toTypedArray()) R.id.menu_add_group -> selectionAddToGroups() R.id.menu_remove_group -> selectionRemoveFromGroups() - R.id.menu_export_selection -> FilePicker.selectFolder(this, exportRequestCode) + R.id.menu_export_selection -> exportDir.launch(null) } return true } @@ -467,46 +497,6 @@ class BookSourceActivity : VMBaseActivity if (resultCode == RESULT_OK) { - data?.getStringExtra("result")?.let { - startActivity { - putExtra("source", it) - } - } - } - importRequestCode -> if (resultCode == Activity.RESULT_OK) { - data?.data?.let { uri -> - try { - uri.readText(this)?.let { - val dataKey = IntentDataHelp.putData(it) - startActivity { - putExtra("dataKey", dataKey) - } - } - } catch (e: Exception) { - toastOnUi("readTextError:${e.localizedMessage}") - } - } - } - exportRequestCode -> { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - DocumentFile.fromTreeUri(this, uri)?.let { - viewModel.exportSelection(adapter.getSelection(), it) - } - } else { - uri.path?.let { - viewModel.exportSelection(adapter.getSelection(), File(it)) - } - } - } - } - } - } - override fun finish() { if (searchView.query.isNullOrEmpty()) { super.finish() diff --git a/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt index bd1865828..7b5aacc31 100644 --- a/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt @@ -2,31 +2,105 @@ package io.legado.app.ui.config import android.content.Intent import android.content.SharedPreferences +import android.net.Uri import android.os.Bundle import android.text.InputType import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View +import androidx.documentfile.provider.DocumentFile import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.Preference import io.legado.app.R import io.legado.app.base.BasePreferenceFragment import io.legado.app.constant.PreferKey +import io.legado.app.help.AppConfig import io.legado.app.help.LocalConfig +import io.legado.app.help.coroutine.Coroutine +import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.BookWebDav +import io.legado.app.help.storage.ImportOldData import io.legado.app.help.storage.Restore 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.ATH import io.legado.app.lib.theme.accentColor -import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.filepicker.FilePicker import io.legado.app.ui.widget.dialog.TextDialog -import io.legado.app.utils.applyTint -import io.legado.app.utils.getPrefString +import io.legado.app.utils.* +import kotlinx.coroutines.Dispatchers +import splitties.init.appCtx class BackupConfigFragment : BasePreferenceFragment(), - SharedPreferences.OnSharedPreferenceChangeListener, - FilePickerDialog.CallBack { + SharedPreferences.OnSharedPreferenceChangeListener { + + private val selectBackupPath = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + appCtx.contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + AppConfig.backupPath = uri.toString() + } else { + AppConfig.backupPath = uri.path + } + } + private val backupDir = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + appCtx.contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + AppConfig.backupPath = uri.toString() + Coroutine.async { + Backup.backup(appCtx, uri.toString()) + }.onSuccess { + appCtx.toastOnUi(R.string.backup_success) + } + } else { + uri.path?.let { path -> + AppConfig.backupPath = path + Coroutine.async { + Backup.backup(appCtx, path) + }.onSuccess { + appCtx.toastOnUi(R.string.backup_success) + } + } + } + } + private val restoreDir = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + appCtx.contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + AppConfig.backupPath = uri.toString() + Coroutine.async { + Restore.restore(appCtx, uri.toString()) + } + } else { + uri.path?.let { path -> + AppConfig.backupPath = path + Coroutine.async { + Restore.restore(appCtx, path) + } + } + } + } + private val restoreOld = registerForActivityResult(FilePicker()) { uri -> + uri?.let { + ImportOldData.importUri(appCtx, uri) + } + } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config_backup) @@ -53,7 +127,7 @@ class BackupConfigFragment : BasePreferenceFragment(), upPreferenceSummary(PreferKey.webDavPassword, getPrefString(PreferKey.webDavPassword)) upPreferenceSummary(PreferKey.backupPath, getPrefString(PreferKey.backupPath)) findPreference("web_dav_restore") - ?.onLongClick = { BackupRestoreUi.restoreByFolder(this) } + ?.onLongClick = { restoreDir.launch(null) } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -135,11 +209,11 @@ class BackupConfigFragment : BasePreferenceFragment(), override fun onPreferenceTreeClick(preference: Preference?): Boolean { when (preference?.key) { - PreferKey.backupPath -> BackupRestoreUi.selectBackupFolder(this) + PreferKey.backupPath -> selectBackupPath.launch(null) PreferKey.restoreIgnore -> restoreIgnore() - "web_dav_backup" -> BackupRestoreUi.backup(this) - "web_dav_restore" -> BackupRestoreUi.restore(this) - "import_old" -> BackupRestoreUi.importOldData(this) + "web_dav_backup" -> backup() + "web_dav_restore" -> restore() + "import_old" -> restoreOld.launch(null) } return super.onPreferenceTreeClick(preference) } @@ -159,8 +233,81 @@ class BackupConfigFragment : BasePreferenceFragment(), }.show() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - BackupRestoreUi.onActivityResult(requestCode, resultCode, data) + + fun backup() { + val backupPath = AppConfig.backupPath + if (backupPath.isNullOrEmpty()) { + backupDir.launch(null) + } else { + if (backupPath.isContentScheme()) { + val uri = Uri.parse(backupPath) + val doc = DocumentFile.fromTreeUri(requireContext(), uri) + if (doc?.canWrite() == true) { + Coroutine.async { + Backup.backup(requireContext(), backupPath) + }.onSuccess { + toastOnUi(R.string.backup_success) + } + } else { + backupDir.launch(null) + } + } else { + backupUsePermission(backupPath) + } + } } + + private fun backupUsePermission(path: String) { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { + Coroutine.async { + AppConfig.backupPath = path + Backup.backup(requireContext(), path) + }.onSuccess { + toastOnUi(R.string.backup_success) + } + } + .request() + } + + fun restore() { + Coroutine.async(context = Dispatchers.Main) { + BookWebDav.showRestoreDialog(requireContext()) + }.onError { + longToast("WebDavError:${it.localizedMessage}\n将从本地备份恢复。") + val backupPath = getPrefString(PreferKey.backupPath) + if (backupPath?.isNotEmpty() == true) { + if (backupPath.isContentScheme()) { + val uri = Uri.parse(backupPath) + val doc = DocumentFile.fromTreeUri(requireContext(), uri) + if (doc?.canWrite() == true) { + Restore.restore(requireContext(), backupPath) + } else { + restoreDir.launch(null) + } + } else { + restoreUsePermission(backupPath) + } + } else { + restoreDir.launch(null) + } + } + } + + private fun restoreUsePermission(path: String) { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { + Coroutine.async { + AppConfig.backupPath = path + Restore.restoreDatabase(path) + Restore.restoreConfig(path) + } + } + .request() + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt b/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt deleted file mode 100644 index 46fee049a..000000000 --- a/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt +++ /dev/null @@ -1,195 +0,0 @@ -package io.legado.app.ui.config - -import android.app.Activity.RESULT_OK -import android.content.Intent -import android.net.Uri -import androidx.documentfile.provider.DocumentFile -import androidx.fragment.app.Fragment -import io.legado.app.R -import io.legado.app.constant.PreferKey -import io.legado.app.help.AppConfig -import io.legado.app.help.coroutine.Coroutine -import io.legado.app.help.storage.Backup -import io.legado.app.help.storage.BookWebDav -import io.legado.app.help.storage.ImportOldData -import io.legado.app.help.storage.Restore -import io.legado.app.lib.permission.Permissions -import io.legado.app.lib.permission.PermissionsCompat -import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.utils.getPrefString -import io.legado.app.utils.isContentScheme -import io.legado.app.utils.longToast -import io.legado.app.utils.toastOnUi -import kotlinx.coroutines.Dispatchers.Main -import splitties.init.appCtx - -object BackupRestoreUi { - private const val selectFolderRequestCode = 21 - private const val backupSelectRequestCode = 22 - private const val restoreSelectRequestCode = 33 - private const val oldDataRequestCode = 11 - - fun backup(fragment: Fragment) { - val backupPath = AppConfig.backupPath - if (backupPath.isNullOrEmpty()) { - selectBackupFolder(fragment, backupSelectRequestCode) - } else { - if (backupPath.isContentScheme()) { - val uri = Uri.parse(backupPath) - val doc = DocumentFile.fromTreeUri(fragment.requireContext(), uri) - if (doc?.canWrite() == true) { - Coroutine.async { - Backup.backup(fragment.requireContext(), backupPath) - }.onSuccess { - fragment.toastOnUi(R.string.backup_success) - } - } else { - selectBackupFolder(fragment, backupSelectRequestCode) - } - } else { - backupUsePermission(fragment, backupPath) - } - } - } - - private fun backupUsePermission( - fragment: Fragment, - path: String - ) { - 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) - }.onSuccess { - fragment.toastOnUi(R.string.backup_success) - } - } - .request() - } - - fun selectBackupFolder(fragment: Fragment, requestCode: Int = selectFolderRequestCode) { - FilePicker.selectFolder(fragment, requestCode) - } - - fun restore(fragment: Fragment) { - Coroutine.async(context = Main) { - BookWebDav.showRestoreDialog(fragment.requireContext()) - }.onError { - fragment.longToast("WebDavError:${it.localizedMessage}\n将从本地备份恢复。") - val backupPath = fragment.getPrefString(PreferKey.backupPath) - if (backupPath?.isNotEmpty() == true) { - if (backupPath.isContentScheme()) { - val uri = Uri.parse(backupPath) - val doc = DocumentFile.fromTreeUri(fragment.requireContext(), uri) - if (doc?.canWrite() == true) { - Restore.restore(fragment.requireContext(), backupPath) - } else { - selectBackupFolder(fragment, restoreSelectRequestCode) - } - } else { - restoreUsePermission(fragment, backupPath) - } - } else { - selectBackupFolder(fragment, restoreSelectRequestCode) - } - } - } - - fun restoreByFolder(fragment: Fragment) { - selectBackupFolder(fragment, restoreSelectRequestCode) - } - - private fun restoreUsePermission(fragment: Fragment, path: String) { - PermissionsCompat.Builder(fragment) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { - Coroutine.async { - AppConfig.backupPath = path - Restore.restoreDatabase(path) - Restore.restoreConfig(path) - } - } - .request() - } - - fun importOldData(fragment: Fragment) { - FilePicker.selectFolder(fragment, oldDataRequestCode) - } - - fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - backupSelectRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - appCtx.contentResolver.takePersistableUriPermission( - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION - or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - AppConfig.backupPath = uri.toString() - Coroutine.async { - Backup.backup(appCtx, uri.toString()) - }.onSuccess { - appCtx.toastOnUi(R.string.backup_success) - } - } else { - uri.path?.let { path -> - AppConfig.backupPath = path - Coroutine.async { - Backup.backup(appCtx, path) - }.onSuccess { - appCtx.toastOnUi(R.string.backup_success) - } - } - } - } - } - restoreSelectRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - appCtx.contentResolver.takePersistableUriPermission( - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION - or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - AppConfig.backupPath = uri.toString() - Coroutine.async { - Restore.restore(appCtx, uri.toString()) - } - } else { - uri.path?.let { path -> - AppConfig.backupPath = path - Coroutine.async { - Restore.restore(appCtx, path) - } - } - } - } - } - selectFolderRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - appCtx.contentResolver.takePersistableUriPermission( - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION - or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - AppConfig.backupPath = uri.toString() - } else { - AppConfig.backupPath = uri.path - } - } - } - oldDataRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - ImportOldData.importUri(appCtx, uri) - } - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt b/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt index 1d784ec39..92665a7a3 100644 --- a/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt +++ b/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt @@ -1,284 +1,43 @@ package io.legado.app.ui.filepicker +import android.app.Activity.RESULT_OK +import android.content.Context import android.content.Intent -import android.os.Build -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import io.legado.app.R -import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.permission.Permissions -import io.legado.app.lib.permission.PermissionsCompat +import android.net.Uri +import androidx.activity.result.contract.ActivityResultContract @Suppress("unused") -object FilePicker { +class FilePicker : ActivityResultContract() { - fun selectFolder( - activity: AppCompatActivity, - requestCode: Int, - title: String = activity.getString(R.string.select_folder), - otherActions: List? = null, - otherFun: ((action: String) -> Unit)? = null - ) { - val selectList = arrayListOf(activity.getString(R.string.sys_folder_picker)) - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { - selectList.add(activity.getString(R.string.app_folder_picker)) - } - otherActions?.let { - selectList.addAll(otherActions) - } - activity.alert(title = title) { - items(selectList) { _, index -> - when (index) { - 0 -> { - kotlin.runCatching { - val intent = createSelectDirIntent() - activity.startActivityForResult(intent, requestCode) - }.onFailure { - checkPermissions(activity) { - FilePickerDialog.show( - activity.supportFragmentManager, - requestCode, - mode = FilePickerDialog.DIRECTORY - ) - } - } - } - 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) - } - } - } - } - }.show() - } - - fun selectFolder( - fragment: Fragment, - requestCode: Int, - title: String = fragment.getString(R.string.select_folder), - otherActions: List? = null, - otherFun: ((action: String) -> Unit)? = null - ) { - val selectList = arrayListOf(fragment.getString(R.string.sys_folder_picker)) - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { - selectList.add(fragment.getString(R.string.app_folder_picker)) - } - otherActions?.let { - selectList.addAll(otherActions) - } - fragment.alert(title = title) { - items(selectList) { _, index -> - when (index) { - 0 -> { - kotlin.runCatching { - val intent = createSelectDirIntent() - fragment.startActivityForResult(intent, requestCode) - }.onFailure { - checkPermissions(fragment) { - FilePickerDialog.show( - fragment.childFragmentManager, - requestCode, - mode = FilePickerDialog.DIRECTORY - ) - } - } - } - 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) - } - } - } - } - }.show() - } - - fun selectFile( - activity: AppCompatActivity, - requestCode: Int, - title: String = activity.getString(R.string.select_file), - allowExtensions: Array = arrayOf(), - otherActions: List? = null, - otherFun: ((action: String) -> Unit)? = null - ) { - val selectList = arrayListOf(activity.getString(R.string.sys_file_picker)) - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { - selectList.add(activity.getString(R.string.app_file_picker)) - } - otherActions?.let { - selectList.addAll(otherActions) - } - activity.alert(title = title) { - items(selectList) { _, index -> - when (index) { - 0 -> { - kotlin.runCatching { - val intent = createSelectFileIntent() - intent.putExtra( - Intent.EXTRA_MIME_TYPES, - typesOfExtensions(allowExtensions) - ) - activity.startActivityForResult(intent, requestCode) - }.onFailure { - checkPermissions(activity) { - FilePickerDialog.show( - activity.supportFragmentManager, - requestCode, - mode = FilePickerDialog.FILE, - allowExtensions = allowExtensions - ) - } - } - } - 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) - } - } - } - } - }.show() + companion object { + const val DIRECTORY = 0 + const val FILE = 1 } - fun selectFile( - fragment: Fragment, - requestCode: Int, - title: String = fragment.getString(R.string.select_file), - allowExtensions: Array = arrayOf(), - otherActions: List? = null, - otherFun: ((action: String) -> Unit)? = null - ) { - val selectList = arrayListOf(fragment.getString(R.string.sys_file_picker)) - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { - selectList.add(fragment.getString(R.string.app_file_picker)) + override fun createIntent(context: Context, input: FilePickerParam?): Intent { + val intent = Intent(context, FilePickerActivity::class.java) + input?.let { + intent.putExtra("mode", it.mode) + intent.putExtra("title", it.title) + intent.putExtra("allowExtensions", it.allowExtensions) + intent.putExtra("otherActions", it.otherActions) } - otherActions?.let { - selectList.addAll(otherActions) - } - fragment.alert(title = title) { - items(selectList) { _, index -> - when (index) { - 0 -> { - kotlin.runCatching { - val intent = createSelectFileIntent() - intent.putExtra( - Intent.EXTRA_MIME_TYPES, - typesOfExtensions(allowExtensions) - ) - fragment.startActivityForResult(intent, requestCode) - }.onFailure { - checkPermissions(fragment) { - FilePickerDialog.show( - fragment.childFragmentManager, - requestCode, - mode = FilePickerDialog.FILE, - allowExtensions = allowExtensions - ) - } - } - } - 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) - } - } - } - } - }.show() - } - - private fun createSelectFileIntent(): Intent { - val intent = Intent(Intent.ACTION_GET_CONTENT) - intent.addCategory(Intent.CATEGORY_OPENABLE) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) - intent.type = "*/*" - return intent - } - - private fun createSelectDirIntent(): Intent { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) 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() + override fun parseResult(resultCode: Int, intent: Intent?): Uri? { + if (resultCode == RESULT_OK) { + return intent?.data + } + return null } - 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): Array { - val types = hashSetOf() - if (allowExtensions.isNullOrEmpty()) { - types.add("*/*") - } else { - allowExtensions.forEach { - when (it) { - "*" -> types.add("*/*") - "txt", "xml" -> types.add("text/*") - else -> types.add("application/$it") - } - } - } - return types.toTypedArray() - } -} \ No newline at end of file +@Suppress("ArrayInDataClass") +data class FilePickerParam( + var mode: Int = 0, + var title: String? = null, + var allowExtensions: Array = arrayOf(), + var otherActions: Array? = null, +) diff --git a/app/src/main/java/io/legado/app/ui/filepicker/FilePickerActivity.kt b/app/src/main/java/io/legado/app/ui/filepicker/FilePickerActivity.kt new file mode 100644 index 000000000..865bf5372 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/filepicker/FilePickerActivity.kt @@ -0,0 +1,145 @@ +package io.legado.app.ui.filepicker + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import androidx.activity.result.contract.ActivityResultContract +import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.CallSuper +import io.legado.app.R +import io.legado.app.base.BaseActivity +import io.legado.app.constant.Theme +import io.legado.app.databinding.ActivityTranslucenceBinding +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.utils.isContentScheme +import java.io.File + +class FilePickerActivity : + BaseActivity( + theme = Theme.Transparent + ), FilePickerDialog.CallBack { + + private val selectDocTree = + registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { + onResult(Intent().setData(it)) + } + + private val selectDoc = registerForActivityResult(GetContent()) { + onResult(Intent().setData(it)) + } + + override fun getViewBinding(): ActivityTranslucenceBinding { + return ActivityTranslucenceBinding.inflate(layoutInflater) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + val mode = intent.getIntExtra("mode", 0) + val allowExtensions = intent.getStringArrayExtra("allowExtensions") + val selectList = if (mode == FilePicker.DIRECTORY) { + arrayListOf(getString(R.string.sys_folder_picker)) + } else { + arrayListOf(getString(R.string.sys_file_picker)) + } + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { + selectList.add(getString(R.string.app_folder_picker)) + } + intent.getStringArrayListExtra("otherActions")?.let { + selectList.addAll(it) + } + val title = intent.getStringExtra("title") ?: let { + if (mode == FilePicker.DIRECTORY) { + return@let getString(R.string.select_folder) + } else { + return@let getString(R.string.select_file) + } + } + alert(title) { + items(selectList) { _, index -> + when (index) { + 0 -> if (mode == FilePicker.DIRECTORY) { + selectDocTree.launch(null) + } else { + selectDoc.launch(typesOfExtensions(allowExtensions)) + } + 2 -> if (mode == FilePicker.DIRECTORY) { + checkPermissions { + FilePickerDialog.show( + supportFragmentManager, + mode = FilePicker.DIRECTORY + ) + } + } else { + checkPermissions { + FilePickerDialog.show( + supportFragmentManager, + mode = FilePicker.FILE, + allowExtensions = allowExtensions + ) + } + } + else -> { + val path = selectList[index] + val uri = if (path.isContentScheme()) { + Uri.fromFile(File(path)) + } else { + Uri.parse(path) + } + onResult(Intent().setData(uri)) + } + } + } + onCancelled { + finish() + } + }.show() + } + + private fun checkPermissions(success: (() -> Unit)? = null) { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { + success?.invoke() + } + .request() + } + + private fun typesOfExtensions(allowExtensions: Array?): Array { + val types = hashSetOf() + if (allowExtensions.isNullOrEmpty()) { + types.add("*/*") + } else { + allowExtensions.forEach { + when (it) { + "*" -> types.add("*/*") + "txt", "xml" -> types.add("text/*") + else -> types.add("application/$it") + } + } + } + return types.toTypedArray() + } + + override fun onResult(data: Intent) { + setResult(RESULT_OK, data) + finish() + } + + class GetContent : ActivityResultContract, Uri>() { + @CallSuper + override fun createIntent(context: Context, input: Array): Intent { + return Intent(Intent.ACTION_GET_CONTENT) + .addCategory(Intent.CATEGORY_OPENABLE) + .putExtra(Intent.EXTRA_MIME_TYPES, input) + .setType("*/*") + } + + override fun parseResult(resultCode: Int, intent: Intent?): Uri? { + return if (intent == null || resultCode != RESULT_OK) null else intent.data + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/filepicker/FilePickerDialog.kt b/app/src/main/java/io/legado/app/ui/filepicker/FilePickerDialog.kt index 1150a1580..666de4cc3 100644 --- a/app/src/main/java/io/legado/app/ui/filepicker/FilePickerDialog.kt +++ b/app/src/main/java/io/legado/app/ui/filepicker/FilePickerDialog.kt @@ -1,6 +1,6 @@ package io.legado.app.ui.filepicker -import android.app.Activity +import android.content.DialogInterface import android.content.Intent import android.net.Uri import android.os.Bundle @@ -8,7 +8,6 @@ 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.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager @@ -16,8 +15,9 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.databinding.DialogFileChooserBinding -import io.legado.app.lib.permission.Permissions import io.legado.app.lib.theme.primaryColor +import io.legado.app.ui.filepicker.FilePicker.Companion.DIRECTORY +import io.legado.app.ui.filepicker.FilePicker.Companion.FILE import io.legado.app.ui.filepicker.adapter.FileAdapter import io.legado.app.ui.filepicker.adapter.PathAdapter import io.legado.app.ui.widget.recycler.VerticalDivider @@ -33,12 +33,9 @@ class FilePickerDialog : DialogFragment(), companion object { const val tag = "FileChooserDialog" - const val DIRECTORY = 0 - const val FILE = 1 fun show( manager: FragmentManager, - requestCode: Int, mode: Int = FILE, title: String? = null, initPath: String? = null, @@ -51,7 +48,6 @@ class FilePickerDialog : DialogFragment(), FilePickerDialog().apply { val bundle = Bundle() bundle.putInt("mode", mode) - bundle.putInt("requestCode", requestCode) bundle.putString("title", title) bundle.putBoolean("isShowHomeDir", isShowHomeDir) bundle.putBoolean("isShowUpDir", isShowUpDir) @@ -71,20 +67,6 @@ class FilePickerDialog : DialogFragment(), override var isShowHomeDir: Boolean = false override var isShowUpDir: Boolean = true override var isShowHideDir: Boolean = false - private val queryPermission = - registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { - var hasPermission = true - it.forEach { (t, u) -> - if (!u) { - hasPermission = false - toastOnUi(t) - } - } - if (hasPermission) { - refreshCurrentDirPath(initPath) - } - } - private var requestCode: Int = 0 var title: String? = null private var initPath = FileUtils.getSdCardPath() private var mode: Int = FILE @@ -111,7 +93,6 @@ class FilePickerDialog : DialogFragment(), binding.toolBar.setBackgroundColor(primaryColor) view.setBackgroundResource(R.color.background_card) arguments?.let { - requestCode = it.getInt("requestCode") mode = it.getInt("mode", FILE) title = it.getString("title") isShowHomeDir = it.getBoolean("isShowHomeDir") @@ -132,7 +113,7 @@ class FilePickerDialog : DialogFragment(), } initMenu() initContentView() - queryPermission.launch(Permissions.Group.STORAGE) + refreshCurrentDirPath(initPath) } private fun initMenu() { @@ -168,11 +149,6 @@ class FilePickerDialog : DialogFragment(), setData(it) dismissAllowingStateLoss() } - else -> item?.title?.let { - (parentFragment as? CallBack)?.onMenuClick(it.toString()) - (activity as? CallBack)?.onMenuClick(it.toString()) - dismissAllowingStateLoss() - } } return true } @@ -225,14 +201,16 @@ class FilePickerDialog : DialogFragment(), private fun setData(path: String) { val data = Intent().setData(Uri.fromFile(File(path))) - (parentFragment as? CallBack) - ?.onActivityResult(requestCode, Activity.RESULT_OK, data) - (activity as? CallBack) - ?.onActivityResult(requestCode, Activity.RESULT_OK, data) + (parentFragment as? CallBack)?.onResult(data) + (activity as? CallBack)?.onResult(data) + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + activity?.finish() } interface CallBack { - fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) - fun onMenuClick(menu: String) {} + fun onResult(data: Intent) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 4ff1e9b50..4f69d0ec5 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -1,8 +1,6 @@ package io.legado.app.ui.main.bookshelf import android.annotation.SuppressLint -import android.app.Activity.RESULT_OK -import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -30,7 +28,7 @@ import io.legado.app.ui.book.group.GroupManageDialog import io.legado.app.ui.book.local.ImportBookActivity import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.filepicker.FilePickerParam import io.legado.app.ui.main.MainViewModel import io.legado.app.ui.main.bookshelf.books.BooksFragment import io.legado.app.utils.* @@ -41,10 +39,8 @@ import io.legado.app.utils.viewbindingdelegate.viewBinding */ class BookshelfFragment : VMBaseFragment(R.layout.fragment_bookshelf), TabLayout.OnTabSelectedListener, - FilePickerDialog.CallBack, SearchView.OnQueryTextListener { - private val requestCodeImportBookshelf = 312 private val binding by viewBinding(FragmentBookshelfBinding::bind) override val viewModel: BookshelfViewModel by viewModels() private val activityViewModel: MainViewModel by activityViewModels() @@ -53,6 +49,11 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b private var bookGroupLiveData: LiveData>? = null private val bookGroups = mutableListOf() private val fragmentMap = hashMapOf() + private val importBookshelf = registerForActivityResult(FilePicker()) { + it?.readText(requireContext())?.let { text -> + viewModel.importBookshelf(text, selectedGroup.groupId) + } + } override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { tabLayout = binding.titleBar.findViewById(R.id.tab_layout) @@ -229,28 +230,16 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } noButton() neutralButton(R.string.select_file) { - FilePicker.selectFile( - this@BookshelfFragment, - requestCodeImportBookshelf, - allowExtensions = arrayOf("txt", "json") + importBookshelf.launch( + FilePickerParam( + mode = FilePicker.FILE, + allowExtensions = arrayOf("txt", "json") + ) ) } }.show() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - requestCodeImportBookshelf -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - uri.readText(requireContext())?.let { - viewModel.importBookshelf(it, selectedGroup.groupId) - } - } - } - } - } - private inner class TabFragmentPageAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index 4ce39781a..bf09a6171 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -1,6 +1,5 @@ package io.legado.app.ui.main.my -import android.content.Intent import android.content.SharedPreferences import android.os.Bundle import android.view.Menu @@ -21,10 +20,8 @@ import io.legado.app.ui.about.AboutActivity import io.legado.app.ui.about.DonateActivity import io.legado.app.ui.about.ReadRecordActivity import io.legado.app.ui.book.source.manage.BookSourceActivity -import io.legado.app.ui.config.BackupRestoreUi import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel -import io.legado.app.ui.filepicker.FilePickerDialog import io.legado.app.ui.replace.ReplaceRuleActivity import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.ui.widget.prefs.NameListPreference @@ -33,7 +30,7 @@ import io.legado.app.ui.widget.prefs.SwitchPreference import io.legado.app.utils.* import io.legado.app.utils.viewbindingdelegate.viewBinding -class MyFragment : BaseFragment(R.layout.fragment_my_config), FilePickerDialog.CallBack { +class MyFragment : BaseFragment(R.layout.fragment_my_config) { private val binding by viewBinding(FragmentMyConfigBinding::bind) @@ -59,11 +56,6 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config), FilePickerDialog.C } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - BackupRestoreUi.onActivityResult(requestCode, resultCode, data) - } - /** * 配置 */ diff --git a/app/src/main/java/io/legado/app/ui/qrcode/QrCodeResult.kt b/app/src/main/java/io/legado/app/ui/qrcode/QrCodeResult.kt new file mode 100644 index 000000000..b39f09791 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/qrcode/QrCodeResult.kt @@ -0,0 +1,23 @@ +package io.legado.app.ui.qrcode + +import android.app.Activity.RESULT_OK +import android.content.Context +import android.content.Intent +import androidx.activity.result.contract.ActivityResultContract + +class QrCodeResult : ActivityResultContract() { + + override fun createIntent(context: Context, input: Unit?): Intent { + return Intent(context, QrCodeActivity::class.java) + } + + override fun parseResult(resultCode: Int, intent: Intent?): String? { + if (resultCode == RESULT_OK) { + intent?.getStringExtra("result")?.let { + return it + } + } + return null + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt index 13469d229..263e4896a 100644 --- a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt @@ -2,7 +2,6 @@ package io.legado.app.ui.replace import android.annotation.SuppressLint import android.app.Activity -import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -30,8 +29,8 @@ import io.legado.app.lib.theme.primaryTextColor import io.legado.app.service.help.ReadBook import io.legado.app.ui.association.ImportReplaceRuleActivity import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog -import io.legado.app.ui.qrcode.QrCodeActivity +import io.legado.app.ui.filepicker.FilePickerParam +import io.legado.app.ui.qrcode.QrCodeResult import io.legado.app.ui.replace.edit.ReplaceEditActivity import io.legado.app.ui.widget.SelectActionBar import io.legado.app.ui.widget.dialog.TextDialog @@ -47,24 +46,50 @@ import java.io.File class ReplaceRuleActivity : VMBaseActivity(), SearchView.OnQueryTextListener, PopupMenu.OnMenuItemClickListener, - FilePickerDialog.CallBack, SelectActionBar.CallBack, ReplaceRuleAdapter.CallBack { override val viewModel: ReplaceRuleViewModel by viewModels() private val importRecordKey = "replaceRuleRecordKey" - private val importRequestCode = 132 - private val importRequestCodeQr = 133 - private val exportRequestCode = 234 - private val editActivity = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - setResult(RESULT_OK) - } private lateinit var adapter: ReplaceRuleAdapter private lateinit var searchView: SearchView private var groups = hashSetOf() private var groupMenu: SubMenu? = null private var replaceRuleLiveData: LiveData>? = null private var dataInit = false + private val qrCodeResult = registerForActivityResult(QrCodeResult()) { + it ?: return@registerForActivityResult + startActivity { + putExtra("source", it) + } + } + private val editActivity = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + setResult(RESULT_OK) + } + private val importDoc = registerForActivityResult(FilePicker()) { uri -> + kotlin.runCatching { + uri?.readText(this)?.let { + val dataKey = IntentDataHelp.putData(it) + startActivity { + putExtra("dataKey", dataKey) + } + } + }.onFailure { + toastOnUi("readTextError:${it.localizedMessage}") + } + } + private val exportDir = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + DocumentFile.fromTreeUri(this, uri)?.let { + viewModel.exportSelection(adapter.getSelection(), it) + } + } else { + uri.path?.let { + viewModel.exportSelection(adapter.getSelection(), File(it)) + } + } + } override fun getViewBinding(): ActivityReplaceRuleBinding { return ActivityReplaceRuleBinding.inflate(layoutInflater) @@ -190,9 +215,13 @@ class ReplaceRuleActivity : VMBaseActivity viewModel.delSelection(adapter.getSelection()) R.id.menu_import_source_onLine -> showImportDialog() - R.id.menu_import_source_local -> FilePicker - .selectFile(this, importRequestCode, allowExtensions = arrayOf("txt", "json")) - R.id.menu_import_source_qr -> startActivityForResult(importRequestCodeQr) + R.id.menu_import_source_local -> importDoc.launch( + FilePickerParam( + mode = FilePicker.FILE, + allowExtensions = arrayOf("txt", "json") + ) + ) + R.id.menu_import_source_qr -> qrCodeResult.launch(null) R.id.menu_help -> showHelp() else -> if (item.groupId == R.id.replace_group) { searchView.setQuery("group:${item.title}", true) @@ -205,7 +234,7 @@ class ReplaceRuleActivity : VMBaseActivity viewModel.enableSelection(adapter.getSelection()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelection()) - R.id.menu_export_selection -> FilePicker.selectFolder(this, exportRequestCode) + R.id.menu_export_selection -> exportDir.launch(null) } return false } @@ -263,47 +292,6 @@ class ReplaceRuleActivity : VMBaseActivity { - data?.data?.let { uri -> - kotlin.runCatching { - uri.readText(this)?.let { - val dataKey = IntentDataHelp.putData(it) - startActivity { - putExtra("dataKey", dataKey) - } - } - }.onFailure { - toastOnUi("readTextError:${it.localizedMessage}") - } - } - } - importRequestCodeQr -> { - data?.getStringExtra("result")?.let { - startActivity { - putExtra("source", it) - } - } - } - exportRequestCode -> { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - DocumentFile.fromTreeUri(this, uri)?.let { - viewModel.exportSelection(adapter.getSelection(), it) - } - } else { - uri.path?.let { - viewModel.exportSelection(adapter.getSelection(), File(it)) - } - } - } - } - } - } - override fun onDestroy() { super.onDestroy() Coroutine.async { ReadBook.contentProcessor?.upReplaceRules() } diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 42372eaf5..cee652ca9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -24,7 +24,7 @@ import io.legado.app.ui.association.ImportBookSourceActivity import io.legado.app.ui.association.ImportReplaceRuleActivity import io.legado.app.ui.association.ImportRssSourceActivity import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.filepicker.FilePickerParam import io.legado.app.utils.* import kotlinx.coroutines.launch import org.apache.commons.text.StringEscapeUtils @@ -33,7 +33,6 @@ import splitties.systemservices.downloadManager class ReadRssActivity : VMBaseActivity(false), - FilePickerDialog.CallBack, ReadRssViewModel.CallBack { override val viewModel: ReadRssViewModel @@ -44,6 +43,10 @@ class ReadRssActivity : VMBaseActivity private var ttsMenuItem: MenuItem? = null private var customWebViewCallback: WebChromeClient.CustomViewCallback? = null private var webPic: String? = null + private val saveImage = registerForActivityResult(FilePicker()) { + ACache.get(this).put(imagePathKey, it.toString()) + viewModel.saveImage(webPic, it.toString()) + } override fun getViewBinding(): ActivityRssReadBinding { return ActivityRssReadBinding.inflate(layoutInflater) @@ -156,14 +159,11 @@ class ReadRssActivity : VMBaseActivity if (!path.isNullOrEmpty()) { default.add(path) } - FilePicker.selectFolder( - this, - savePathRequestCode, - getString(R.string.save_image), - default - ) { - viewModel.saveImage(webPic, it) - } + saveImage.launch( + FilePickerParam( + otherActions = default.toTypedArray() + ) + ) } @SuppressLint("SetJavaScriptEnabled") @@ -269,16 +269,6 @@ class ReadRssActivity : VMBaseActivity } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - savePathRequestCode -> data?.data?.let { - ACache.get(this).put(imagePathKey, it.toString()) - viewModel.saveImage(webPic, it.toString()) - } - } - } - override fun onDestroy() { super.onDestroy() binding.webView.destroy() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 3a763c87b..03ed50688 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -1,7 +1,6 @@ package io.legado.app.ui.rss.source.manage import android.annotation.SuppressLint -import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.Menu @@ -26,8 +25,8 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.association.ImportRssSourceActivity import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog -import io.legado.app.ui.qrcode.QrCodeActivity +import io.legado.app.ui.filepicker.FilePickerParam +import io.legado.app.ui.qrcode.QrCodeResult import io.legado.app.ui.rss.source.edit.RssSourceEditActivity import io.legado.app.ui.widget.SelectActionBar import io.legado.app.ui.widget.dialog.TextDialog @@ -37,23 +36,51 @@ import io.legado.app.ui.widget.recycler.VerticalDivider import io.legado.app.utils.* import java.io.File - +/** + * 订阅源管理 + */ class RssSourceActivity : VMBaseActivity(), PopupMenu.OnMenuItemClickListener, - FilePickerDialog.CallBack, SelectActionBar.CallBack, RssSourceAdapter.CallBack { override val viewModel: RssSourceViewModel by viewModels() private val importRecordKey = "rssSourceRecordKey" - private val qrRequestCode = 101 - private val importRequestCode = 124 - private val exportRequestCode = 65 private lateinit var adapter: RssSourceAdapter private var sourceLiveData: LiveData>? = null private var groups = hashSetOf() private var groupMenu: SubMenu? = null + private val qrCodeResult = registerForActivityResult(QrCodeResult()) { + it ?: return@registerForActivityResult + startActivity { + putExtra("source", it) + } + } + private val importDoc = registerForActivityResult(FilePicker()) { uri -> + kotlin.runCatching { + uri?.readText(this)?.let { + val dataKey = IntentDataHelp.putData(it) + startActivity { + putExtra("dataKey", dataKey) + } + } + }.onFailure { + toastOnUi("readTextError:${it.localizedMessage}") + } + } + private val exportDir = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.isContentScheme()) { + DocumentFile.fromTreeUri(this, uri)?.let { + viewModel.exportSelection(adapter.getSelection(), it) + } + } else { + uri.path?.let { + viewModel.exportSelection(adapter.getSelection(), File(it)) + } + } + } override fun getViewBinding(): ActivityRssSourceBinding { return ActivityRssSourceBinding.inflate(layoutInflater) @@ -81,10 +108,14 @@ class RssSourceActivity : VMBaseActivity startActivity() - R.id.menu_import_source_local -> FilePicker - .selectFile(this, importRequestCode, allowExtensions = arrayOf("txt", "json")) + R.id.menu_import_source_local -> importDoc.launch( + FilePickerParam( + mode = FilePicker.FILE, + allowExtensions = arrayOf("txt", "json") + ) + ) R.id.menu_import_source_onLine -> showImportDialog() - R.id.menu_import_source_qr -> startActivityForResult(qrRequestCode) + R.id.menu_import_source_qr -> qrCodeResult.launch(null) R.id.menu_group_manage -> GroupManageDialog() .show(supportFragmentManager, "rssGroupManage") R.id.menu_share_source -> viewModel.shareSelection(adapter.getSelection()) { @@ -105,7 +136,7 @@ class RssSourceActivity : VMBaseActivity viewModel.enableSelection(adapter.getSelection()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelection()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelection()) - R.id.menu_export_selection -> FilePicker.selectFolder(this, exportRequestCode) + R.id.menu_export_selection -> exportDir.launch(null) R.id.menu_top_sel -> viewModel.topSource(*adapter.getSelection().toTypedArray()) R.id.menu_bottom_sel -> viewModel.bottomSource(*adapter.getSelection().toTypedArray()) } @@ -260,46 +291,6 @@ class RssSourceActivity : VMBaseActivity if (resultCode == Activity.RESULT_OK) { - data?.data?.let { uri -> - kotlin.runCatching { - uri.readText(this)?.let { - val dataKey = IntentDataHelp.putData(it) - startActivity { - putExtra("dataKey", dataKey) - } - } - }.onFailure { - toastOnUi("readTextError:${it.localizedMessage}") - } - } - } - qrRequestCode -> if (resultCode == RESULT_OK) { - data?.getStringExtra("result")?.let { - startActivity { - putExtra("source", it) - } - } - } - exportRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - if (uri.isContentScheme()) { - DocumentFile.fromTreeUri(this, uri)?.let { - viewModel.exportSelection(adapter.getSelection(), it) - } - } else { - uri.path?.let { - viewModel.exportSelection(adapter.getSelection(), File(it)) - } - } - } - } - } - } - override fun del(source: RssSource) { viewModel.del(source) } diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 6be1e4d65..de1af18ba 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -1,6 +1,5 @@ package io.legado.app.ui.widget.font -import android.app.Activity.RESULT_OK import android.content.Intent import android.net.Uri import android.os.Bundle @@ -21,7 +20,7 @@ import io.legado.app.lib.permission.Permissions import io.legado.app.lib.permission.PermissionsCompat import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.filepicker.FilePicker -import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.filepicker.FilePickerParam import io.legado.app.utils.* import io.legado.app.utils.viewbindingdelegate.viewBinding import kotlinx.coroutines.Dispatchers.Main @@ -32,16 +31,37 @@ import java.util.* import kotlin.collections.ArrayList class FontSelectDialog : BaseDialogFragment(), - FilePickerDialog.CallBack, Toolbar.OnMenuItemClickListener, FontAdapter.CallBack { - private val fontFolderRequestCode = 35485 private val fontRegex = Regex(".*\\.[ot]tf") private val fontFolder by lazy { FileUtils.createFolderIfNotExist(appCtx.filesDir, "Fonts") } private var adapter: FontAdapter? = null private val binding by viewBinding(DialogFontSelectBinding::bind) + private val selectFontDir = registerForActivityResult(FilePicker()) { uri -> + uri ?: return@registerForActivityResult + if (uri.toString().isContentScheme()) { + putPrefString(PreferKey.fontFolder, uri.toString()) + val doc = DocumentFile.fromTreeUri(requireContext(), uri) + if (doc != null) { + context?.contentResolver?.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + ) + loadFontFiles(doc) + } else { + RealPathUtil.getPath(requireContext(), uri)?.let { + loadFontFilesByPermission(it) + } + } + } else { + uri.path?.let { path -> + putPrefString(PreferKey.fontFolder, path) + loadFontFilesByPermission(path) + } + } + } override fun onStart() { super.onStart() @@ -108,19 +128,11 @@ class FontSelectDialog : BaseDialogFragment(), private fun openFolder() { launch(Main) { val defaultPath = "SD${File.separator}Fonts" - FilePicker.selectFolder( - this@FontSelectDialog, - fontFolderRequestCode, - otherActions = arrayListOf(defaultPath) - ) { - when (it) { - defaultPath -> { - val path = "${FileUtils.getSdCardPath()}${File.separator}Fonts" - putPrefString(PreferKey.fontFolder, path) - loadFontFilesByPermission(path) - } - } - } + selectFontDir.launch( + FilePickerParam( + otherActions = arrayOf(defaultPath) + ) + ) } } @@ -227,36 +239,6 @@ class FontSelectDialog : BaseDialogFragment(), } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - fontFolderRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { uri -> - if (uri.toString().isContentScheme()) { - putPrefString(PreferKey.fontFolder, uri.toString()) - val doc = DocumentFile.fromTreeUri(requireContext(), uri) - if (doc != null) { - context?.contentResolver?.takePersistableUriPermission( - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION - ) - loadFontFiles(doc) - } else { - RealPathUtil.getPath(requireContext(), uri)?.let { - loadFontFilesByPermission(it) - } - } - } else { - uri.path?.let { path -> - putPrefString(PreferKey.fontFolder, path) - loadFontFilesByPermission(path) - } - } - } - } - } - } - private fun onDefaultFontChange() { callBack?.selectFont("") } diff --git a/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt b/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt index 5a086cf29..1883dd7e0 100644 --- a/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt @@ -10,10 +10,6 @@ import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.core.content.edit import androidx.fragment.app.Fragment -import splitties.systemservices.connectivityManager - -@Suppress("DEPRECATION") -fun Fragment.isOnline() = connectivityManager.activeNetworkInfo?.isConnected == true fun Fragment.getPrefBoolean(key: String, defValue: Boolean = false) = requireContext().defaultSharedPreferences.getBoolean(key, defValue) @@ -63,11 +59,4 @@ inline fun Fragment.startActivity( configIntent: Intent.() -> Unit = {} ) { startActivity(Intent(requireContext(), T::class.java).apply(configIntent)) -} - -inline fun Fragment.startActivityForResult( - requestCode: Int, - configIntent: Intent.() -> Unit = {} -) { - startActivityForResult(Intent(requireContext(), T::class.java).apply(configIntent), requestCode) } \ No newline at end of file