diff --git a/README.md b/README.md index e63456b42..843400d98 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,10 @@ Google Play or CoolApk or [Releases](https://github.com/gedoor/legado/releases/latest) ## 阅读API -阅读3.0 提供了2种方式的API:`Web方式`和`Content Provider方式`。您可以在[这里](api.md)根据需要自行调用。 +* 阅读3.0 提供了2种方式的API:`Web方式`和`Content Provider方式`。您可以在[这里](api.md)根据需要自行调用。 +* 可通过url唤起阅读进行一键导入,url格式: legado://import/{path}?src={url} +* path类型: bookSource,rssSource,replaceRule,textTocRule,httpTTS,theme,readConfig +* path类型解释: 书源,订阅源,替换规则,本地txt小说目录规则,在线朗读引擎,主题,阅读排版 ## 感谢 ``` diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fea75c6a4..522dd2c43 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -319,16 +319,6 @@ - - - - - - - - - + + - - - - - - - - - + android:theme="@style/AppTheme.Transparent" /> - - - - - - - - - + android:theme="@style/AppTheme.Transparent" /> - - - - - - - - - + android:theme="@style/AppTheme.Transparent" /> if (newConfig.themeName == config.themeName) { configList[index] = newConfig diff --git a/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt index a1e1badca..f2c09bd88 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt @@ -8,8 +8,6 @@ import io.legado.app.constant.Theme import io.legado.app.databinding.ActivityTranslucenceBinding import io.legado.app.help.IntentDataHelp import io.legado.app.lib.dialogs.alert - -import io.legado.app.utils.toastOnUi import io.legado.app.utils.viewbindingdelegate.viewBinding @@ -49,18 +47,7 @@ class ImportBookSourceActivity : viewModel.importSource(it) return } - intent.data?.let { - when (it.path) { - "/importonline" -> it.getQueryParameter("src")?.let { url -> - viewModel.importSource(url) - } - else -> { - binding.rotateLoading.hide() - toastOnUi(R.string.wrong_format) - finish() - } - } - } ?: finish() + finish() } private fun errorDialog(msg: String) { diff --git a/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt index d01b49f26..a202a03e9 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt @@ -7,7 +7,6 @@ import io.legado.app.constant.Theme import io.legado.app.databinding.ActivityTranslucenceBinding import io.legado.app.help.IntentDataHelp import io.legado.app.lib.dialogs.alert -import io.legado.app.utils.toastOnUi import io.legado.app.utils.viewbindingdelegate.viewBinding class ImportReplaceRuleActivity : @@ -46,18 +45,7 @@ class ImportReplaceRuleActivity : viewModel.import(it) return } - intent.data?.let { - when (it.path) { - "/importonline" -> it.getQueryParameter("src")?.let { url -> - viewModel.import(url) - } - else -> { - binding.rotateLoading.hide() - toastOnUi("格式不对") - finish() - } - } - } ?: finish() + finish() } private fun errorDialog(msg: String) { diff --git a/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt index 7a2cfe9d9..a7a82a2cb 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt @@ -8,8 +8,6 @@ import io.legado.app.constant.Theme import io.legado.app.databinding.ActivityTranslucenceBinding import io.legado.app.help.IntentDataHelp import io.legado.app.lib.dialogs.alert - -import io.legado.app.utils.toastOnUi import io.legado.app.utils.viewbindingdelegate.viewBinding class ImportRssSourceActivity : @@ -48,18 +46,7 @@ class ImportRssSourceActivity : viewModel.importSource(it) return } - intent.data?.let { - when (it.path) { - "/importonline" -> it.getQueryParameter("src")?.let { url -> - viewModel.importSource(url) - } - else -> { - binding.rotateLoading.hide() - toastOnUi(R.string.wrong_format) - finish() - } - } - } ?: finish() + finish() } private fun errorDialog(msg: String) { diff --git a/app/src/main/java/io/legado/app/ui/association/OnLineImportActivity.kt b/app/src/main/java/io/legado/app/ui/association/OnLineImportActivity.kt index 45cc57de7..d24a1d635 100644 --- a/app/src/main/java/io/legado/app/ui/association/OnLineImportActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/OnLineImportActivity.kt @@ -3,15 +3,22 @@ package io.legado.app.ui.association import android.os.Bundle import androidx.activity.viewModels import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Theme import io.legado.app.databinding.ActivityTranslucenceBinding import io.legado.app.lib.dialogs.alert +import io.legado.app.utils.toastOnUi import io.legado.app.utils.viewbindingdelegate.viewBinding -class OnLineImportActivity : BaseActivity(theme = Theme.Transparent) { +/** + * 网络一键导入 + * 格式: legado://import/{path}?src={url} + */ +class OnLineImportActivity : + VMBaseActivity(theme = Theme.Transparent) { override val binding by viewBinding(ActivityTranslucenceBinding::inflate) + override val viewModel by viewModels() override fun onActivityCreated(savedInstanceState: Bundle?) { intent.data?.let { @@ -21,10 +28,21 @@ class OnLineImportActivity : BaseActivity(theme = T return } when (it.path) { - "bookSource" -> importBookSource(url) - "rssSource" -> importRssSource(url) - "replaceRule" -> importReplaceRule(url) - else -> { + "/bookSource" -> importBookSource(url) + "/rssSource" -> importRssSource(url) + "/replaceRule" -> importReplaceRule(url) + "/textTocRule" -> viewModel.importTextTocRule(url, this::finallyDialog) + "/httpTTS" -> viewModel.importHttpTTS(url, this::finallyDialog) + "/theme" -> viewModel.importTheme(url, this::finallyDialog) + "/readConfig" -> viewModel.importReadConfig(url, this::finallyDialog) + "/importonline" -> when (it.host) { + "booksource" -> importBookSource(url) + "rsssource" -> importRssSource(url) + "replace" -> importReplaceRule(url) + else -> { + toastOnUi("url error") + finish() + } } } } @@ -35,14 +53,14 @@ class OnLineImportActivity : BaseActivity(theme = T binding.rotateLoading.show() viewModel.errorLiveData.observe(this, { binding.rotateLoading.hide() - errorDialog(it) + finallyDialog(getString(R.string.error), it) }) viewModel.successLiveData.observe(this, { binding.rotateLoading.hide() if (it > 0) { ImportBookSourceDialog().show(supportFragmentManager, "bookSource") } else { - errorDialog(getString(R.string.wrong_format)) + finallyDialog(getString(R.string.error), getString(R.string.wrong_format)) } }) viewModel.importSource(url) @@ -53,14 +71,14 @@ class OnLineImportActivity : BaseActivity(theme = T binding.rotateLoading.show() viewModel.errorLiveData.observe(this, { binding.rotateLoading.hide() - errorDialog(it) + finallyDialog(getString(R.string.error), it) }) viewModel.successLiveData.observe(this, { binding.rotateLoading.hide() if (it > 0) { ImportRssSourceDialog().show(supportFragmentManager, "rssSource") } else { - errorDialog(getString(R.string.wrong_format)) + finallyDialog(getString(R.string.error), getString(R.string.wrong_format)) } }) viewModel.importSource(url) @@ -71,22 +89,22 @@ class OnLineImportActivity : BaseActivity(theme = T binding.rotateLoading.show() viewModel.errorLiveData.observe(this, { binding.rotateLoading.hide() - errorDialog(it) + finallyDialog(getString(R.string.error), it) }) viewModel.successLiveData.observe(this, { binding.rotateLoading.hide() if (it > 0) { ImportReplaceRuleDialog().show(supportFragmentManager, "replaceRule") } else { - errorDialog(getString(R.string.wrong_format)) + finallyDialog(getString(R.string.error), getString(R.string.wrong_format)) } }) viewModel.import(url) } - private fun errorDialog(msg: String) { - alert(getString(R.string.error), msg) { - okButton { } + private fun finallyDialog(title: String, msg: String) { + alert(title, msg) { + okButton() onDismiss { finish() } diff --git a/app/src/main/java/io/legado/app/ui/association/OnLineImportViewModel.kt b/app/src/main/java/io/legado/app/ui/association/OnLineImportViewModel.kt index 8dfba367e..2526d32b9 100644 --- a/app/src/main/java/io/legado/app/ui/association/OnLineImportViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/association/OnLineImportViewModel.kt @@ -1,6 +1,111 @@ package io.legado.app.ui.association import io.legado.app.App +import io.legado.app.R import io.legado.app.base.BaseViewModel +import io.legado.app.data.appDb +import io.legado.app.data.entities.HttpTTS +import io.legado.app.data.entities.TxtTocRule +import io.legado.app.help.ReadBookConfig +import io.legado.app.help.ThemeConfig +import io.legado.app.help.http.newCall +import io.legado.app.help.http.okHttpClient +import io.legado.app.help.http.text +import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonArray +import io.legado.app.utils.fromJsonObject +import io.legado.app.utils.isJsonArray -class OnLineImportViewModel(app: App) : BaseViewModel(app) \ No newline at end of file +class OnLineImportViewModel(app: App) : BaseViewModel(app) { + + fun importTextTocRule(url: String, finally: (title: String, msg: String) -> Unit) { + execute { + okHttpClient.newCall { + url(url) + }.text("utf-8").let { json -> + if (json.isJsonArray()) { + GSON.fromJsonArray(json)?.let { + appDb.txtTocRuleDao.insert(*it.toTypedArray()) + } ?: throw Exception("格式不对") + } else { + GSON.fromJsonObject(json)?.let { + appDb.txtTocRuleDao.insert(it) + } ?: throw Exception("格式不对") + } + } + }.onSuccess { + finally.invoke(context.getString(R.string.success), "导入Txt规则成功") + }.onError { + finally.invoke(context.getString(R.string.error), it.localizedMessage ?: "未知错误") + } + } + + fun importHttpTTS(url: String, finally: (title: String, msg: String) -> Unit) { + execute { + okHttpClient.newCall { + url(url) + }.text("utf-8").let { json -> + if (json.isJsonArray()) { + GSON.fromJsonArray(json)?.let { + appDb.httpTTSDao.insert(*it.toTypedArray()) + return@execute it.size + } ?: throw Exception("格式不对") + } else { + GSON.fromJsonObject(json)?.let { + appDb.httpTTSDao.insert(it) + return@execute 1 + } ?: throw Exception("格式不对") + } + } + }.onSuccess { + finally.invoke(context.getString(R.string.success), "导入${it}朗读引擎") + }.onError { + finally.invoke(context.getString(R.string.error), it.localizedMessage ?: "未知错误") + } + } + + fun importTheme(url: String, finally: (title: String, msg: String) -> Unit) { + execute { + okHttpClient.newCall { + url(url) + }.text("utf-8").let { json -> + if (json.isJsonArray()) { + GSON.fromJsonArray(json)?.forEach { + ThemeConfig.addConfig(it) + } ?: throw Exception("格式不对") + } else { + GSON.fromJsonObject(json)?.let { + ThemeConfig.addConfig(it) + } ?: throw Exception("格式不对") + } + } + }.onSuccess { + finally.invoke(context.getString(R.string.success), "导入主题成功") + }.onError { + finally.invoke(context.getString(R.string.error), it.localizedMessage ?: "未知错误") + } + } + + fun importReadConfig(url: String, finally: (title: String, msg: String) -> Unit) { + execute { + @Suppress("BlockingMethodInNonBlockingContext") + val bytes = okHttpClient.newCall { + url(url) + }.bytes() + val config = ReadBookConfig.import(bytes) + ReadBookConfig.configList.forEachIndexed { index, c -> + if (c.name == config.name) { + ReadBookConfig.configList[index] = config + return@execute config.name + } + ReadBookConfig.configList.add(config) + return@execute config.name + } + }.onSuccess { + finally.invoke(context.getString(R.string.success), "导入排版成功") + }.onError { + finally.invoke(context.getString(R.string.error), it.localizedMessage ?: "未知错误") + } + } + +} \ No newline at end of file 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 3837b6c22..5175f6610 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 @@ -308,6 +308,7 @@ class BgTextConfigDialog : BaseDialogFragment() { private fun importNetConfig(url: String) { execute { + @Suppress("BlockingMethodInNonBlockingContext") okHttpClient.newCall { url(url) }.bytes().let { @@ -318,9 +319,9 @@ class BgTextConfigDialog : BaseDialogFragment() { } } - @Suppress("BlockingMethodInNonBlockingContext") private fun importConfig(uri: Uri) { execute { + @Suppress("BlockingMethodInNonBlockingContext") importConfig(uri.readBytes(requireContext())!!) }.onError { it.printStackTrace() @@ -328,61 +329,13 @@ class BgTextConfigDialog : BaseDialogFragment() { } } - @Suppress("BlockingMethodInNonBlockingContext") + @Suppress("BlockingMethodInNonBlockingContext", "BlockingMethodInNonBlockingContext") private fun importConfig(byteArray: ByteArray) { execute { - val configZipPath = FileUtils.getPath(requireContext().externalCache, configFileName) - FileUtils.deleteFile(configZipPath) - val zipFile = FileUtils.createFileIfNotExist(configZipPath) - zipFile.writeBytes(byteArray) - val configDirPath = FileUtils.getPath(requireContext().externalCache, "readConfig") - FileUtils.deleteFile(configDirPath) - ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath)) - val configDir = FileUtils.createFolderIfNotExist(configDirPath) - val configFile = FileUtils.getFile(configDir, "readConfig.json") - val config: ReadBookConfig.Config = GSON.fromJsonObject(configFile.readText())!! - if (config.textFont.isNotEmpty()) { - val fontName = FileUtils.getName(config.textFont) - val fontPath = - FileUtils.getPath(requireContext().externalFiles, "font", fontName) - if (!FileUtils.exist(fontPath)) { - FileUtils.getFile(configDir, fontName).copyTo(File(fontPath)) - } - config.textFont = fontPath - } - if (config.bgType == 2) { - val bgName = FileUtils.getName(config.bgStr) - val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName) - if (!FileUtils.exist(bgPath)) { - val bgFile = FileUtils.getFile(configDir, bgName) - if (bgFile.exists()) { - bgFile.copyTo(File(bgPath)) - } - } - } - if (config.bgTypeNight == 2) { - val bgName = FileUtils.getName(config.bgStrNight) - val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName) - if (!FileUtils.exist(bgPath)) { - val bgFile = FileUtils.getFile(configDir, bgName) - if (bgFile.exists()) { - bgFile.copyTo(File(bgPath)) - } - } - } - if (config.bgTypeEInk == 2) { - val bgName = FileUtils.getName(config.bgStrEInk) - val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName) - if (!FileUtils.exist(bgPath)) { - val bgFile = FileUtils.getFile(configDir, bgName) - if (bgFile.exists()) { - bgFile.copyTo(File(bgPath)) - } - } - } - ReadBookConfig.durConfig = config - postEvent(EventBus.UP_CONFIG, true) + ReadBookConfig.import(byteArray) }.onSuccess { + ReadBookConfig.durConfig = it + postEvent(EventBus.UP_CONFIG, true) toastOnUi("导入成功") }.onError { it.printStackTrace() 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 73bfd6e24..ecadd4519 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 @@ -2,7 +2,6 @@ package io.legado.app.ui.rss.read import android.annotation.SuppressLint import android.app.DownloadManager -import android.content.Intent import android.content.pm.ActivityInfo import android.content.res.Configuration import android.net.Uri @@ -23,9 +22,7 @@ import io.legado.app.help.AppConfig import io.legado.app.lib.theme.DrawableUtils import io.legado.app.lib.theme.primaryTextColor import io.legado.app.service.help.Download -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.association.OnLineImportActivity import io.legado.app.ui.document.FilePicker import io.legado.app.ui.document.FilePickerParam import io.legado.app.utils.* @@ -332,41 +329,23 @@ class ReadRssActivity : VMBaseActivity } private fun shouldOverrideUrlLoading(url: Uri): Boolean { - if (url.scheme == "http" || url.scheme == "https") { - return false - } else if (url.scheme == "yuedu") { - when (url.host) { - "booksource" -> { - val intent = Intent( - this@ReadRssActivity, - ImportBookSourceActivity::class.java - ) - intent.data = url - startActivity(intent) - } - "rsssource" -> { - val intent = Intent( - this@ReadRssActivity, - ImportRssSourceActivity::class.java - ) - intent.data = url - startActivity(intent) + when (url.scheme) { + "http", "https" -> { + return false + } + "legado", "yuedu" -> { + startActivity { + data = url } - "replace" -> { - val intent = Intent( - this@ReadRssActivity, - ImportReplaceRuleActivity::class.java - ) - intent.data = url - startActivity(intent) + return true + } + else -> { + binding.root.longSnackbar("跳转其它应用", "确认") { + openUrl(url) } + return true } - return true - } - binding.root.longSnackbar("跳转其它应用", "确认") { - openUrl(url) } - return true } }