Merge pull request #8 from gedoor/master

up
pull/69/head
口口吕 5 years ago committed by GitHub
commit f41d6373d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      app/src/main/assets/updateLog.md
  2. 25
      app/src/main/java/io/legado/app/help/storage/OldRule.kt
  3. 17
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  4. 55
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  5. 36
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  6. 84
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt
  7. 14
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt
  8. 20
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt
  9. 1
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt
  10. 32
      app/src/main/java/io/legado/app/utils/DocumentUtils.kt
  11. 61
      app/src/main/java/io/legado/app/utils/UriExtensions.kt

@ -5,6 +5,7 @@
**2020/01/07** **2020/01/07**
* 修复备份问题 * 修复备份问题
* 设置背景不再需要存储权限
**2020/01/06** **2020/01/06**
* 适配Android 10 权限 * 适配Android 10 权限

@ -3,6 +3,7 @@ package io.legado.app.help.storage
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.ReplaceRule
import io.legado.app.data.entities.rule.* import io.legado.app.data.entities.rule.*
import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.help.storage.Restore.jsonPath
import io.legado.app.utils.* import io.legado.app.utils.*
@ -205,5 +206,27 @@ object OldRule {
return GSON.toJson(map) return GSON.toJson(map)
} }
fun jsonToReplaceRule(json: String): ReplaceRule? {
var replaceRule: ReplaceRule? = null
runCatching {
replaceRule = GSON.fromJsonObject<ReplaceRule>(json.trim())
}
runCatching {
if (replaceRule == null || replaceRule?.pattern.isNullOrBlank()) {
val jsonItem = jsonPath.parse(json.trim())
val rule = ReplaceRule()
rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis()
rule.pattern = jsonItem.readString("$.regex") ?: ""
if (rule.pattern.isEmpty()) return null
rule.name = jsonItem.readString("$.replaceSummary") ?: ""
rule.replacement = jsonItem.readString("$.replacement") ?: ""
rule.isRegex = jsonItem.readBool("$.isRegex") == true
rule.scope = jsonItem.readString("$.useTo")
rule.isEnabled = jsonItem.readBool("$.enable") == true
rule.order = jsonItem.readInt("$.serialNumber") ?: 0
return rule
}
}
return replaceRule
}
} }

