Merge branch 'master' into master

pull/276/head
kunfei 4 years ago committed by GitHub
commit 7485224a4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      app/src/main/assets/updateLog.md
  2. 6
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  3. 7
      app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt
  4. 3
      app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
  5. 3
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  6. 11
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  7. 26
      app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt
  8. 87
      app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt
  9. 2
      app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt
  10. 2
      app/src/main/java/io/legado/app/utils/DocumentUtils.kt
  11. 10
      app/src/main/java/io/legado/app/utils/StringExtensions.kt
  12. 2
      app/src/main/res/values-zh-rHK/strings.xml
  13. 2
      app/src/main/res/values-zh-rTW/strings.xml
  14. 2
      app/src/main/res/values-zh/strings.xml
  15. 2
      app/src/main/res/values/strings.xml
  16. 7
      app/src/main/res/xml/pref_config_backup.xml

@ -3,6 +3,9 @@
* 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
* 新公众号[开源阅读]()已启用,[开源阅读软件]()备用 * 新公众号[开源阅读]()已启用,[开源阅读软件]()备用
**2020/07/20**
* 优化文字选择,不再缓存
**2020/07/19** **2020/07/19**
* 添加自定义默认封面 * 添加自定义默认封面
* 修复封面选择本地图片时书架不显示的bug * 修复封面选择本地图片时书架不显示的bug

@ -52,4 +52,10 @@ interface JsExtensions {
fun timeFormat(time: Long): String { fun timeFormat(time: Long): String {
return dateFormat.format(Date(time)) return dateFormat.format(Date(time))
} }
//utf8编码转gbk编码
fun utf8ToGbk(str: String): String {
val utf8 = String(str.toByteArray(charset("UTF-8")))
val unicode = String(utf8.toByteArray(), charset("UTF-8"))
return String(unicode.toByteArray(charset("GBK")))
}
} }

@ -27,6 +27,7 @@ import io.legado.app.service.AudioPlayService
import io.legado.app.service.help.AudioPlay import io.legado.app.service.help.AudioPlay
import io.legado.app.ui.book.changesource.ChangeSourceDialog import io.legado.app.ui.book.changesource.ChangeSourceDialog
import io.legado.app.ui.book.chapterlist.ChapterListActivity import io.legado.app.ui.book.chapterlist.ChapterListActivity
import io.legado.app.ui.widget.image.CoverImageView
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.activity_audio_play.* import kotlinx.android.synthetic.main.activity_audio_play.*
import org.apache.commons.lang3.time.DateFormatUtils import org.apache.commons.lang3.time.DateFormatUtils
@ -117,8 +118,8 @@ class AudioPlayActivity :
private fun upCover(path: String?) { private fun upCover(path: String?) {
ImageLoader.load(this, path) ImageLoader.load(this, path)
.placeholder(R.drawable.image_cover_default) .placeholder(CoverImageView.defaultDrawable)
.error(R.drawable.image_cover_default) .error(CoverImageView.defaultDrawable)
.into(iv_cover) .into(iv_cover)
ImageLoader.load(this, path) ImageLoader.load(this, path)
.transition(DrawableTransitionOptions.withCrossFade(1500)) .transition(DrawableTransitionOptions.withCrossFade(1500))
@ -128,7 +129,7 @@ class AudioPlayActivity :
} }
private fun defaultCover(): RequestBuilder<Drawable> { private fun defaultCover(): RequestBuilder<Drawable> {
return ImageLoader.load(this, R.drawable.image_cover_default) return ImageLoader.load(this, CoverImageView.defaultDrawable)
.apply(bitmapTransform(BlurTransformation(this, 25))) .apply(bitmapTransform(BlurTransformation(this, 25)))
} }

@ -32,6 +32,7 @@ import io.legado.app.ui.book.info.edit.BookInfoEditActivity
import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.book.source.edit.BookSourceEditActivity
import io.legado.app.ui.widget.image.CoverImageView
import io.legado.app.utils.dp import io.legado.app.utils.dp
import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModel
import io.legado.app.utils.gone import io.legado.app.utils.gone
@ -141,7 +142,7 @@ class BookInfoActivity :
} }
private fun defaultCover(): RequestBuilder<Drawable> { private fun defaultCover(): RequestBuilder<Drawable> {
return ImageLoader.load(this, R.drawable.image_cover_default) return ImageLoader.load(this, CoverImageView.defaultDrawable)
.apply(bitmapTransform(BlurTransformation(this, 25))) .apply(bitmapTransform(BlurTransformation(this, 25)))
} }

@ -64,6 +64,9 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
viewModel.upChapterList() viewModel.upChapterList()
}, 1000) }, 1000)
} }
view_pager_main.postDelayed({
viewModel.postLoad()
}, 3000)
} }
override fun onNavigationItemSelected(item: MenuItem): Boolean { override fun onNavigationItemSelected(item: MenuItem): Boolean {

@ -10,6 +10,7 @@ import io.legado.app.data.entities.RssSource
import io.legado.app.help.http.HttpHelper import io.legado.app.help.http.HttpHelper
import io.legado.app.help.storage.Restore import io.legado.app.help.storage.Restore
import io.legado.app.model.WebBook import io.legado.app.model.WebBook
import io.legado.app.utils.FileUtils
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.postEvent 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()
}
}
}
}
} }

