diff --git a/app/build.gradle b/app/build.gradle index cb11eee2f..01ca59663 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,6 +115,7 @@ dependencies { testImplementation 'junit:junit:4.13' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation "com.android.support:multidex:1.0.3" //kotlin implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 245e53bb0..d80cfd98d 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -3,6 +3,11 @@ * 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 新公众号[开源阅读]()已启用,[开源阅读软件]()备用 +**2020/07/21** +* 优化文字选择,不再缓存 +* 添加忽略恢复列表,方便不同手机配置不同 +* 其它一些bug修复 + **2020/07/19** * 添加自定义默认封面 * 修复封面选择本地图片时书架不显示的bug diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index bdf59ed54..eba95b8e9 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -1,6 +1,5 @@ package io.legado.app -import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context @@ -9,6 +8,7 @@ import android.graphics.Color import android.os.Build import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatDelegate +import androidx.multidex.MultiDexApplication import com.jeremyliao.liveeventbus.LiveEventBus import io.legado.app.constant.AppConst.channelIdDownload import io.legado.app.constant.AppConst.channelIdReadAloud @@ -28,7 +28,7 @@ import io.legado.app.utils.postEvent import io.legado.app.utils.putPrefInt @Suppress("DEPRECATION") -class App : Application() { +class App : MultiDexApplication() { companion object { @JvmStatic diff --git a/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt b/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt index 7e016521a..093d5fbed 100644 --- a/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt +++ b/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt @@ -3,6 +3,7 @@ package io.legado.app.base import android.os.Bundle import android.view.View import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager import io.legado.app.help.coroutine.Coroutine import io.legado.app.lib.theme.ThemeStore import kotlinx.coroutines.CoroutineScope @@ -10,6 +11,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlin.coroutines.CoroutineContext + abstract class BaseDialogFragment : DialogFragment(), CoroutineScope { override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main @@ -29,6 +31,17 @@ abstract class BaseDialogFragment : DialogFragment(), CoroutineScope { abstract fun onFragmentCreated(view: View, savedInstanceState: Bundle?) + override fun show(manager: FragmentManager, tag: String?) { + try { + //在每个add事务前增加一个remove事务,防止连续的add + manager.beginTransaction().remove(this).commit() + super.show(manager, tag) + } catch (e: Exception) { + //同一实例使用不同的tag会异常,这里捕获一下 + e.printStackTrace() + } + } + override fun onDestroy() { super.onDestroy() job.cancel() diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index 7e18a675b..729225d5f 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -25,6 +25,7 @@ object PreferKey { const val readBookFont = "readBookFont" const val fontFolder = "fontFolder" const val backupPath = "backupUri" + const val restoreIgnore = "restoreIgnore" const val threadCount = "threadCount" const val webPort = "webPort" const val keepLight = "keep_light" diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index fca1ef1fa..73e344393 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -19,8 +19,7 @@ import java.io.File @Keep object ReadBookConfig { const val readConfigFileName = "readConfig.json" - private val configFilePath = - App.INSTANCE.filesDir.absolutePath + File.separator + readConfigFileName + private val configFilePath = FileUtils.getPath(App.INSTANCE.filesDir, readConfigFileName) val configList: ArrayList = arrayListOf() private val defaultConfigs by lazy { val json = String(App.INSTANCE.assets.open(readConfigFileName).readBytes()) diff --git a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt index 7150284ff..e88702b32 100644 --- a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt @@ -1,7 +1,5 @@ package io.legado.app.help.http -import com.franmontiel.persistentcookiejar.PersistentCookieJar -import com.franmontiel.persistentcookiejar.cache.SetCookieCache import io.legado.app.constant.AppConst import io.legado.app.help.http.api.HttpGetApi import io.legado.app.utils.NetworkUtils @@ -19,8 +17,6 @@ object HttpHelper { val client: OkHttpClient by lazy { - val cookieJar = PersistentCookieJar(SetCookieCache(), CookieStore) - val specs = arrayListOf( ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, @@ -39,7 +35,6 @@ object HttpHelper { .followSslRedirects(true) .protocols(listOf(Protocol.HTTP_1_1)) .addInterceptor(getHeaderInterceptor()) - .cookieJar(cookieJar) builder.build() } diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 770e2e337..f3d56c214 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -9,6 +9,7 @@ import com.jayway.jsonpath.Option import com.jayway.jsonpath.ParseContext import io.legado.app.App import io.legado.app.BuildConfig +import io.legado.app.R import io.legado.app.constant.EventBus import io.legado.app.constant.PreferKey import io.legado.app.data.entities.* @@ -24,6 +25,42 @@ import org.jetbrains.anko.defaultSharedPreferences import java.io.File object Restore { + private val ignoreConfigPath = FileUtils.getPath(App.INSTANCE.filesDir, "restoreIgnore.json") + val ignoreConfig: HashMap by lazy { + val file = FileUtils.createFileIfNotExist(ignoreConfigPath) + val json = file.readText() + GSON.fromJsonObject>(json) ?: hashMapOf() + } + + //忽略key + val ignoreKeys = arrayOf( + "readConfig", + PreferKey.themeMode, + PreferKey.bookshelfLayout + ) + + //忽略标题 + val ignoreTitle = arrayOf( + App.INSTANCE.getString(R.string.read_config), + App.INSTANCE.getString(R.string.theme_mode), + App.INSTANCE.getString(R.string.bookshelf_layout) + ) + + //默认忽略keys + private val ignorePrefKeys = arrayOf( + PreferKey.versionCode, + PreferKey.defaultCover + ) + private val readPrefKeys = arrayOf( + PreferKey.readStyleSelect, + PreferKey.shareLayout, + PreferKey.pageAnim, + PreferKey.hideStatusBar, + PreferKey.hideNavigationBar, + PreferKey.bodyIndent, + PreferKey.autoReadSpeed + ) + val jsonPath: ParseContext by lazy { JsonPath.using( Configuration.builder() @@ -92,24 +129,25 @@ object Restore { suspend fun restoreConfig(path: String = Backup.backupPath) { withContext(IO) { - try { - val file = - FileUtils.createFileIfNotExist(path + File.separator + ReadBookConfig.readConfigFileName) - val configFile = - FileUtils.getFile(App.INSTANCE.filesDir, ReadBookConfig.readConfigFileName) - if (file.exists()) { - file.copyTo(configFile, true) - ReadBookConfig.upConfig() + if (!ignoreReadConfig) { + try { + val file = + FileUtils.createFileIfNotExist(path + File.separator + ReadBookConfig.readConfigFileName) + val configFile = + FileUtils.getFile(App.INSTANCE.filesDir, ReadBookConfig.readConfigFileName) + if (file.exists()) { + file.copyTo(configFile, true) + ReadBookConfig.upConfig() + } + } catch (e: Exception) { + e.printStackTrace() } - } catch (e: Exception) { - e.printStackTrace() } Preferences.getSharedPreferences(App.INSTANCE, path, "config")?.all ?.let { map -> - val ignoreKeys = arrayOf(PreferKey.versionCode, PreferKey.defaultCover) val edit = App.INSTANCE.defaultSharedPreferences.edit() map.forEach { - if (!ignoreKeys.contains(it.key)) { + if (keyIsNotIgnore(it.key)) { when (val value = it.value) { is Int -> edit.putInt(it.key, value) is Boolean -> edit.putBoolean(it.key, value) @@ -143,6 +181,28 @@ object Restore { } } + private fun keyIsNotIgnore(key: String): Boolean { + return when { + ignorePrefKeys.contains(key) -> false + readPrefKeys.contains(key) && ignoreReadConfig -> false + PreferKey.themeMode == key && ignoreThemeMode -> false + PreferKey.bookshelfLayout == key && ignoreBookshelfLayout -> false + else -> true + } + } + + private val ignoreReadConfig: Boolean + get() = ignoreConfig["readConfig"] == true + private val ignoreThemeMode: Boolean + get() = ignoreConfig[PreferKey.themeMode] == true + private val ignoreBookshelfLayout: Boolean + get() = ignoreConfig[PreferKey.bookshelfLayout] == true + + fun saveIgnoreConfig() { + val json = GSON.toJson(ignoreConfig) + FileUtils.createFileIfNotExist(ignoreConfigPath).writeText(json) + } + private inline fun fileToListT(path: String, fileName: String): List? { try { val file = FileUtils.createFileIfNotExist(path + File.separator + fileName) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt index ae477acd6..56aa3a2be 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt @@ -75,7 +75,16 @@ interface AlertBuilder { fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean) fun items(items: List, onItemSelected: (dialog: DialogInterface, index: Int) -> Unit) - fun items(items: List, onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit) + fun items( + items: List, + onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit + ) + + fun multiChoiceItems( + items: Array, + checkedItems: BooleanArray, + onClick: (dialog: DialogInterface, which: Int, isChecked: Boolean) -> Unit + ) fun build(): D fun show(): D diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt index 52711a17a..49d059b84 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt @@ -105,12 +105,25 @@ internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder items(items: List, onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit) { + override fun items( + items: List, + onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit + ) { builder.setItems(Array(items.size) { i -> items[i].toString() }) { dialog, which -> onItemSelected(dialog, items[which], which) } } + override fun multiChoiceItems( + items: Array, + checkedItems: BooleanArray, + onClick: (dialog: DialogInterface, which: Int, isChecked: Boolean) -> Unit + ) { + builder.setMultiChoiceItems(items, checkedItems) { dialog, which, isChecked -> + onClick(dialog, which, isChecked) + } + } + override fun build(): AlertDialog = builder.create() override fun show(): AlertDialog = builder.show() 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 9df96e3f2..e684ccfff 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 @@ -11,6 +11,8 @@ import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legado.app.R import io.legado.app.constant.PreferKey +import io.legado.app.help.storage.Restore +import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.filechooser.FileChooserDialog @@ -104,6 +106,7 @@ class BackupConfigFragment : PreferenceFragmentCompat(), override fun onPreferenceTreeClick(preference: Preference?): Boolean { when (preference?.key) { PreferKey.backupPath -> BackupRestoreUi.selectBackupFolder(this) + PreferKey.restoreIgnore -> restoreIgnore() "web_dav_backup" -> BackupRestoreUi.backup(this) "web_dav_restore" -> BackupRestoreUi.restore(this) "import_old" -> BackupRestoreUi.importOldData(this) @@ -111,6 +114,19 @@ class BackupConfigFragment : PreferenceFragmentCompat(), return super.onPreferenceTreeClick(preference) } + private fun restoreIgnore() { + val checkedItems = BooleanArray(Restore.ignoreKeys.size) { + Restore.ignoreConfig[Restore.ignoreKeys[it]] ?: false + } + alert(R.string.restore_ignore) { + multiChoiceItems(Restore.ignoreTitle, checkedItems) { _, which, isChecked -> + Restore.ignoreConfig[Restore.ignoreKeys[which]] = isChecked + } + }.show().setOnDismissListener { + Restore.saveIgnoreConfig() + } + } + override fun onFilePicked(requestCode: Int, currentPath: String) { BackupRestoreUi.onFilePicked(requestCode, currentPath) } diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index a417f4ca1..56b6e5715 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -64,6 +64,9 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), viewModel.upChapterList() }, 1000) } + view_pager_main.postDelayed({ + viewModel.postLoad() + }, 3000) } override fun onNavigationItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index b7392aaef..186f54a92 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -10,6 +10,7 @@ import io.legado.app.data.entities.RssSource import io.legado.app.help.http.HttpHelper import io.legado.app.help.storage.Restore import io.legado.app.model.WebBook +import io.legado.app.utils.FileUtils import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject import io.legado.app.utils.postEvent @@ -77,4 +78,14 @@ class MainViewModel(application: Application) : BaseViewModel(application) { } } } + + fun postLoad() { + execute { + FileUtils.getDirFile(context.cacheDir, "Fonts").let { + if (it.exists()) { + it.delete() + } + } + } + } } \ 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 cfd4f7d6d..1466f92f0 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 @@ -88,18 +88,18 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b R.id.menu_add_local -> startActivity() R.id.menu_add_url -> addBookByUrl() R.id.menu_arrange_bookshelf -> startActivity( - Pair("groupId", selectedGroup.groupId), - Pair("groupName", selectedGroup.groupName) + Pair("groupId", selectedGroup?.groupId ?: 0), + Pair("groupName", selectedGroup?.groupName ?: 0) ) R.id.menu_download -> startActivity( - Pair("groupId", selectedGroup.groupId), - Pair("groupName", selectedGroup.groupName) + Pair("groupId", selectedGroup?.groupId ?: 0), + Pair("groupName", selectedGroup?.groupName ?: 0) ) } } - private val selectedGroup: BookGroup - get() = bookGroups[view_pager_bookshelf.currentItem] + private val selectedGroup: BookGroup? + get() = bookGroups.getOrNull(view_pager_bookshelf?.currentItem ?: 0) private fun initView() { ATH.applyEdgeEffectColor(view_pager_bookshelf) @@ -267,7 +267,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } fun gotoTop() { - fragmentMap[selectedGroup.groupId]?.gotoTop() + fragmentMap[selectedGroup?.groupId]?.gotoTop() } private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt index ab6e34a1c..a54ee0182 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt @@ -2,9 +2,12 @@ package io.legado.app.ui.widget.font import android.content.Context import android.graphics.Typeface +import android.os.Build import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.utils.DocItem +import io.legado.app.utils.RealPathUtil import io.legado.app.utils.invisible import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_font.view.* @@ -13,15 +16,28 @@ import org.jetbrains.anko.toast import java.io.File class FontAdapter(context: Context, val callBack: CallBack) : - SimpleRecyclerAdapter(context, R.layout.item_font) { + SimpleRecyclerAdapter(context, R.layout.item_font) { - override fun convert(holder: ItemViewHolder, item: File, payloads: MutableList) { + override fun convert(holder: ItemViewHolder, item: DocItem, payloads: MutableList) { with(holder.itemView) { try { - val typeface = Typeface.createFromFile(item) + val typeface: Typeface? = if (item.isContentPath) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.contentResolver + .openFileDescriptor(item.uri, "r") + ?.fileDescriptor?.let { + Typeface.Builder(it).build() + } + } else { + Typeface.createFromFile(RealPathUtil.getPath(context, item.uri)) + } + } else { + Typeface.createFromFile(item.uri.toString()) + } tv_font.typeface = typeface } catch (e: Exception) { - context.toast("读取${item.name}字体失败") + e.printStackTrace() + context.toast("Read ${item.name} Error: ${e.localizedMessage}") } tv_font.text = item.name this.onClick { callBack.onClick(item) } @@ -42,7 +58,7 @@ class FontAdapter(context: Context, val callBack: CallBack) : } interface CallBack { - fun onClick(file: File) + fun onClick(docItem: DocItem) val curFilePath: String } } \ No newline at end of file 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 8157ed870..34e629e33 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 @@ -26,11 +26,11 @@ import io.legado.app.ui.filechooser.FileChooserDialog import io.legado.app.ui.filechooser.FilePicker import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_font_select.* -import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File +import java.util.* class FontSelectDialog : BaseDialogFragment(), FileChooserDialog.CallBack, @@ -40,9 +40,6 @@ class FontSelectDialog : BaseDialogFragment(), private val fontFolder by lazy { FileUtils.createFolderIfNotExist(App.INSTANCE.filesDir, "Fonts") } - private val fontCacheFolder by lazy { - FileUtils.createFolderIfNotExist(App.INSTANCE.cacheDir, "Fonts") - } private var adapter: FontAdapter? = null override fun onStart() { @@ -90,7 +87,9 @@ class FontSelectDialog : BaseDialogFragment(), R.id.menu_default -> { val requireContext = requireContext() requireContext.alert(titleResource = R.string.system_typeface) { - items(requireContext.resources.getStringArray(R.array.system_typefaces).toList()) { _, i -> + items( + requireContext.resources.getStringArray(R.array.system_typefaces).toList() + ) { _, i -> AppConfig.systemTypefaces = i onDefaultFontChange() dismiss() @@ -117,40 +116,16 @@ class FontSelectDialog : BaseDialogFragment(), @SuppressLint("DefaultLocale") private fun getFontFiles(doc: DocumentFile) { execute { + val fontItems = arrayListOf() val docItems = DocumentUtils.listFiles(App.INSTANCE, doc.uri) - fontCacheFolder.listFiles()?.forEach { fontFile -> - var contain = false - for (item in docItems) { - if (fontFile.name == item.name) { - contain = true - break - } - } - if (!contain) { - fontFile.delete() - } - } docItems.forEach { item -> if (item.name.toLowerCase().matches(".*\\.[ot]tf".toRegex())) { - val fontFile = FileUtils.getFile(fontCacheFolder, item.name) - if (!fontFile.exists()) { - DocumentUtils.readBytes(App.INSTANCE, item.uri)?.let { byteArray -> - fontFile.writeBytes(byteArray) - } - } - } - } - try { - fontCacheFolder.listFiles { pathName -> - pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) - }?.let { - withContext(Main) { - adapter?.setItems(it.toList()) - } + fontItems.add(item) } - } catch (e: Exception) { - toast(e.localizedMessage ?: "") } + fontItems + }.onSuccess { + adapter?.setItems(it) }.onError { toast("getFontFiles:${it.localizedMessage}") } @@ -163,12 +138,22 @@ class FontSelectDialog : BaseDialogFragment(), .rationale(R.string.tip_perm_request_storage) .onGranted { try { + val fontItems = arrayListOf() val file = File(path) file.listFiles { pathName -> pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) - }?.let { - adapter?.setItems(it.toList()) + }?.forEach { + fontItems.add( + DocItem( + it.name, + it.extension, + it.length(), + Date(it.lastModified()), + Uri.parse(it.absolutePath) + ) + ) } + adapter?.setItems(fontItems) } catch (e: Exception) { toast(e.localizedMessage ?: "") } @@ -176,16 +161,32 @@ class FontSelectDialog : BaseDialogFragment(), .request() } - override fun onClick(file: File) { - launch(IO) { - file.copyTo(FileUtils.createFileIfNotExist(fontFolder, file.name), true) - .absolutePath.let { path -> - if (curFilePath != path) { - withContext(Main) { - callBack?.selectFile(path) + override fun onClick(docItem: DocItem) { + execute { + fontFolder.listFiles()?.forEach { + it.delete() + } + if (docItem.isContentPath) { + val file = FileUtils.createFileIfNotExist(fontFolder, docItem.name) + @Suppress("BlockingMethodInNonBlockingContext") + requireActivity().contentResolver.openInputStream(docItem.uri)?.use { input -> + file.outputStream().use { output -> + input.copyTo(output) } } + callBack?.selectFile(file.path) + } else { + val file = File(docItem.uri.toString()) + file.copyTo(FileUtils.createFileIfNotExist(fontFolder, file.name), true) + .absolutePath.let { path -> + if (curFilePath != path) { + withContext(Main) { + callBack?.selectFile(path) + } + } + } } + }.onSuccess { dialog?.dismiss() } } diff --git a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt index b53cebb14..041189c7f 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt @@ -138,6 +138,8 @@ data class DocItem( val isDir: Boolean by lazy { DocumentsContract.Document.MIME_TYPE_DIR == attr } + + val isContentPath get() = uri.toString().isContentPath() } @Throws(Exception::class) diff --git a/app/src/main/java/io/legado/app/utils/FileUtils.kt b/app/src/main/java/io/legado/app/utils/FileUtils.kt index a9408dd10..d82f6bca0 100644 --- a/app/src/main/java/io/legado/app/utils/FileUtils.kt +++ b/app/src/main/java/io/legado/app/utils/FileUtils.kt @@ -18,7 +18,7 @@ object FileUtils { } fun createFolderIfNotExist(root: File, vararg subDirs: String): File { - val filePath = root.absolutePath + File.separator + subDirs.joinToString(File.separator) + val filePath = getPath(root, subDirs = *subDirs) return createFolderIfNotExist(filePath) } @@ -60,11 +60,14 @@ object FileUtils { } fun getPath(root: File, fileName: String? = null, vararg subDirs: String): String { - return if (fileName.isNullOrEmpty()) { - root.absolutePath + File.separator + subDirs.joinToString(File.separator) - } else { - root.absolutePath + File.separator + subDirs.joinToString(File.separator) + File.separator + fileName + val path = StringBuilder(root.absolutePath) + subDirs.forEach { + path.append(File.separator).append(it) + } + if (!fileName.isNullOrEmpty()) { + path.append(File.separator).append(fileName) } + return path.toString() } //递归删除文件夹下的数据 diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index 6da5a6cc6..7443c0244 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -1,7 +1,8 @@ package io.legado.app.utils -val removeHtmlRegex = - "]*>".toRegex() +val removeHtmlRegex = "]*>".toRegex() +val imgRegex = "]*>".toRegex() +val notImgHtmlRegex = "]*>".toRegex() fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim() @@ -37,7 +38,10 @@ fun String?.isJsonArray(): Boolean = fun String?.htmlFormat(): String { this ?: return "" - return this.replace(removeHtmlRegex, "\n") + return this + .replace(imgRegex, "\n$0\n") + .replace(removeHtmlRegex, "\n") + .replace(notImgHtmlRegex, "") .replace("\\s*\\n+\\s*".toRegex(), "\n  ") .replace("^[\\n\\s]+".toRegex(), "  ") .replace("[\\n\\s]+$".toRegex(), "") diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index 3754c0914..4fdba8675 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -222,7 +222,7 @@ @@ -257,7 +258,7 @@ @@ -292,7 +294,7 @@ @@ -327,7 +330,7 @@ diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 6d5d0a942..20529810b 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -721,4 +721,7 @@ gedoor,Invinciblelee等,详情请在github中查看 清除已下载书籍和字体缓存 默认封面 + 恢复忽略列表 + 恢复时忽略一些内容不恢复,方便不同手机配置不同 + 阅读界面设置 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 35dec6a8e..89cdbf2a5 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -721,5 +721,8 @@ gedoor,Invinciblelee等,详情请在github中查看 清除已下载书籍和字体缓存 默认封面 + 恢复忽略列表 + 恢复时忽略一些内容不恢复,方便不同手机配置不同 + 阅读界面设置 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 67df126cf..f44eaa67f 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -721,4 +721,7 @@ gedoor,Invinciblelee等,详情请在github中查看 清除已下载书籍和字体缓存 默认封面 + 恢复忽略列表 + 恢复时忽略一些内容不恢复,方便不同手机配置不同 + 阅读界面设置 diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index d184e497a..f9abf310a 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -42,9 +42,9 @@ Follow system - Bright theme - Dark theme - E-Ink + Bright mode + Dark mode + E-Ink mode diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 19eba0abd..62b552f92 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -218,7 +218,7 @@ Import selected book(s) Number of concurrent tasks Change icon - Remove books + Remove Start reading Loading… Load failed, tap to retry @@ -332,7 +332,7 @@ Margin adjustment Allow update Disable update - Invert selection + Inverse Search bookName/author BookName,Author,URL FAQ @@ -586,8 +586,8 @@ I AM OVER! Uri To Path failed Refresh cover - Change cover\'s origin - Select a local image + Change origin + Local image Type: Text Audio @@ -652,7 +652,7 @@ Save image No default path Group settings - View changes + View Chapters Navigation bar shadow Current shadow size(elevation): %s Default @@ -697,13 +697,13 @@ Night,Accent Night,Background color Night,NavBar color - Changing source automatically + Change source automatically Text justified Text align bottom Auto scroll speed Sort by URL - The local backup and WebDav backup at the same time - Restore from WebDAV first, and Restore form local backups if failed + Backup the local and WebDav simultaneously + Restore from WebDAV first, and Restore form the local backup if failed Select a legacy backup folder Enabled Disabled @@ -711,16 +711,19 @@ Starting download This book is already in Download list click to open - 关注[开源阅读]点击广告支持我 - 微信赞赏码 - 支付宝 - 支付宝红包搜索码 - 537954522 点击复制 - 支付宝红包二维码 - 支付宝收款二维码 - QQ收款二维码 - gedoor,Invinciblelee等,详情请在github中查看 - 清除已下载书籍和字体缓存 - 默认封面 + Follow [开源阅读] to support me by clicking on ads + WeChat Tipping Code + AliPay + AliPay red envelope search code + 537954522 Click to copy + AliPay red envelope QR code + AliPay QR code + QQ Collection QR code + gedoor,Invinciblelee etc. Checking in github for details + Clear the cache of the downloaded books and fonts + Default cover + 恢复忽略列表 + 恢复时忽略一些内容不恢复,方便不同手机配置不同 + 阅读界面设置 \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config_backup.xml b/app/src/main/res/xml/pref_config_backup.xml index 784089b69..b16c6f32b 100644 --- a/app/src/main/res/xml/pref_config_backup.xml +++ b/app/src/main/res/xml/pref_config_backup.xml @@ -39,6 +39,7 @@ @@ -61,6 +62,12 @@ android:summary="@string/restore_summary" app:iconSpaceReserved="false" /> + +