@ -226,20 +226,11 @@ object Restore {
fun importOldReplaceRule(json: String): Int { fun importOldReplaceRule(json: String): Int {
val replaceRules = mutableListOf<ReplaceRule>() val replaceRules = mutableListOf<ReplaceRule>()
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$") val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() for (item in items) {
for ((index: Int, item: Map<String, Any>) in items.withIndex()) {
val jsonItem = jsonPath.parse(item) val jsonItem = jsonPath.parse(item)
val rule = ReplaceRule() OldRule.jsonToReplaceRule(jsonItem.jsonString())?.let {
rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis().plus(index) replaceRules.add(it)
rule.pattern = jsonItem.readString("$.regex") ?: "" }
if (rule.pattern.isEmpty() || rule.pattern in existingRules) continue
rule.name = jsonItem.readString("$.replaceSummary") ?: ""
rule.replacement = jsonItem.readString("$.replacement") ?: ""
rule.isRegex = jsonItem.readBool("$.isRegex") == true
rule.scope = jsonItem.readString("$.useTo")
rule.isEnabled = jsonItem.readBool("$.enable") == true
rule.order = jsonItem.readInt("$.serialNumber") ?: index
replaceRules.add(rule)
} }
App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) App.db.replaceRuleDao().insert(*replaceRules.toTypedArray())
return replaceRules.size return replaceRules.size

@ -12,6 +12,7 @@ import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -20,11 +21,13 @@ import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.base.adapter.SimpleRecyclerAdapter
import io.legado.app.constant.Bus import io.legado.app.constant.Bus
import io.legado.app.help.FileHelp
import io.legado.app.help.ImageLoader import io.legado.app.help.ImageLoader
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.ui.book.read.Help import io.legado.app.ui.book.read.Help
import io.legado.app.utils.DocumentUtils
import io.legado.app.utils.FileUtils import io.legado.app.utils.FileUtils
import io.legado.app.utils.getCompatColor import io.legado.app.utils.getCompatColor
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
@ -32,6 +35,7 @@ import kotlinx.android.synthetic.main.dialog_read_bg_text.*
import kotlinx.android.synthetic.main.item_bg_image.view.* import kotlinx.android.synthetic.main.item_bg_image.view.*
import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onCheckedChange
import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onClick
import java.io.File
class BgTextConfigDialog : DialogFragment() { class BgTextConfigDialog : DialogFragment() {
@ -133,17 +137,10 @@ class BgTextConfigDialog : DialogFragment() {
} }
private fun selectImage() { private fun selectImage() {
PermissionsCompat.Builder(this) val intent = Intent(Intent.ACTION_GET_CONTENT)
.addPermissions(Permissions.READ_EXTERNAL_STORAGE, Permissions.WRITE_EXTERNAL_STORAGE) intent.addCategory(Intent.CATEGORY_OPENABLE)
.rationale(R.string.bg_image_per) intent.type = "image/*"
.onGranted { startActivityForResult(intent, resultSelectBg)
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, resultSelectBg)
Unit
}
.request()
} }
class BgAdapter(context: Context) : class BgAdapter(context: Context) :
@ -170,11 +167,37 @@ class BgTextConfigDialog : DialogFragment() {
when (requestCode) { when (requestCode) {
resultSelectBg -> { resultSelectBg -> {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
data?.data?.let { data?.data?.let { uri ->
FileUtils.getPath(requireContext(), it)?.let { path -> if (DocumentFile.isDocumentUri(requireContext(), uri)) {
ReadBookConfig.getConfig().setBg(2, path) val doc = DocumentFile.fromSingleUri(requireContext(), uri)
ReadBookConfig.upBg() doc?.let {
postEvent(Bus.UP_CONFIG, false) var file = requireContext().getExternalFilesDir(null)
?: requireContext().filesDir
file =
FileHelp.getFile(file.absolutePath + File.separator + "bg" + File.separator + doc.name)
DocumentUtils.readBytes(requireContext(), uri)?.let {
file.writeBytes(it)
ReadBookConfig.getConfig().setBg(2, file.absolutePath)
ReadBookConfig.upBg()
postEvent(Bus.UP_CONFIG, false)
}
}
} else {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.onGranted {
FileUtils.getPath(requireContext(), uri)?.let { path ->
ReadBookConfig.getConfig().setBg(2, path)
ReadBookConfig.upBg()
postEvent(Bus.UP_CONFIG, false)
}
Unit
}
.request()
} }
} }
} }

@ -49,7 +49,7 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
get() = getViewModel(BookSourceViewModel::class.java) get() = getViewModel(BookSourceViewModel::class.java)
private val qrRequestCode = 101 private val qrRequestCode = 101
private val importSource = 13141 private val importSource = 132
private lateinit var adapter: BookSourceAdapter private lateinit var adapter: BookSourceAdapter
private var bookSourceLiveDate: LiveData<List<BookSource>>? = null private var bookSourceLiveDate: LiveData<List<BookSource>>? = null
private var groups = hashSetOf<String>() private var groups = hashSetOf<String>()
@ -82,7 +82,7 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
supportFragmentManager, supportFragmentManager,
"groupManage" "groupManage"
) )
R.id.menu_import_source_local -> selectFile() R.id.menu_import_source_local -> selectFileSys()
R.id.menu_select_all -> adapter.selectAll() R.id.menu_select_all -> adapter.selectAll()
R.id.menu_revert_selection -> adapter.revertSelection() R.id.menu_revert_selection -> adapter.revertSelection()
R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds())
@ -219,10 +219,15 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
} }
private fun selectFileSys() { private fun selectFileSys() {
val intent = Intent(Intent.ACTION_GET_CONTENT) try {
intent.addCategory(Intent.CATEGORY_OPENABLE) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "text/*"//设置类型 intent.addCategory(Intent.CATEGORY_OPENABLE)
startActivityForResult(intent, importSource) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = "text/*"//设置类型
startActivityForResult(intent, importSource)
} catch (e: Exception) {
selectFile()
}
} }
override fun onMenuClick(menu: String) { override fun onMenuClick(menu: String) {
@ -284,16 +289,17 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
} }
} }
importSource -> if (resultCode == Activity.RESULT_OK) { importSource -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { data?.data?.let { uri ->
val path = FileUtils.getPath(this, it) try {
if (path != null) { uri.readText(this)?.let {
Snackbar.make(title_bar, R.string.importing, Snackbar.LENGTH_INDEFINITE) Snackbar.make(title_bar, R.string.importing, Snackbar.LENGTH_INDEFINITE)
.show() .show()
viewModel.importSourceFromFilePath(path) { msg -> viewModel.importSource(it) { msg ->
title_bar.snackbar(msg) toast(msg)
}
} }
} else { } catch (e: Exception) {
toast(R.string.uri_to_path_fail) e.localizedMessage?.let { toast(it) }
} }
} }
} }