@ -2,9 +2,12 @@ package io.legado.app.ui.widget.font
import android.content.Context import android.content.Context
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Build
import io.legado.app.R 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.utils.DocItem
import io.legado.app.utils.RealPathUtil
import io.legado.app.utils.invisible import io.legado.app.utils.invisible
import io.legado.app.utils.visible import io.legado.app.utils.visible
import kotlinx.android.synthetic.main.item_font.view.* import kotlinx.android.synthetic.main.item_font.view.*
@ -13,15 +16,28 @@ import org.jetbrains.anko.toast
import java.io.File import java.io.File
class FontAdapter(context: Context, val callBack: CallBack) : class FontAdapter(context: Context, val callBack: CallBack) :
SimpleRecyclerAdapter<File>(context, R.layout.item_font) { SimpleRecyclerAdapter<DocItem>(context, R.layout.item_font) {
override fun convert(holder: ItemViewHolder, item: File, payloads: MutableList<Any>) { override fun convert(holder: ItemViewHolder, item: DocItem, payloads: MutableList<Any>) {
with(holder.itemView) { with(holder.itemView) {
try { 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 tv_font.typeface = typeface
} catch (e: Exception) { } catch (e: Exception) {
context.toast("读取${item.name}字体失败") e.printStackTrace()
context.toast("Read ${item.name} Error: ${e.localizedMessage}")
} }
tv_font.text = item.name tv_font.text = item.name
this.onClick { callBack.onClick(item) } this.onClick { callBack.onClick(item) }
@ -42,7 +58,7 @@ class FontAdapter(context: Context, val callBack: CallBack) :
} }
interface CallBack { interface CallBack {
fun onClick(file: File) fun onClick(docItem: DocItem)
val curFilePath: String val curFilePath: String
} }
} }

@ -26,11 +26,11 @@ import io.legado.app.ui.filechooser.FileChooserDialog
import io.legado.app.ui.filechooser.FilePicker import io.legado.app.ui.filechooser.FilePicker
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.dialog_font_select.* import kotlinx.android.synthetic.main.dialog_font_select.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.util.*
class FontSelectDialog : BaseDialogFragment(), class FontSelectDialog : BaseDialogFragment(),
FileChooserDialog.CallBack, FileChooserDialog.CallBack,
@ -40,9 +40,6 @@ class FontSelectDialog : BaseDialogFragment(),
private val fontFolder by lazy { private val fontFolder by lazy {
FileUtils.createFolderIfNotExist(App.INSTANCE.filesDir, "Fonts") FileUtils.createFolderIfNotExist(App.INSTANCE.filesDir, "Fonts")
} }
private val fontCacheFolder by lazy {
FileUtils.createFolderIfNotExist(App.INSTANCE.cacheDir, "Fonts")
}
private var adapter: FontAdapter? = null private var adapter: FontAdapter? = null
override fun onStart() { override fun onStart() {
@ -90,7 +87,9 @@ class FontSelectDialog : BaseDialogFragment(),
R.id.menu_default -> { R.id.menu_default -> {
val requireContext = requireContext() val requireContext = requireContext()
requireContext.alert(titleResource = R.string.system_typeface) { 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 AppConfig.systemTypefaces = i
onDefaultFontChange() onDefaultFontChange()
dismiss() dismiss()
@ -117,40 +116,16 @@ class FontSelectDialog : BaseDialogFragment(),
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
private fun getFontFiles(doc: DocumentFile) { private fun getFontFiles(doc: DocumentFile) {
execute { execute {
val fontItems = arrayListOf<DocItem>()
val docItems = DocumentUtils.listFiles(App.INSTANCE, doc.uri) 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 -> docItems.forEach { item ->
if (item.name.toLowerCase().matches(".*\\.[ot]tf".toRegex())) { if (item.name.toLowerCase().matches(".*\\.[ot]tf".toRegex())) {
val fontFile = FileUtils.getFile(fontCacheFolder, item.name) fontItems.add(item)
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())
}
} }
} catch (e: Exception) {
toast(e.localizedMessage ?: "")
} }
fontItems
}.onSuccess {
adapter?.setItems(it)
}.onError { }.onError {
toast("getFontFiles:${it.localizedMessage}") toast("getFontFiles:${it.localizedMessage}")
} }
@ -163,12 +138,22 @@ class FontSelectDialog : BaseDialogFragment(),
.rationale(R.string.tip_perm_request_storage) .rationale(R.string.tip_perm_request_storage)
.onGranted { .onGranted {
try { try {
val fontItems = arrayListOf<DocItem>()
val file = File(path) val file = File(path)
file.listFiles { pathName -> file.listFiles { pathName ->
pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex())
}?.let { }?.forEach {
adapter?.setItems(it.toList()) fontItems.add(
DocItem(
it.name,
it.extension,
it.length(),
Date(it.lastModified()),
Uri.parse(it.absolutePath)
)
)
} }
adapter?.setItems(fontItems)
} catch (e: Exception) { } catch (e: Exception) {
toast(e.localizedMessage ?: "") toast(e.localizedMessage ?: "")
} }
@ -176,16 +161,32 @@ class FontSelectDialog : BaseDialogFragment(),
.request() .request()
} }
override fun onClick(file: File) { override fun onClick(docItem: DocItem) {
launch(IO) { execute {
file.copyTo(FileUtils.createFileIfNotExist(fontFolder, file.name), true) fontFolder.listFiles()?.forEach {
.absolutePath.let { path -> it.delete()
if (curFilePath != path) { }
withContext(Main) { if (docItem.isContentPath) {
callBack?.selectFile(path) 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() dialog?.dismiss()
} }
} }

@ -165,7 +165,7 @@ class CoverImageView : androidx.appcompat.widget.AppCompatImageView {
companion object { companion object {
private var showBookName = false private var showBookName = false
private lateinit var defaultDrawable: Drawable lateinit var defaultDrawable: Drawable
init { init {
upDefaultCover() upDefaultCover()

@ -138,6 +138,8 @@ data class DocItem(
val isDir: Boolean by lazy { val isDir: Boolean by lazy {
DocumentsContract.Document.MIME_TYPE_DIR == attr DocumentsContract.Document.MIME_TYPE_DIR == attr
} }
val isContentPath get() = uri.toString().isContentPath()
} }
@Throws(Exception::class) @Throws(Exception::class)

@ -1,7 +1,8 @@
package io.legado.app.utils package io.legado.app.utils
val removeHtmlRegex = val removeHtmlRegex = "</?(?:div|p|br|hr|h\\d|article|dd|dl)[^>]*>".toRegex()
"</?(?:html|head|div|a|p|b|br|hr|h\\d|article|dd|dl|span|link|title)[^>]*>".toRegex() val imgRegex = "<img[^>]*>".toRegex()
val notImgHtmlRegex = "^\\s*|</?(?!img)\\w+[^>]*>".toRegex()
fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim() fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim()
@ -37,7 +38,10 @@ fun String?.isJsonArray(): Boolean =
fun String?.htmlFormat(): String { fun String?.htmlFormat(): String {
this ?: return "" 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("\\s*\\n+\\s*".toRegex(), "\n  ")
.replace("^[\\n\\s]+".toRegex(), "  ") .replace("^[\\n\\s]+".toRegex(), "  ")
.replace("[\\n\\s]+$".toRegex(), "") .replace("[\\n\\s]+$".toRegex(), "")

@ -721,4 +721,6 @@
<string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string> <string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string>
<string name="clear_cache_summary">清除已下载书籍和字体缓存</string> <string name="clear_cache_summary">清除已下载书籍和字体缓存</string>
<string name="default_cover">默认封面</string> <string name="default_cover">默认封面</string>
<string name="restore_ignore">恢复忽略列表</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string>
</resources> </resources>

@ -721,5 +721,7 @@
<string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string> <string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string>
<string name="clear_cache_summary">清除已下载书籍和字体缓存</string> <string name="clear_cache_summary">清除已下载书籍和字体缓存</string>
<string name="default_cover">默认封面</string> <string name="default_cover">默认封面</string>
<string name="restore_ignore">恢复忽略列表</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string>
</resources> </resources>

@ -721,4 +721,6 @@
<string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string> <string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string>
<string name="clear_cache_summary">清除已下载书籍和字体缓存</string> <string name="clear_cache_summary">清除已下载书籍和字体缓存</string>
<string name="default_cover">默认封面</string> <string name="default_cover">默认封面</string>
<string name="restore_ignore">恢复忽略列表</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string>
</resources> </resources>

@ -722,5 +722,7 @@
<string name="contributors_summary">gedoor,Invinciblelee etc. Checking in github for details</string> <string name="contributors_summary">gedoor,Invinciblelee etc. Checking in github for details</string>
<string name="clear_cache_summary">Clear the cache of the downloaded books and fonts</string> <string name="clear_cache_summary">Clear the cache of the downloaded books and fonts</string>
<string name="default_cover">Default cover</string> <string name="default_cover">Default cover</string>
<string name="restore_ignore">恢复忽略列表</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string>
</resources> </resources>

@ -39,6 +39,7 @@
</io.legado.app.ui.widget.prefs.PreferenceCategory> </io.legado.app.ui.widget.prefs.PreferenceCategory>
<io.legado.app.ui.widget.prefs.PreferenceCategory <io.legado.app.ui.widget.prefs.PreferenceCategory
android:title="@string/backup_restore"
app:allowDividerBelow="false" app:allowDividerBelow="false"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:layout="@layout/view_preference_category"> app:layout="@layout/view_preference_category">
@ -61,6 +62,12 @@
android:summary="@string/restore_summary" android:summary="@string/restore_summary"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference
android:key="restoreIgnore"
android:title="@string/restore_ignore"
android:summary="@string/restore_ignore_summary"
app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference <io.legado.app.ui.widget.prefs.Preference
android:key="import_old" android:key="import_old"
android:title="@string/menu_import_old_version" android:title="@string/menu_import_old_version"

Loading…
Cancel
Save