feat(Cache/Export): ✨ 新增 开启自定义导出 菜单与对话框

This commit is contained in:
Discut
2023-05-22 21:00:37 +08:00
parent cfe9701c26
commit d95376448d
8 changed files with 268 additions and 0 deletions
@@ -54,6 +54,7 @@ object PreferKey {
const val webDavAccount = "web_dav_account" const val webDavAccount = "web_dav_account"
const val webDavPassword = "web_dav_password" const val webDavPassword = "web_dav_password"
const val webDavDir = "webDavDir" const val webDavDir = "webDavDir"
const val enableCustomExport = "enableCustomExport"
const val exportToWebDav = "webDavCacheBackup" const val exportToWebDav = "webDavCacheBackup"
const val exportNoChapterName = "exportNoChapterName" const val exportNoChapterName = "exportNoChapterName"
const val exportType = "exportType" const val exportType = "exportType"
@@ -268,6 +268,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
set(value) { set(value) {
appCtx.putPrefBoolean(PreferKey.exportNoChapterName, value) appCtx.putPrefBoolean(PreferKey.exportNoChapterName, value)
} }
var enableCustomExport: Boolean
get() = appCtx.getPrefBoolean(PreferKey.enableCustomExport)
set(value) {
appCtx.putPrefBoolean(PreferKey.enableCustomExport, value)
}
var exportType: Int var exportType: Int
get() = appCtx.getPrefInt(PreferKey.exportType) get() = appCtx.getPrefInt(PreferKey.exportType)
set(value) { set(value) {
@@ -4,7 +4,9 @@ import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
@@ -17,6 +19,7 @@ import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookGroup import io.legado.app.data.entities.BookGroup
import io.legado.app.databinding.ActivityCacheBookBinding import io.legado.app.databinding.ActivityCacheBookBinding
import io.legado.app.databinding.DialogEditTextBinding import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.databinding.DialogSelectSectionExportBinding
import io.legado.app.help.book.isAudio import io.legado.app.help.book.isAudio
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.lib.dialogs.SelectItem import io.legado.app.lib.dialogs.SelectItem
@@ -32,7 +35,11 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import androidx.core.widget.doOnTextChanged
/**
* cache/download 缓存界面
*/
class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>(), class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>(),
CacheAdapter.CallBack { CacheAdapter.CallBack {
@@ -88,6 +95,8 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
override fun onMenuOpened(featureId: Int, menu: Menu): Boolean { override fun onMenuOpened(featureId: Int, menu: Menu): Boolean {
menu.findItem(R.id.menu_enable_replace)?.isChecked = AppConfig.exportUseReplace menu.findItem(R.id.menu_enable_replace)?.isChecked = AppConfig.exportUseReplace
// 菜单打开时读取状态[enableCustomExport]
menu.findItem(R.id.menu_enable_custom_export)?.isChecked = AppConfig.enableCustomExport
menu.findItem(R.id.menu_export_no_chapter_name)?.isChecked = AppConfig.exportNoChapterName menu.findItem(R.id.menu_export_no_chapter_name)?.isChecked = AppConfig.exportNoChapterName
menu.findItem(R.id.menu_export_web_dav)?.isChecked = AppConfig.exportToWebDav menu.findItem(R.id.menu_export_web_dav)?.isChecked = AppConfig.exportToWebDav
menu.findItem(R.id.menu_export_pics_file)?.isChecked = AppConfig.exportPictureFile menu.findItem(R.id.menu_export_pics_file)?.isChecked = AppConfig.exportPictureFile
@@ -108,6 +117,9 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
} }
} }
/**
* 菜单按下回调
*/
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_download -> { R.id.menu_download -> {
@@ -126,6 +138,8 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
} }
R.id.menu_export_all -> exportAll() R.id.menu_export_all -> exportAll()
R.id.menu_enable_replace -> AppConfig.exportUseReplace = !item.isChecked R.id.menu_enable_replace -> AppConfig.exportUseReplace = !item.isChecked
// 更改菜单状态[enableCustomExport]
R.id.menu_enable_custom_export -> AppConfig.enableCustomExport = !item.isChecked
R.id.menu_export_no_chapter_name -> AppConfig.exportNoChapterName = !item.isChecked R.id.menu_export_no_chapter_name -> AppConfig.exportNoChapterName = !item.isChecked
R.id.menu_export_web_dav -> AppConfig.exportToWebDav = !item.isChecked R.id.menu_export_web_dav -> AppConfig.exportToWebDav = !item.isChecked
R.id.menu_export_pics_file -> AppConfig.exportPictureFile = !item.isChecked R.id.menu_export_pics_file -> AppConfig.exportPictureFile = !item.isChecked
@@ -233,6 +247,8 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
val path = ACache.get().getAsString(exportBookPathKey) val path = ACache.get().getAsString(exportBookPathKey)
if (path.isNullOrEmpty()) { if (path.isNullOrEmpty()) {
selectExportFolder(position) selectExportFolder(position)
} else if (AppConfig.enableCustomExport) {// 启用自定义导出
configExportSection(path, position);
} else { } else {
startExport(path, position) startExport(path, position)
} }
@@ -247,6 +263,102 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
} }
} }
/**
* 配置自定义导出对话框
*
* @param path 导出路径
* @param position book位置
* @author Discut
* @since 1.0.0
*/
private fun configExportSection(path: String, position: Int) {
if (AppConfig.enableCustomExport) {
val alertBinding = DialogSelectSectionExportBinding.inflate(layoutInflater)
.apply {
cbAllExport.isChecked = true
cbSelectExport.isChecked = false
etEpubSize.isEnabled = false
etInputScope.isEnabled = false
tvAllExport.setOnClickListener {
cbAllExport.isChecked = true
}
tvSelectExport.setOnClickListener {
cbSelectExport.isChecked = true
}
cbSelectExport.onCheckedChangeListener = { _, isChecked ->
if (isChecked) {
etEpubSize.isEnabled = true
etInputScope.isEnabled = true
cbAllExport.isChecked = false
}
}
cbAllExport.onCheckedChangeListener = { _, isChecked ->
if (isChecked) {
etEpubSize.isEnabled = false
etInputScope.isEnabled = false
cbSelectExport.isChecked = false
}
}
etInputScope.onFocusChangeListener =
View.OnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
etInputScope.hint = "例如:1-5,8,10-18"
} else {
etInputScope.hint = ""
}
}
etInputScope.doOnTextChanged { text, start, before, count ->
var a: Int = 1
a = 2
}
}
val alertDialog = alert(titleResource = R.string.select_section_export) {
customView { alertBinding.root }
positiveButton("确认")
//okButton {
// alertBinding.apply {
// it.dismiss()
// if (cbAllExport.isChecked) {
// // export all sections of the book.
// startExport(path, position)
// } else if (cbSelectExport.isChecked) {
//
// }
// }
//}
cancelButton()
}
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
alertBinding.apply {
val text = etInputScope.text
if (!verificationField(text.toString())) {
etInputScope.error = "请输入正确的范围"
} else {
etInputScope.error = null
val toInt = etEpubSize.text.toString().toInt()
startExport(path, position, toInt, text.toString())
}
}
}
}
}
/**
* 验证 输入的范围 是否正确
*
* @since 1.0.0
* @author Discut
* @param text 输入的范围 字符串
* @return 是否正确
*/
private fun verificationField(text: String): Boolean {
return text.matches(Regex("\\d+(-\\d+)?(,\\d+(-\\d+)?)*"))
}
private fun selectExportFolder(exportPosition: Int) { private fun selectExportFolder(exportPosition: Int) {
val default = arrayListOf<SelectItem<Int>>() val default = arrayListOf<SelectItem<Int>>()
val path = ACache.get().getAsString(exportBookPathKey) val path = ACache.get().getAsString(exportBookPathKey)
@@ -259,6 +371,18 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
} }
} }
private fun startExport(path: String, exportPosition: Int, size: Int, scope: String) {
if (exportPosition >= 0) {
adapter.getItem(exportPosition)?.let { book ->
when (AppConfig.exportType) {
1 -> viewModel.exportEPUB(path, book, size, scope)
// 目前仅支持 epub
//else -> viewModel.export(path, book)
}
}
}
}
private fun startExport(path: String, exportPosition: Int) { private fun startExport(path: String, exportPosition: Int) {
if (exportPosition == -10) { if (exportPosition == -10) {
if (adapter.getItems().isNotEmpty()) { if (adapter.getItems().isNotEmpty()) {
@@ -0,0 +1,16 @@
package io.legado.app.ui.book.cache
import android.os.Bundle
import android.view.View
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.databinding.DialogSelectSectionExportBinding
import io.legado.app.utils.viewbindingdelegate.viewBinding
class CustomExportSectionDialog() : BaseDialogFragment(R.layout.dialog_select_section_export) {
private val binding by viewBinding(DialogSelectSectionExportBinding::bind)
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
TODO("Not yet implemented")
}
}
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- <androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="ifContentScrolls"
android:paddingTop="6dp">-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal">
<io.legado.app.ui.widget.checkbox.SmoothCheckBox
android:id="@+id/cb_all_export"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="16dp" />
<TextView
android:id="@+id/tv_all_export"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全部导出"
android:textSize="18sp" />
</LinearLayout>
<!-- <com.google.android.material.divider.MaterialDivider-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content" />-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal">
<io.legado.app.ui.widget.checkbox.SmoothCheckBox
android:id="@+id/cb_select_export"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="16dp" />
<TextView
android:id="@+id/tv_select_export"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择导出"
android:textSize="18sp" />
</LinearLayout>
<io.legado.app.ui.widget.text.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:hint="每个文件包含章节大小">
<io.legado.app.lib.theme.view.ThemeEditText
android:id="@+id/et_epub_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:text="1"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout>
<io.legado.app.ui.widget.text.TextInputLayout
android:id="@+id/ly_et_input_scope"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输出章节序号">
<io.legado.app.lib.theme.view.ThemeEditText
android:id="@+id/et_input_scope"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout>
</LinearLayout>
<!-- </androidx.core.widget.NestedScrollView>-->
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
+7
View File
@@ -31,6 +31,13 @@
android:checkable="true" android:checkable="true"
app:showAsAction="never" /> app:showAsAction="never" />
<!--自定义导出章节 选择菜单-->
<item
android:id="@+id/menu_enable_custom_export"
android:title="@string/custom_export_section"
android:checkable="true"
app:showAsAction="never" />
<item <item
android:id="@+id/menu_export_web_dav" android:id="@+id/menu_export_web_dav"
android:title="@string/export_to_web_dav" android:title="@string/export_to_web_dav"
+2
View File
@@ -31,6 +31,7 @@
<string name="delete_all">删除所有</string> <string name="delete_all">删除所有</string>
<string name="replace">替换</string> <string name="replace">替换</string>
<string name="replace_purify">替换净化</string> <string name="replace_purify">替换净化</string>
<string name="custom_export_section">自定义导出章节</string>
<string name="replace_purify_desc">配置替换净化规则</string> <string name="replace_purify_desc">配置替换净化规则</string>
<string name="not_available">暂无</string> <string name="not_available">暂无</string>
<string name="enable">启用</string> <string name="enable">启用</string>
@@ -346,6 +347,7 @@
<string name="ps_show_all_find">关闭则只显示勾选源的发现</string> <string name="ps_show_all_find">关闭则只显示勾选源的发现</string>
<string name="update_toc">更新目录</string> <string name="update_toc">更新目录</string>
<string name="txt_toc_rule">TXT 目录规则</string> <string name="txt_toc_rule">TXT 目录规则</string>
<string name="select_section_export">选择待导出章节</string>
<string name="set_charset">设置编码</string> <string name="set_charset">设置编码</string>
<string name="swap_sort">倒序-顺序</string> <string name="swap_sort">倒序-顺序</string>
<string name="sort">排序</string> <string name="sort">排序</string>
+2
View File
@@ -30,6 +30,7 @@
<string name="edit">Edit</string> <string name="edit">Edit</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="delete_all">Delete all</string> <string name="delete_all">Delete all</string>
<string name="custom_export_section">Custom export chapter</string>
<string name="replace">Replace</string> <string name="replace">Replace</string>
<string name="replace_purify">Replacement</string> <string name="replace_purify">Replacement</string>
<string name="replace_purify_desc">Configure replacement rules</string> <string name="replace_purify_desc">Configure replacement rules</string>
@@ -347,6 +348,7 @@
<string name="ps_show_all_find">Display the selected origin\'s Discovery if closed</string> <string name="ps_show_all_find">Display the selected origin\'s Discovery if closed</string>
<string name="update_toc">Update chapters</string> <string name="update_toc">Update chapters</string>
<string name="txt_toc_rule">Txt Chapters Rule</string> <string name="txt_toc_rule">Txt Chapters Rule</string>
<string name="select_section_export">Choose some chapters to be exported</string>
<string name="set_charset">Text encoding</string> <string name="set_charset">Text encoding</string>
<string name="swap_sort">Ascending/Descending order</string> <string name="swap_sort">Ascending/Descending order</string>
<string name="sort">Sort</string> <string name="sort">Sort</string>