@ -1,6 +1,8 @@
package io.legado.app.ui.replacerule package io.legado.app.ui.replacerule
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -13,18 +15,25 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import io.legado.app.App import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.ItemTouchCallback import io.legado.app.help.ItemTouchCallback
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.cancelButton
import io.legado.app.lib.dialogs.customView
import io.legado.app.lib.dialogs.okButton
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.primaryTextColor import io.legado.app.lib.theme.primaryTextColor
import io.legado.app.lib.theme.view.ATEAutoCompleteTextView
import io.legado.app.ui.replacerule.edit.ReplaceEditDialog import io.legado.app.ui.replacerule.edit.ReplaceEditDialog
import io.legado.app.utils.getViewModel import io.legado.app.utils.*
import io.legado.app.utils.splitNotBlank
import kotlinx.android.synthetic.main.activity_replace_rule.* import kotlinx.android.synthetic.main.activity_replace_rule.*
import kotlinx.android.synthetic.main.dialog_edit_text.view.*
import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_search.*
import org.jetbrains.anko.toast
class ReplaceRuleActivity : VMBaseActivity<ReplaceRuleViewModel>(R.layout.activity_replace_rule), class ReplaceRuleActivity : VMBaseActivity<ReplaceRuleViewModel>(R.layout.activity_replace_rule),
@ -32,7 +41,7 @@ class ReplaceRuleActivity : VMBaseActivity<ReplaceRuleViewModel>(R.layout.activi
ReplaceRuleAdapter.CallBack { ReplaceRuleAdapter.CallBack {
override val viewModel: ReplaceRuleViewModel override val viewModel: ReplaceRuleViewModel
get() = getViewModel(ReplaceRuleViewModel::class.java) get() = getViewModel(ReplaceRuleViewModel::class.java)
private val importSource = 132
private lateinit var adapter: ReplaceRuleAdapter private lateinit var adapter: ReplaceRuleAdapter
private var groups = hashSetOf<String>() private var groups = hashSetOf<String>()
private var groupMenu: SubMenu? = null private var groupMenu: SubMenu? = null
@ -68,6 +77,8 @@ class ReplaceRuleActivity : VMBaseActivity<ReplaceRuleViewModel>(R.layout.activi
R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds())
R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds())
R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds())
R.id.menu_import_source_onLine -> showImportDialog()
R.id.menu_import_source_local -> selectFileSys()
R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelectionIds()) R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelectionIds())
} }
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
@ -134,6 +145,52 @@ class ReplaceRuleActivity : VMBaseActivity<ReplaceRuleViewModel>(R.layout.activi
} }
} }
@SuppressLint("InflateParams")
private fun showImportDialog() {
val aCache = ACache.get(this, cacheDir = false)
val cacheUrls: MutableList<String> = aCache
.getAsString("replaceRuleUrl")
?.splitNotBlank(",")
?.toMutableList() ?: mutableListOf()
alert(titleResource = R.string.import_replace_rule_on_line) {
var editText: ATEAutoCompleteTextView? = null
customView {
layoutInflater.inflate(R.layout.dialog_edit_text, null).apply {
editText = edit_view
edit_view.setFilterValues(cacheUrls) {
cacheUrls.remove(it)
aCache.put("replaceRuleUrl", cacheUrls.joinToString(","))
}
}
}
okButton {
val text = editText?.text?.toString()
text?.let {
if (!cacheUrls.contains(it)) {
cacheUrls.add(0, it)
aCache.put("replaceRuleUrl", cacheUrls.joinToString(","))
}
Snackbar.make(title_bar, R.string.importing, Snackbar.LENGTH_INDEFINITE).show()
viewModel.importSource(it) { msg ->
title_bar.snackbar(msg)
}
}
}
cancelButton()
}.show().applyTint()
}
private fun selectFileSys() {
try {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = "text/*"//设置类型
startActivityForResult(intent, importSource)
} catch (e: Exception) {
}
}
override fun onQueryTextChange(newText: String?): Boolean { override fun onQueryTextChange(newText: String?): Boolean {
observeReplaceRuleData("%$newText%") observeReplaceRuleData("%$newText%")
@ -144,6 +201,27 @@ class ReplaceRuleActivity : VMBaseActivity<ReplaceRuleViewModel>(R.layout.activi
return false return false
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
importSource -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
try {
uri.readText(this)?.let {
Snackbar.make(title_bar, R.string.importing, Snackbar.LENGTH_INDEFINITE)
.show()
viewModel.importSource(it) { msg ->
toast(msg)
}
}
} catch (e: Exception) {
e.localizedMessage?.let { toast(it) }
}
}
}
}
}
override fun update(vararg rule: ReplaceRule) { override fun update(vararg rule: ReplaceRule) {
viewModel.update(*rule) viewModel.update(*rule)
} }

@ -3,10 +3,12 @@ package io.legado.app.ui.replacerule
import android.app.Application import android.app.Application
import android.text.TextUtils import android.text.TextUtils
import io.legado.app.App import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.FileHelp import io.legado.app.help.FileHelp
import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.Restore
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@ -14,6 +16,15 @@ import java.io.File
class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) { class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) {
fun importSource(text: String, toast: (msg: String) -> Unit) {
execute {
Restore.importOldReplaceRule(text)
}.onError {
toast(it.localizedMessage ?: "ERROR")
}.onSuccess {
toast(context.getString(R.string.success))
}
}
fun update(vararg rule: ReplaceRule) { fun update(vararg rule: ReplaceRule) {
execute { execute {
@ -68,7 +79,8 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application
App.db.replaceRuleDao().findById(it) App.db.replaceRuleDao().findById(it)
}.let { }.let {
val json = GSON.toJson(it) val json = GSON.toJson(it)
val file = FileHelp.getFile(Backup.exportPath + File.separator + "exportReplaceRule.json") val file =
FileHelp.getFile(Backup.exportPath + File.separator + "exportReplaceRule.json")
file.writeText(json) file.writeText(json)
} }
}.onSuccess { }.onSuccess {

@ -80,7 +80,7 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds())
R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds())
R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelectionIds()) R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelectionIds())
R.id.menu_import_source_local -> selectFile() R.id.menu_import_source_local -> selectFileSys()
R.id.menu_import_source_onLine -> showImportDialog() R.id.menu_import_source_onLine -> showImportDialog()
R.id.menu_import_source_qr -> startActivityForResult<QrCodeActivity>(qrRequestCode) R.id.menu_import_source_qr -> startActivityForResult<QrCodeActivity>(qrRequestCode)
R.id.menu_group_manage -> GroupManageDialog() R.id.menu_group_manage -> GroupManageDialog()
@ -203,10 +203,14 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
} }
private fun selectFileSys() { private fun selectFileSys() {
val intent = Intent(Intent.ACTION_GET_CONTENT) try {
intent.addCategory(Intent.CATEGORY_OPENABLE) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "text/*"//设置类型 intent.addCategory(Intent.CATEGORY_OPENABLE)
startActivityForResult(intent, importSource) intent.type = "text/*"//设置类型
startActivityForResult(intent, importSource)
} catch (e: Exception) {
selectFile()
}
} }
override fun onMenuClick(menu: String) { override fun onMenuClick(menu: String) {
@ -229,11 +233,11 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
when (requestCode) { when (requestCode) {
importSource -> if (resultCode == Activity.RESULT_OK) { importSource -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { data?.data?.let { uri ->
FileUtils.getPath(this, it)?.let { path -> uri.readText(this)?.let {
Snackbar.make(title_bar, R.string.importing, Snackbar.LENGTH_INDEFINITE) Snackbar.make(title_bar, R.string.importing, Snackbar.LENGTH_INDEFINITE)
.show() .show()
viewModel.importSourceFromFilePath(path) { msg -> viewModel.importSource(it) { msg ->
title_bar.snackbar(msg) title_bar.snackbar(msg)
} }
} }

@ -115,7 +115,6 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application)
} }
} }
fun importSourceFromFilePath(path: String, finally: (msg: String) -> Unit) { fun importSourceFromFilePath(path: String, finally: (msg: String) -> Unit) {
execute { execute {
val file = File(path) val file = File(path)

@ -6,25 +6,24 @@ import android.net.Uri
object DocumentUtils { object DocumentUtils {
@JvmStatic @JvmStatic
@Throws(Exception::class)
fun writeText(context: Context, data: String, fileUri: Uri): Boolean { fun writeText(context: Context, data: String, fileUri: Uri): Boolean {
return writeBytes(context, data.toByteArray(), fileUri) return writeBytes(context, data.toByteArray(), fileUri)
} }
@JvmStatic @JvmStatic
@Throws(Exception::class)
fun writeBytes(context: Context, data: ByteArray, fileUri: Uri): Boolean { fun writeBytes(context: Context, data: ByteArray, fileUri: Uri): Boolean {
try { context.contentResolver.openOutputStream(fileUri)?.let {
context.contentResolver.openOutputStream(fileUri)?.let { it.write(data)
it.write(data) it.close()
it.close() return true
return true
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
} }
return false return false
} }
@JvmStatic @JvmStatic
@Throws(Exception::class)
fun readText(context: Context, uri: Uri): String? { fun readText(context: Context, uri: Uri): String? {
readBytes(context, uri)?.let { readBytes(context, uri)?.let {
return String(it) return String(it)
@ -33,17 +32,14 @@ object DocumentUtils {
} }
@JvmStatic @JvmStatic
@Throws(Exception::class)
fun readBytes(context: Context, uri: Uri): ByteArray? { fun readBytes(context: Context, uri: Uri): ByteArray? {
try { context.contentResolver.openInputStream(uri)?.let {
context.contentResolver.openInputStream(uri)?.let { val len: Int = it.available()
val len: Int = it.available() val buffer = ByteArray(len)
val buffer = ByteArray(len) it.read(buffer)
it.read(buffer) it.close()
it.close() return buffer
return buffer
}
} catch (e: Exception) {
e.printStackTrace()
} }
return null return null
} }

@ -0,0 +1,61 @@
package io.legado.app.utils
import android.content.Context
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import java.io.File
@Throws(Exception::class)
fun Uri.readBytes(context: Context): ByteArray? {
if (DocumentFile.isDocumentUri(context, this)) {
return DocumentUtils.readBytes(context, this)
} else {
val path = FileUtils.getPath(context, this)
if (path?.isNotEmpty() == true) {
return File(path).readBytes()
}
}
return null
}
@Throws(Exception::class)
fun Uri.readText(context: Context): String? {
if (DocumentFile.isDocumentUri(context, this)) {
return DocumentUtils.readText(context, this)
} else {
val path = FileUtils.getPath(context, this)
if (path?.isNotEmpty() == true) {
return File(path).readText()
}
}
return null
}
@Throws(Exception::class)
fun Uri.writeBytes(context: Context, byteArray: ByteArray): Boolean {
if (DocumentFile.isDocumentUri(context, this)) {
return DocumentUtils.writeBytes(context, byteArray, this)
} else {
val path = FileUtils.getPath(context, this)
if (path?.isNotEmpty() == true) {
File(path).writeBytes(byteArray)
return true
}
}
return false
}
@Throws(Exception::class)
fun Uri.writeText(context: Context, text: String): Boolean {
if (DocumentFile.isDocumentUri(context, this)) {
return DocumentUtils.writeText(context, text, this)
} else {
val path = FileUtils.getPath(context, this)
if (path?.isNotEmpty() == true) {
File(path).writeText(text)
return true
}
}
return false
}
Loading…
Cancel
Save