diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a1b9f1846..8b943cc65 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -79,6 +79,20 @@
android:resource="@xml/shortcuts"
android:launchMode="singleTask" />
+
+
+
+
+
+
+
+
【备份与恢复】,选择【导入旧版本数据】。
-* 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
+* 请关注[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
+
+**2020/03/15**
+* 弄了个企业公众号[开源阅读](),后面弄好后会把原来的开源阅读软件迁移过来
+* 修复滚动模式切换章节位置不归0的bug
+* 修复文字选择更多菜单在部分手机上报错的bug
+
+**2020/03/14**
+* 加载正文无书源时自动换源
+
+**2020/03/14**
+* 修改导航栏图标
**2020/03/13**
* 更改书架控件,ViewPager2替换回2.0使用的ViewPager,解决下拉不流畅问题
* 修复点击作者搜索后,打开的详情页还是原来的书籍的bug
* 修改朗读菜单
+* 优化rss朗读
**2020/03/12**
* 导入本地添加需要权限模式
diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
index 9ce5c65be..55d5ada4c 100644
--- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
+++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
@@ -50,9 +50,12 @@ interface BookSourceDao {
@get:Query("select * from book_sources order by customOrder asc")
val all: List
- @get:Query("select * from book_sources where enabled = 1 order by customOrder asc")
+ @get:Query("select * from book_sources where enabled = 1 order by customOrder")
val allEnabled: List
+ @get:Query("select * from book_sources where enabled = 1 and bookSourceType = 0 order by customOrder")
+ val allTextEnabled: List
+
@Query("select * from book_sources where bookSourceUrl = :key")
fun getBookSource(key: String): BookSource?
diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt
index 833561f1b..9e50a6d4c 100644
--- a/app/src/main/java/io/legado/app/data/entities/Book.kt
+++ b/app/src/main/java/io/legado/app/data/entities/Book.kt
@@ -31,8 +31,8 @@ data class Book(
var intro: String? = null, // 简介内容(书源获取)
var customIntro: String? = null, // 简介内容(用户修改)
var charset: String? = null, // 自定义字符集名称(仅适用于本地书籍)
- var type: Int = 0, // @BookType
- var group: Int = 0, // 自定义分组索引号
+ var type: Int = 0, // 0:text 1:audio
+ var group: Int = 1, // 自定义分组索引号
var latestChapterTitle: String? = null, // 最新章节标题
var latestChapterTime: Long = System.currentTimeMillis(), // 最新章节标题更新时间
var lastCheckTime: Long = System.currentTimeMillis(), // 最近一次更新书籍信息的时间
diff --git a/app/src/main/java/io/legado/app/help/LauncherIconHelp.kt b/app/src/main/java/io/legado/app/help/LauncherIconHelp.kt
index 76bcd6116..70f72f55a 100644
--- a/app/src/main/java/io/legado/app/help/LauncherIconHelp.kt
+++ b/app/src/main/java/io/legado/app/help/LauncherIconHelp.kt
@@ -5,10 +5,7 @@ import android.content.pm.PackageManager
import android.os.Build
import io.legado.app.App
import io.legado.app.R
-import io.legado.app.ui.welcome.Launcher1
-import io.legado.app.ui.welcome.Launcher2
-import io.legado.app.ui.welcome.Launcher3
-import io.legado.app.ui.welcome.WelcomeActivity
+import io.legado.app.ui.welcome.*
import org.jetbrains.anko.toast
/**
@@ -20,7 +17,8 @@ object LauncherIconHelp {
private val componentNames = arrayListOf(
ComponentName(App.INSTANCE, Launcher1::class.java.name),
ComponentName(App.INSTANCE, Launcher2::class.java.name),
- ComponentName(App.INSTANCE, Launcher3::class.java.name)
+ ComponentName(App.INSTANCE, Launcher3::class.java.name),
+ ComponentName(App.INSTANCE, Launcher4::class.java.name)
)
fun changeIcon(icon: String?) {
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 5393249c3..f174a6f5e 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
@@ -128,7 +128,7 @@ object Restore {
bodyIndentCount = App.INSTANCE.getPrefInt(PreferKey.bodyIndent, 2)
}
ChapterProvider.upStyle()
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = false)
}
withContext(Main) {
if (AppConfig.isNightTheme && AppCompatDelegate.getDefaultNightMode() != AppCompatDelegate.MODE_NIGHT_YES) {
diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt
index 0bcbb114b..19304862c 100644
--- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt
+++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt
@@ -199,13 +199,12 @@ object ATH {
fun applyBottomNavigationColor(bottomBar: BottomNavigationView?) {
bottomBar?.apply {
- setBackgroundColor(ThemeStore.backgroundColor(context))
+ setBackgroundColor(ThemeStore.bottomBackground(context))
val colorStateList = Selector.colorBuild()
.setDefaultColor(context.getCompatColor(R.color.btn_bg_press_tp))
.setSelectedColor(ThemeStore.accentColor(bottom_navigation_view.context)).create()
itemIconTintList = colorStateList
itemTextColor = colorStateList
- setBackgroundColor(ThemeStore.bottomBackground(context))
}
}
diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt
index 69dfb943c..7d14ea8bc 100644
--- a/app/src/main/java/io/legado/app/model/WebBook.kt
+++ b/app/src/main/java/io/legado/app/model/WebBook.kt
@@ -29,26 +29,34 @@ class WebBook(val bookSource: BookSource) {
context: CoroutineContext = Dispatchers.IO
): Coroutine> {
return Coroutine.async(scope, context) {
- bookSource.searchUrl?.let { searchUrl ->
- val analyzeUrl = AnalyzeUrl(
- ruleUrl = searchUrl,
- key = key,
- page = page,
- baseUrl = sourceUrl,
- headerMapF = bookSource.getHeaderMap()
- )
- val res = analyzeUrl.getResponseAwait(bookSource.bookSourceUrl)
- BookList.analyzeBookList(
- res.body,
- bookSource,
- analyzeUrl,
- res.url,
- true
- )
- } ?: arrayListOf()
+ searchBookSuspend(key, page)
}
}
+ suspend fun searchBookSuspend(
+ key: String,
+ page: Int? = 1
+ ): ArrayList {
+ bookSource.searchUrl?.let { searchUrl ->
+ val analyzeUrl = AnalyzeUrl(
+ ruleUrl = searchUrl,
+ key = key,
+ page = page,
+ baseUrl = sourceUrl,
+ headerMapF = bookSource.getHeaderMap()
+ )
+ val res = analyzeUrl.getResponseAwait(bookSource.bookSourceUrl)
+ return BookList.analyzeBookList(
+ res.body,
+ bookSource,
+ analyzeUrl,
+ res.url,
+ true
+ )
+ }
+ return arrayListOf()
+ }
+
/**
* 发现
*/
diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt
index 61507bf7c..1f63dac89 100644
--- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt
+++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt
@@ -29,7 +29,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
}
}
- private var ttsIsSuccess: Boolean = false
+ private var ttsInitFinish = false
override fun onCreate() {
super.onCreate()
@@ -42,22 +42,23 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
clearTTS()
}
+ @Synchronized
override fun onInit(status: Int) {
- launch {
- if (status == TextToSpeech.SUCCESS) {
- textToSpeech?.language = Locale.CHINA
- textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener())
- ttsIsSuccess = true
- play()
- } else {
+ if (status == TextToSpeech.SUCCESS) {
+ textToSpeech?.language = Locale.CHINA
+ textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener())
+ ttsInitFinish = true
+ play()
+ } else {
+ launch {
toast(R.string.tts_init_failed)
}
}
}
- @Suppress("DEPRECATION")
+ @Synchronized
override fun play() {
- if (contentList.isEmpty() || !ttsIsSuccess) {
+ if (contentList.isEmpty() || !ttsInitFinish) {
return
}
if (requestFocus()) {
diff --git a/app/src/main/java/io/legado/app/service/help/ReadBook.kt b/app/src/main/java/io/legado/app/service/help/ReadBook.kt
index 85f2fff45..68b1601ac 100644
--- a/app/src/main/java/io/legado/app/service/help/ReadBook.kt
+++ b/app/src/main/java/io/legado/app/service/help/ReadBook.kt
@@ -21,7 +21,6 @@ import org.jetbrains.anko.toast
object ReadBook {
-
var titleDate = MutableLiveData()
var book: Book? = null
var inBookshelf = false
@@ -34,9 +33,10 @@ object ReadBook {
var curTextChapter: TextChapter? = null
var nextTextChapter: TextChapter? = null
var webBook: WebBook? = null
+ var msg: String? = null
private val loadingChapters = arrayListOf()
- fun resetData(book: Book) {
+ fun resetData(book: Book, noSource: (name: String, author: String) -> Unit) {
this.book = book
titleDate.postValue(book.name)
durChapterIndex = book.durChapterIndex
@@ -46,12 +46,22 @@ object ReadBook {
prevTextChapter = null
curTextChapter = null
nextTextChapter = null
- upWebBook(book.origin)
+ upWebBook(book, noSource)
}
- fun upWebBook(origin: String) {
- val bookSource = App.db.bookSourceDao().getBookSource(origin)
- webBook = if (bookSource != null) WebBook(bookSource) else null
+ fun upWebBook(book: Book?, noSource: (name: String, author: String) -> Unit) {
+ book ?: return
+ if (book.origin == BookType.local) {
+ webBook = null
+ } else {
+ val bookSource = App.db.bookSourceDao().getBookSource(book.origin)
+ if (bookSource != null) {
+ webBook = WebBook(bookSource)
+ } else {
+ webBook = null
+ noSource.invoke(book.name, book.author)
+ }
+ }
}
fun moveToNextPage() {
@@ -69,11 +79,11 @@ object ReadBook {
nextTextChapter = null
book?.let {
if (curTextChapter == null) {
- loadContent(durChapterIndex, upContent)
+ loadContent(durChapterIndex, upContent, false)
} else if (upContent) {
callBack?.upContent()
}
- loadContent(durChapterIndex.plus(1), upContent)
+ loadContent(durChapterIndex.plus(1), upContent, false)
GlobalScope.launch(Dispatchers.IO) {
for (i in 2..10) {
delay(100)
@@ -99,11 +109,11 @@ object ReadBook {
prevTextChapter = null
book?.let {
if (curTextChapter == null) {
- loadContent(durChapterIndex, upContent)
+ loadContent(durChapterIndex, upContent, false)
} else if (upContent) {
callBack?.upContent()
}
- loadContent(durChapterIndex.minus(1), upContent)
+ loadContent(durChapterIndex.minus(1), upContent, false)
GlobalScope.launch(Dispatchers.IO) {
for (i in -5..-2) {
delay(100)
@@ -184,21 +194,21 @@ object ReadBook {
/**
* 加载章节内容
*/
- fun loadContent() {
- loadContent(durChapterIndex)
- loadContent(durChapterIndex + 1)
- loadContent(durChapterIndex - 1)
+ fun loadContent(resetPageOffset: Boolean) {
+ loadContent(durChapterIndex, resetPageOffset = resetPageOffset)
+ loadContent(durChapterIndex + 1, resetPageOffset = resetPageOffset)
+ loadContent(durChapterIndex - 1, resetPageOffset = resetPageOffset)
}
- fun loadContent(index: Int, upContent: Boolean = true) {
+ fun loadContent(index: Int, upContent: Boolean = true, resetPageOffset: Boolean) {
book?.let { book ->
if (addLoading(index)) {
Coroutine.async {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
BookHelp.getContent(book, chapter)?.let {
- contentLoadFinish(chapter, it, upContent)
+ contentLoadFinish(chapter, it, upContent, resetPageOffset)
removeLoading(chapter.index)
- } ?: download(chapter)
+ } ?: download(chapter, resetPageOffset = resetPageOffset)
} ?: removeLoading(index)
}.onError {
removeLoading(index)
@@ -216,7 +226,7 @@ object ReadBook {
if (BookHelp.hasContent(book, chapter)) {
removeLoading(chapter.index)
} else {
- download(chapter)
+ download(chapter, false)
}
} ?: removeLoading(index)
}.onError {
@@ -226,20 +236,28 @@ object ReadBook {
}
}
- private fun download(chapter: BookChapter) {
+ private fun download(chapter: BookChapter, resetPageOffset: Boolean) {
book?.let { book ->
webBook?.getContent(book, chapter)
?.onSuccess(Dispatchers.IO) { content ->
if (content.isNullOrEmpty()) {
- contentLoadFinish(chapter, App.INSTANCE.getString(R.string.content_empty))
+ contentLoadFinish(
+ chapter,
+ App.INSTANCE.getString(R.string.content_empty),
+ resetPageOffset = resetPageOffset
+ )
removeLoading(chapter.index)
} else {
BookHelp.saveContent(book, chapter, content)
- contentLoadFinish(chapter, content)
+ contentLoadFinish(chapter, content, resetPageOffset = resetPageOffset)
removeLoading(chapter.index)
}
}?.onError {
- contentLoadFinish(chapter, it.localizedMessage ?: "未知错误")
+ contentLoadFinish(
+ chapter,
+ it.localizedMessage ?: "未知错误",
+ resetPageOffset = resetPageOffset
+ )
removeLoading(chapter.index)
}
}
@@ -265,7 +283,8 @@ object ReadBook {
private fun contentLoadFinish(
chapter: BookChapter,
content: String,
- upContent: Boolean = true
+ upContent: Boolean = true,
+ resetPageOffset: Boolean
) {
Coroutine.async {
if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) {
@@ -279,18 +298,18 @@ object ReadBook {
when (chapter.index) {
durChapterIndex -> {
curTextChapter = ChapterProvider.getTextChapter(chapter, c, chapterSize)
- if (upContent) callBack?.upContent()
+ if (upContent) callBack?.upContent(resetPageOffset = resetPageOffset)
callBack?.upView()
curPageChanged()
callBack?.contentLoadFinish()
}
durChapterIndex - 1 -> {
prevTextChapter = ChapterProvider.getTextChapter(chapter, c, chapterSize)
- if (upContent) callBack?.upContent(-1)
+ if (upContent) callBack?.upContent(-1, resetPageOffset)
}
durChapterIndex + 1 -> {
nextTextChapter = ChapterProvider.getTextChapter(chapter, c, chapterSize)
- if (upContent) callBack?.upContent(1)
+ if (upContent) callBack?.upContent(1, resetPageOffset)
}
}
}
@@ -316,7 +335,7 @@ object ReadBook {
}
interface CallBack {
- fun upContent(relativePosition: Int = 0)
+ fun upContent(relativePosition: Int = 0, resetPageOffset: Boolean = true)
fun upView()
fun upPageProgress()
fun contentLoadFinish()
diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt
index 1086f0416..8be9ed34f 100644
--- a/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt
+++ b/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt
@@ -33,6 +33,7 @@ import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.applyTint
import io.legado.app.utils.getViewModel
import io.legado.app.utils.requestInputMethod
+import io.legado.app.utils.visible
import kotlinx.android.synthetic.main.dialog_edit_text.view.*
import kotlinx.android.synthetic.main.dialog_recycler_view.*
import kotlinx.android.synthetic.main.item_group_manage.view.*
@@ -74,6 +75,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener {
recycler_view.addItemDecoration(VerticalDivider(requireContext()))
recycler_view.adapter = adapter
tv_ok.setTextColor(requireContext().accentColor)
+ tv_ok.visible()
tv_ok.onClick { dismiss() }
App.db.bookGroupDao().liveDataAll().observe(viewLifecycleOwner, Observer {
val diffResult =
diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
index 138d676be..8cd1915cc 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
@@ -25,6 +25,7 @@ import io.legado.app.data.entities.BookChapter
import io.legado.app.help.BookHelp
import io.legado.app.help.ReadBookConfig
import io.legado.app.help.coroutine.Coroutine
+import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.SyncBookProgress
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.noButton
@@ -115,7 +116,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = false)
}
override fun onResume() {
@@ -402,11 +403,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo
*/
override fun showTextActionMenu() {
textActionMenu ?: let {
- textActionMenu = TextActionMenu(this, this).apply {
- contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
- }
+ textActionMenu = TextActionMenu(this, this)
}
textActionMenu?.let { popup ->
+ popup.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val popupHeight = popup.contentView.measuredHeight
val x = text_menu_position.x.toInt()
var y = text_menu_position.y.toInt() - popupHeight
@@ -481,9 +481,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo
/**
* 更新内容
*/
- override fun upContent(relativePosition: Int) {
+ override fun upContent(relativePosition: Int, resetPageOffset: Boolean) {
launch {
- page_view.upContent(relativePosition)
+ page_view.upContent(relativePosition, resetPageOffset)
}
}
@@ -579,7 +579,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo
override fun onReplaceRuleSave() {
Coroutine.async {
BookHelp.upReplaceRules()
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = false)
}
}
@@ -684,6 +684,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo
page_view.onDestroy()
if (!BuildConfig.DEBUG) {
SyncBookProgress.uploadBookProgress()
+ Backup.autoBack(this)
}
}
@@ -707,9 +708,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo
page_view.upBg()
page_view.upStyle()
if (it) {
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = false)
} else {
- page_view.upContent()
+ page_view.upContent(resetPageOffset = false)
}
}
observeEvent(EventBus.ALOUD_STATE) {
@@ -718,7 +719,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo
val page = textChapter.page(ReadBook.durPageIndex)
if (page != null) {
page.removePageAloudSpan()
- page_view.upContent()
+ page_view.upContent(resetPageOffset = false)
}
}
}
diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
index 2ebab7875..6c6d52aca 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
@@ -39,7 +39,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
private fun initBook(book: Book) {
if (ReadBook.book?.bookUrl != book.bookUrl) {
- ReadBook.resetData(book)
+ ReadBook.resetData(book) { name, author ->
+ autoChangeSource(name, author)
+ }
isInitFinish = true
ReadBook.chapterSize = App.db.bookChapterDao().getChapterCount(book.bookUrl)
if (ReadBook.chapterSize == 0) {
@@ -52,7 +54,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
if (ReadBook.durChapterIndex > ReadBook.chapterSize - 1) {
ReadBook.durChapterIndex = ReadBook.chapterSize - 1
}
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = true)
}
if (ReadBook.inBookshelf) {
ReadBook.saveRead()
@@ -60,7 +62,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
} else {
isInitFinish = true
ReadBook.titleDate.postValue(book.name)
- ReadBook.upWebBook(book.origin)
+ ReadBook.upWebBook(book) { name, author ->
+ autoChangeSource(name, author)
+ }
ReadBook.chapterSize = App.db.bookChapterDao().getChapterCount(book.bookUrl)
if (ReadBook.chapterSize == 0) {
if (book.tocUrl.isEmpty()) {
@@ -70,7 +74,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
}
} else {
if (ReadBook.curTextChapter != null) {
- ReadBook.callBack?.upContent()
+ ReadBook.callBack?.upContent(resetPageOffset = false)
}
}
}
@@ -103,7 +107,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
App.db.bookChapterDao().insert(*it.toTypedArray())
App.db.bookDao().update(book)
ReadBook.chapterSize = it.size
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = true)
}
} else {
ReadBook.webBook?.getChapterList(book, this)
@@ -113,7 +117,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
App.db.bookChapterDao().insert(*cList.toTypedArray())
App.db.bookDao().update(book)
ReadBook.chapterSize = cList.size
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = true)
} else {
changeDruChapterIndex(cList)
}
@@ -122,7 +126,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
}
}?.onError {
toast(R.string.error_load_toc)
- } ?: autoChangeSource()
+ } ?: autoChangeSource(book.name, book.author)
}
}
}
@@ -151,8 +155,28 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
}
}
- private fun autoChangeSource() {
-
+ private fun autoChangeSource(name: String, author: String) {
+ execute {
+ App.db.bookSourceDao().allTextEnabled.forEach { source ->
+ try {
+ val searchBooks = WebBook(source).searchBookSuspend(name)
+ searchBooks.getOrNull(0)?.let {
+ if (it.name == name && (it.author == author || author == "")) {
+ changeTo(it.toBook())
+ return@forEach
+ }
+ }
+ } catch (e: Exception) {
+ //nothing
+ }
+ }
+ }.onStart {
+ ReadBook.msg = "正在自动换源"
+ ReadBook.callBack?.upContent()
+ }.onFinally {
+ ReadBook.msg = null
+ ReadBook.callBack?.upContent()
+ }
}
private fun upChangeDurChapterIndex(book: Book, chapters: List) {
@@ -167,7 +191,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
App.db.bookDao().update(book)
App.db.bookChapterDao().insert(*chapters.toTypedArray())
ReadBook.chapterSize = chapters.size
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = true)
}
}
@@ -181,7 +205,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
ReadBook.durPageIndex = pageIndex
}
ReadBook.saveRead()
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = true)
}
fun removeFromBookshelf(success: (() -> Unit)?) {
@@ -208,9 +232,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, ReadBook.durChapterIndex)
?.let { chapter ->
- BookHelp.delContent(book, chapter)
- ReadBook.loadContent(ReadBook.durChapterIndex)
- }
+ BookHelp.delContent(book, chapter)
+ ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
+ }
}
}
diff --git a/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt
index 9d7046f6e..b64ec996d 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt
@@ -15,13 +15,11 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.view.SupportMenuInflater
import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.view.menu.MenuItemImpl
-import androidx.appcompat.widget.PopupMenu
-import androidx.core.view.size
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
+import androidx.core.view.isVisible
import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.SimpleRecyclerAdapter
+import io.legado.app.utils.gone
import io.legado.app.utils.isAbsUrl
import io.legado.app.utils.sendToClip
import io.legado.app.utils.visible
@@ -35,6 +33,10 @@ import org.jetbrains.anko.toast
class TextActionMenu(private val context: Context, private val callBack: CallBack) :
PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) {
+ private val adapter = Adapter(context)
+ private val menu = MenuBuilder(context)
+ private val moreMenu = MenuBuilder(context)
+
init {
@SuppressLint("InflateParams")
contentView = LayoutInflater.from(context).inflate(R.layout.popup_action_menu, null)
@@ -44,33 +46,38 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
isFocusable = false
initRecyclerView()
+ setOnDismissListener {
+ contentView.apply {
+ iv_menu_more.setImageResource(R.drawable.ic_more_vert)
+ recycler_view_more.gone()
+ adapter.setItems(menu.visibleItems)
+ recycler_view.visible()
+ }
+ }
}
private fun initRecyclerView() = with(contentView) {
- val adapter = Adapter(context)
- recycler_view.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
recycler_view.adapter = adapter
- val menu = MenuBuilder(context)
+ recycler_view_more.adapter = adapter
SupportMenuInflater(context).inflate(R.menu.content_select_action, menu)
adapter.setItems(menu.visibleItems)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- val popupMenu = PopupMenu(context, iv_menu_more)
- onInitializeMenu(popupMenu.menu)
- if (popupMenu.menu.size > 0) {
- iv_menu_more.visible()
- popupMenu.setOnMenuItemClickListener { item ->
- item.intent?.let {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- it.putExtra(Intent.EXTRA_PROCESS_TEXT, callBack.selectedText)
- context.startActivity(it)
- }
- }
- this@TextActionMenu.dismiss()
- true
- }
- }
- iv_menu_more.onClick {
- popupMenu.show()
+ onInitializeMenu(moreMenu)
+ }
+ if (moreMenu.size() > 0) {
+ iv_menu_more.visible()
+ }
+ iv_menu_more.onClick {
+ if (recycler_view.isVisible) {
+ iv_menu_more.setImageResource(R.drawable.ic_arrow_back)
+ adapter.setItems(moreMenu.visibleItems)
+ recycler_view.gone()
+ recycler_view_more.visible()
+ } else {
+ iv_menu_more.setImageResource(R.drawable.ic_more_vert)
+ recycler_view_more.gone()
+ adapter.setItems(menu.visibleItems)
+ recycler_view.visible()
}
}
}
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
index 6dc89f716..1cc006512 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
@@ -108,8 +108,10 @@ class ContentView(context: Context) : FrameLayout(context) {
}
}
- fun setContent(textPage: TextPage) {
+ fun setContent(textPage: TextPage, resetPageOffset: Boolean = true) {
setProgress(textPage)
+ if (resetPageOffset)
+ resetPageOffset()
content_text_view.setContent(textPage)
}
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt
index 4f7afa04f..3a128f969 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt
@@ -17,5 +17,5 @@ interface DataSource {
fun hasPrevChapter(): Boolean
- fun upContent(relativePosition: Int = 0)
+ fun upContent(relativePosition: Int = 0, resetPageOffset: Boolean = true)
}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
index 1b7b71b07..dd19fdc0e 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
@@ -38,7 +38,7 @@ class PageView(context: Context, attrs: AttributeSet) :
prevPage.x = -w.toFloat()
pageDelegate?.setViewSize(w, h)
if (oldw != 0 && oldh != 0) {
- ReadBook.loadContent()
+ ReadBook.loadContent(resetPageOffset = false)
}
}
@@ -93,9 +93,9 @@ class PageView(context: Context, attrs: AttributeSet) :
upContent()
}
- override fun upContent(relativePosition: Int) {
+ override fun upContent(relativePosition: Int, resetPageOffset: Boolean) {
if (ReadBookConfig.isScroll) {
- curPage.setContent(pageFactory.currentPage)
+ curPage.setContent(pageFactory.currentPage, resetPageOffset)
} else {
when (relativePosition) {
-1 -> prevPage.setContent(pageFactory.prevPage)
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt
index a867daf3d..a38ed6e51 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt
@@ -38,7 +38,7 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource
} else {
ReadBook.setPageIndex(pageIndex.plus(1))
}
- if (upContent) upContent()
+ if (upContent) upContent(resetPageOffset = false)
true
} else
false
@@ -51,7 +51,7 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource
} else {
ReadBook.setPageIndex(pageIndex.minus(1))
}
- if (upContent) upContent()
+ if (upContent) upContent(resetPageOffset = false)
true
} else
false
@@ -59,6 +59,9 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource
override val currentPage: TextPage
get() = with(dataSource) {
+ ReadBook.msg?.let {
+ return@with TextPage(text = it).format()
+ }
currentChapter?.let {
return@with it.page(pageIndex)
?: TextPage(title = it.title).format()
@@ -68,6 +71,9 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource
override val nextPage: TextPage
get() = with(dataSource) {
+ ReadBook.msg?.let {
+ return@with TextPage(text = it).format()
+ }
currentChapter?.let {
if (pageIndex < it.pageSize() - 1) {
return@with it.page(pageIndex + 1)?.removePageAloudSpan()
@@ -86,6 +92,9 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource
override val prevPage: TextPage
get() = with(dataSource) {
+ ReadBook.msg?.let {
+ return@with TextPage(text = it).format()
+ }
if (pageIndex > 0) {
currentChapter?.let {
return@with it.page(pageIndex - 1)?.removePageAloudSpan()
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 462fb317d..0aa49ede7 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
@@ -3,8 +3,6 @@ package io.legado.app.ui.main
import android.os.Bundle
import android.view.KeyEvent
import android.view.MenuItem
-import androidx.core.view.forEach
-import androidx.core.view.forEachIndexed
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
@@ -17,7 +15,6 @@ import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey
import io.legado.app.help.AppConfig
-import io.legado.app.help.storage.Backup
import io.legado.app.lib.theme.ATH
import io.legado.app.service.BaseReadAloudService
import io.legado.app.service.help.ReadAloud
@@ -96,14 +93,6 @@ class MainActivity : VMBaseActivity(R.layout.activity_main),
bottom_navigation_view.menu.getItem(3).isChecked = true
}
}
-
-
-// bottom_navigation_view.menu.forEachIndexed { index, item ->
-// if (item.isChecked)
-// item.icon = getDrawable(res[1][index])
-// else
-// item.icon = getDrawable(res[0][index])
-// }
}
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
@@ -124,13 +113,6 @@ class MainActivity : VMBaseActivity(R.layout.activity_main),
return super.onKeyUp(keyCode, event)
}
- override fun finish() {
- if (!BuildConfig.DEBUG) {
- Backup.autoBack(this)
- }
- super.finish()
- }
-
override fun onDestroy() {
super.onDestroy()
ReadAloud.stop(this)
diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt
index d647afd3b..1438c4507 100644
--- a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt
+++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt
@@ -21,7 +21,6 @@ class BooksAdapterGrid(context: Context, private val callBack: CallBack) :
if (bundle == null) {
ATH.applyBackgroundTint(this)
tv_name.text = item.name
- bv_author.text = item.author
iv_cover.load(item.getDisplayCover(), item.name, item.author)
if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) {
bv_unread.invisible()
@@ -35,7 +34,6 @@ class BooksAdapterGrid(context: Context, private val callBack: CallBack) :
bundle.keySet().map {
when (it) {
"name" -> tv_name.text = item.name
- "author" -> bv_author.text = item.author
"cover" -> iv_cover.load(item.getDisplayCover(), item.name, item.author)
"refresh" -> if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) {
bv_unread.invisible()
diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt
index 7dcecaf11..f3087f5e7 100644
--- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt
+++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt
@@ -24,6 +24,7 @@ import io.legado.app.ui.config.ConfigActivity
import io.legado.app.ui.config.ConfigViewModel
import io.legado.app.ui.filechooser.FileChooserDialog
import io.legado.app.ui.replacerule.ReplaceRuleActivity
+import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.ui.widget.prefs.NameListPreference
import io.legado.app.ui.widget.prefs.PreferenceCategory
import io.legado.app.ui.widget.prefs.SwitchPreference
@@ -48,9 +49,10 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config), FileChooserDialog.
override fun onCompatOptionsItemSelected(item: MenuItem) {
when (item.itemId) {
- R.id.menu_help -> startActivity()
- R.id.menu_backup -> BackupRestoreUi.backup(this)
- R.id.menu_restore -> BackupRestoreUi.restore(this)
+ R.id.menu_help -> {
+ val text = String(requireContext().assets.open("help.md").readBytes())
+ TextDialog.show(childFragmentManager, text, TextDialog.MD)
+ }
}
}
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 79ea599d1..9aa30235b 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
@@ -22,7 +22,6 @@ import org.apache.commons.text.StringEscapeUtils
import org.jetbrains.anko.share
import org.jetbrains.anko.toast
import org.jsoup.Jsoup
-import org.jsoup.safety.Whitelist
class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_read),
@@ -246,18 +245,15 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r
@SuppressLint("SetJavaScriptEnabled")
private fun readAloud() {
- if (viewModel.textToSpeech.isSpeaking) {
- viewModel.textToSpeech.stop()
+ if (viewModel.textToSpeech?.isSpeaking == true) {
+ viewModel.textToSpeech?.stop()
upTtsMenu(false)
} else {
web_view.settings.javaScriptEnabled = true
web_view.evaluateJavascript("document.documentElement.outerHTML") {
val html = StringEscapeUtils.unescapeJson(it)
- val text = Jsoup.clean(html, Whitelist.none())
- .replace(Regex("""&\w+;"""), "")
- .trim()//朗读过程中总是听到一些杂音,清理一下
- //longToast(需读内容)调试一下
- viewModel.readAloud(text)
+ Jsoup.parse(html).text()
+ viewModel.readAloud(Jsoup.parse(html).textArray())
}
}
}
diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
index 6d90fd181..fd721e09b 100644
--- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
@@ -35,7 +35,9 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
val contentLiveData = MutableLiveData()
val urlLiveData = MutableLiveData()
var star = false
- var textToSpeech: TextToSpeech = TextToSpeech(context, this)
+ var textToSpeech: TextToSpeech? = null
+ private var ttsInitFinish = false
+ private var ttsTextList = arrayListOf()
fun initData(intent: Intent) {
execute {
@@ -143,28 +145,43 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
}
}
+ @Synchronized
override fun onInit(status: Int) {
- launch {
- if (status == TextToSpeech.SUCCESS) {
- textToSpeech.language = Locale.CHINA
- textToSpeech.setOnUtteranceProgressListener(TTSUtteranceListener())
- } else {
+ if (status == TextToSpeech.SUCCESS) {
+ textToSpeech?.language = Locale.CHINA
+ textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener())
+ ttsInitFinish = true
+ play()
+ } else {
+ launch {
toast(R.string.tts_init_failed)
}
}
}
- fun readAloud(text: String) {
- textToSpeech.stop()
- text.split("\n", " ", " ").forEach {
- textToSpeech.speak(it, TextToSpeech.QUEUE_ADD, null, "rss")
+ @Synchronized
+ private fun play() {
+ if (!ttsInitFinish) return
+ textToSpeech?.stop()
+ ttsTextList.forEach {
+ textToSpeech?.speak(it, TextToSpeech.QUEUE_ADD, null, "rss")
+ }
+ }
+
+ fun readAloud(textArray: Array) {
+ ttsTextList.clear()
+ ttsTextList.addAll(textArray)
+ textToSpeech?.let {
+ play()
+ } ?: let {
+ textToSpeech = TextToSpeech(context, this)
}
}
override fun onCleared() {
super.onCleared()
- textToSpeech.stop()
- textToSpeech.shutdown()
+ textToSpeech?.stop()
+ textToSpeech?.shutdown()
}
/**
diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt
index ed09cec93..ce2313f5a 100644
--- a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt
@@ -24,10 +24,7 @@ import io.legado.app.lib.dialogs.noButton
import io.legado.app.lib.dialogs.yesButton
import io.legado.app.lib.theme.accentColor
import io.legado.app.ui.widget.recycler.VerticalDivider
-import io.legado.app.utils.applyTint
-import io.legado.app.utils.getViewModelOfActivity
-import io.legado.app.utils.requestInputMethod
-import io.legado.app.utils.splitNotBlank
+import io.legado.app.utils.*
import kotlinx.android.synthetic.main.dialog_edit_text.view.*
import kotlinx.android.synthetic.main.dialog_recycler_view.*
import kotlinx.android.synthetic.main.item_group_manage.view.*
@@ -68,6 +65,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener {
recycler_view.addItemDecoration(VerticalDivider(requireContext()))
recycler_view.adapter = adapter
tv_ok.setTextColor(requireContext().accentColor)
+ tv_ok.visible()
tv_ok.onClick { dismiss() }
App.db.rssSourceDao().liveGroup().observe(viewLifecycleOwner, Observer {
val groups = linkedSetOf()
diff --git a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt
index 46e1e446e..08eb06a70 100644
--- a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt
@@ -58,4 +58,5 @@ open class WelcomeActivity : BaseActivity(R.layout.activity_welcome) {
class Launcher1 : WelcomeActivity()
class Launcher2 : WelcomeActivity()
-class Launcher3 : WelcomeActivity()
\ No newline at end of file
+class Launcher3 : WelcomeActivity()
+class Launcher4 : WelcomeActivity()
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/ui/widget/dialog/TextDialog.kt b/app/src/main/java/io/legado/app/ui/widget/dialog/TextDialog.kt
index 648949abd..9c1c75d5e 100644
--- a/app/src/main/java/io/legado/app/ui/widget/dialog/TextDialog.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/dialog/TextDialog.kt
@@ -77,10 +77,16 @@ class TextDialog : BaseDialogFragment() {
time -= 1000
badge_view.setBadgeCount((time / 1000).toInt())
if (time <= 0) {
- dialog?.setCancelable(true)
+ view.post {
+ dialog?.setCancelable(true)
+ }
}
}
}
+ } else {
+ view.post {
+ dialog?.setCancelable(true)
+ }
}
}
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 f4fd0e8eb..b53cebb14 100644
--- a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt
+++ b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt
@@ -98,7 +98,7 @@ object DocumentUtils {
DocumentsContract.Document.COLUMN_LAST_MODIFIED,
DocumentsContract.Document.COLUMN_SIZE,
DocumentsContract.Document.COLUMN_MIME_TYPE
- ), null, null, null
+ ), null, null, DocumentsContract.Document.COLUMN_DISPLAY_NAME
)
c?.let {
val ici = c.getColumnIndex(DocumentsContract.Document.COLUMN_DOCUMENT_ID)
diff --git a/app/src/main/java/io/legado/app/utils/JsoupExtensions.kt b/app/src/main/java/io/legado/app/utils/JsoupExtensions.kt
new file mode 100644
index 000000000..3f347e4a1
--- /dev/null
+++ b/app/src/main/java/io/legado/app/utils/JsoupExtensions.kt
@@ -0,0 +1,66 @@
+package io.legado.app.utils
+
+import org.jsoup.internal.StringUtil
+import org.jsoup.nodes.CDataNode
+import org.jsoup.nodes.Element
+import org.jsoup.nodes.Node
+import org.jsoup.nodes.TextNode
+import org.jsoup.select.NodeTraversor
+import org.jsoup.select.NodeVisitor
+
+
+fun Element.textArray(): Array {
+ val accum = StringUtil.borrowBuilder()
+ NodeTraversor.traverse(object : NodeVisitor {
+ override fun head(node: Node, depth: Int) {
+ if (node is TextNode) {
+ appendNormalisedText(accum, node)
+ } else if (node is Element) {
+ if (accum.isNotEmpty() &&
+ (node.isBlock || node.tag().name == "br") &&
+ !lastCharIsWhitespace(accum)
+ ) accum.append("\n")
+ }
+ }
+
+ override fun tail(node: Node, depth: Int) {
+ if (node is Element) {
+ if (node.isBlock && node.nextSibling() is TextNode && !lastCharIsWhitespace(
+ accum
+ )
+ ) accum.append("\n")
+ }
+ }
+ }, this)
+ val text = StringUtil.releaseBuilder(accum).trim { it <= ' ' }
+ return text.splitNotBlank("\n")
+}
+
+private fun appendNormalisedText(accum: StringBuilder, textNode: TextNode) {
+ val text = textNode.wholeText
+ if (preserveWhitespace(textNode.parentNode()) || textNode is CDataNode)
+ accum.append(text)
+ else StringUtil.appendNormalisedWhitespace(
+ accum,
+ text,
+ lastCharIsWhitespace(accum)
+ )
+}
+
+private fun preserveWhitespace(node: Node?): Boolean {
+ if (node is Element) {
+ var el = node as Element?
+ var i = 0
+ do {
+ if (el!!.tag().preserveWhitespace()) return true
+ el = el.parent()
+ i++
+ } while (i < 6 && el != null)
+ }
+ return false
+}
+
+private fun lastCharIsWhitespace(sb: java.lang.StringBuilder): Boolean {
+ return sb.isNotEmpty() && sb[sb.length - 1] == ' '
+}
+
diff --git a/app/src/main/res/drawable-v24/ic_launcher_0.xml b/app/src/main/res/drawable-v24/ic_launcher_4.xml
similarity index 100%
rename from app/src/main/res/drawable-v24/ic_launcher_0.xml
rename to app/src/main/res/drawable-v24/ic_launcher_4.xml
diff --git a/app/src/main/res/drawable/ic_bottom_books.xml b/app/src/main/res/drawable/ic_bottom_books.xml
index ffda5c5d6..807aaaf30 100644
--- a/app/src/main/res/drawable/ic_bottom_books.xml
+++ b/app/src/main/res/drawable/ic_bottom_books.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_bottom_books_e.xml b/app/src/main/res/drawable/ic_bottom_books_e.xml
index ff159823a..16efedae5 100644
--- a/app/src/main/res/drawable/ic_bottom_books_e.xml
+++ b/app/src/main/res/drawable/ic_bottom_books_e.xml
@@ -1,7 +1,12 @@
-
-
-
-
-
+
+
+
diff --git a/app/src/main/res/drawable/ic_bottom_books_s.xml b/app/src/main/res/drawable/ic_bottom_books_s.xml
index eb36d0fa2..0c6d1144b 100644
--- a/app/src/main/res/drawable/ic_bottom_books_s.xml
+++ b/app/src/main/res/drawable/ic_bottom_books_s.xml
@@ -1,6 +1,41 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_bottom_explore.xml b/app/src/main/res/drawable/ic_bottom_explore.xml
new file mode 100644
index 000000000..439f69ba9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bottom_explore.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_bottom_explore_black.xml b/app/src/main/res/drawable/ic_bottom_explore_black.xml
deleted file mode 100644
index 776e0cc40..000000000
--- a/app/src/main/res/drawable/ic_bottom_explore_black.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_bottom_explore_black_e.xml b/app/src/main/res/drawable/ic_bottom_explore_black_e.xml
deleted file mode 100644
index fdbdedd39..000000000
--- a/app/src/main/res/drawable/ic_bottom_explore_black_e.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_bottom_explore_black_s.xml b/app/src/main/res/drawable/ic_bottom_explore_black_s.xml
deleted file mode 100644
index 1b7a47026..000000000
--- a/app/src/main/res/drawable/ic_bottom_explore_black_s.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_bottom_explore_e.xml b/app/src/main/res/drawable/ic_bottom_explore_e.xml
new file mode 100644
index 000000000..37f7a5929
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bottom_explore_e.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_bottom_explore_s.xml b/app/src/main/res/drawable/ic_bottom_explore_s.xml
new file mode 100644
index 000000000..be7cba1eb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bottom_explore_s.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_bottom_person.xml b/app/src/main/res/drawable/ic_bottom_person.xml
index 9ecbba79f..50053997a 100644
--- a/app/src/main/res/drawable/ic_bottom_person.xml
+++ b/app/src/main/res/drawable/ic_bottom_person.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_bottom_person_e.xml b/app/src/main/res/drawable/ic_bottom_person_e.xml
index f2ee25675..e14f45566 100644
--- a/app/src/main/res/drawable/ic_bottom_person_e.xml
+++ b/app/src/main/res/drawable/ic_bottom_person_e.xml
@@ -1,5 +1,12 @@
-
-
-
+
+
+
diff --git a/app/src/main/res/drawable/ic_bottom_person_s.xml b/app/src/main/res/drawable/ic_bottom_person_s.xml
index f0d729116..be5213686 100644
--- a/app/src/main/res/drawable/ic_bottom_person_s.xml
+++ b/app/src/main/res/drawable/ic_bottom_person_s.xml
@@ -1,9 +1,41 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_bottom_rss_feed.xml b/app/src/main/res/drawable/ic_bottom_rss_feed.xml
index 26d0b4322..4cd080b7f 100644
--- a/app/src/main/res/drawable/ic_bottom_rss_feed.xml
+++ b/app/src/main/res/drawable/ic_bottom_rss_feed.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_bottom_rss_feed_e.xml b/app/src/main/res/drawable/ic_bottom_rss_feed_e.xml
index b69c2336d..08f219fcb 100644
--- a/app/src/main/res/drawable/ic_bottom_rss_feed_e.xml
+++ b/app/src/main/res/drawable/ic_bottom_rss_feed_e.xml
@@ -1,9 +1,12 @@
-
-
-
+
+
+
diff --git a/app/src/main/res/drawable/ic_bottom_rss_feed_s.xml b/app/src/main/res/drawable/ic_bottom_rss_feed_s.xml
index b14351098..60374f709 100644
--- a/app/src/main/res/drawable/ic_bottom_rss_feed_s.xml
+++ b/app/src/main/res/drawable/ic_bottom_rss_feed_s.xml
@@ -1,4 +1,24 @@
-
-
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launch.xml b/app/src/main/res/drawable/ic_launch.xml
deleted file mode 100644
index 6b423cdc7..000000000
--- a/app/src/main/res/drawable/ic_launch.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher.xml b/app/src/main/res/drawable/ic_launcher.xml
new file mode 100644
index 000000000..1bb711f8f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 9f2d2044e..77ed85415 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -10,7 +10,7 @@
android:layout_height="wrap_content"
android:elevation="10dp"
android:background="@color/background"
- app:labelVisibilityMode="labeled"
+ app:labelVisibilityMode="unlabeled"
app:menu="@menu/main_bnv"
app:layout_constraintBottom_toBottomOf="parent" />
diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml
index 278117426..504865171 100644
--- a/app/src/main/res/layout/dialog_read_aloud.xml
+++ b/app/src/main/res/layout/dialog_read_aloud.xml
@@ -221,6 +221,7 @@
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="@string/chapter_list"
+ android:maxLines="1"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
@@ -256,6 +257,7 @@
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="@string/main_menu"
+ android:maxLines="1"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
@@ -291,6 +293,7 @@
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="@string/to_backstage"
+ android:maxLines="1"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
@@ -325,7 +328,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
- android:text="@string/aloud_config"
+ android:text="@string/setting"
+ android:maxLines="1"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
diff --git a/app/src/main/res/layout/dialog_recycler_view.xml b/app/src/main/res/layout/dialog_recycler_view.xml
index 98f67043f..5b1d900a9 100644
--- a/app/src/main/res/layout/dialog_recycler_view.xml
+++ b/app/src/main/res/layout/dialog_recycler_view.xml
@@ -15,7 +15,7 @@
android:id="@+id/recycler_view"
android:background="@color/background_card"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:layout_weight="1" />
diff --git a/app/src/main/res/layout/item_bookshelf_grid.xml b/app/src/main/res/layout/item_bookshelf_grid.xml
index 666d67098..a038fa4fb 100644
--- a/app/src/main/res/layout/item_bookshelf_grid.xml
+++ b/app/src/main/res/layout/item_bookshelf_grid.xml
@@ -48,19 +48,6 @@
tools:ignore="RtlHardcoded" />
-
-
-
@@ -10,7 +11,13 @@
android:id="@+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center" />
+ android:layout_gravity="center"
+ android:orientation="horizontal"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/iv_menu_more"
+ app:layout_constraintRight_toLeftOf="@+id/iv_menu_more"
+ app:layout_constraintBottom_toBottomOf="@+id/iv_menu_more" />
+ android:layout_gravity="center_vertical"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintRight_toRightOf="parent" />
-
+
+
+
diff --git a/app/src/main/res/menu/main_bnv.xml b/app/src/main/res/menu/main_bnv.xml
index a696febe9..9197bec7b 100644
--- a/app/src/main/res/menu/main_bnv.xml
+++ b/app/src/main/res/menu/main_bnv.xml
@@ -4,20 +4,20 @@
tools:showIn="bottom_navigation_view">
+ android:id="@+id/menu_bookshelf"
+ android:icon="@drawable/ic_bottom_books"
+ android:title="@string/bookshelf" />
+ android:id="@+id/menu_find_book"
+ android:icon="@drawable/ic_bottom_explore"
+ android:title="@string/find" />
+ android:id="@+id/menu_rss"
+ android:icon="@drawable/ic_bottom_rss_feed"
+ android:title="@string/rss" />
+ android:id="@+id/menu_my_config"
+ android:icon="@drawable/ic_bottom_person"
+ android:title="@string/my" />
diff --git a/app/src/main/res/menu/main_my.xml b/app/src/main/res/menu/main_my.xml
index db1161c28..74e555dff 100644
--- a/app/src/main/res/menu/main_my.xml
+++ b/app/src/main/res/menu/main_my.xml
@@ -10,16 +10,4 @@
app:showAsAction="always"
tools:ignore="AlwaysShowAction" />
-
-
-
-
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index e8409cf31..7f9b677b9 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/launcher4.xml b/app/src/main/res/mipmap-anydpi-v26/launcher4.xml
new file mode 100644
index 000000000..22463230c
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/launcher4.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
index a7e087bc8..66ab5d53d 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
index f0e9ad532..24f2180fb 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 371e045cd..e7b02cc36 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index feff4e965..b41e4253d 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 63cb54502..5ec228901 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/values/array_values.xml b/app/src/main/res/values/array_values.xml
index c517c46ce..dd0842163 100644
--- a/app/src/main/res/values/array_values.xml
+++ b/app/src/main/res/values/array_values.xml
@@ -6,9 +6,9 @@
- launcher1
- launcher2
- launcher3
+ - launcher4
-
- 0
- 60
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index a53546e7f..cb61d6daa 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -79,6 +79,7 @@
- icon1
- icon2
- icon3
+ - icon4
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 6b7b8e2b1..f7ecf2030 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -6,7 +6,6 @@
176dp
16dp
-
14sp
16sp
18sp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 63efa5aee..41c3005f7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -81,7 +81,7 @@
重试
Web 服务
web编辑书源
- http://%s:%d
+ http://%1$s:%2$d
离线下载
离线下载
下载选择的章节到本地
@@ -207,14 +207,14 @@
替换规则为空或者不满足正则表达式要求
选择操作
全选
- 全选(%d/%d)
- 取消(%d/%d)
+ 全选(%1$d/%2$d)
+ 取消(%1$d/%2$d)
深色模式
启动页
开始下载
取消下载
暂无任务
- 已下载 %d/%d
+ 已下载 %1$d/%2$d
导入选择书籍
更新和搜索线程数,太多会卡顿
切换图标
@@ -225,7 +225,7 @@
内容简介
简介:%s
打开外部书籍
- 来源:%s
+ 来源: %s
本地导入
导入在线规则
检查更新间隔
@@ -289,7 +289,7 @@
右边距
校验书源
校验所选
- 进度 %d/%d
+ 进度 %1$d/%2$d
请安装并选择中文TTS!
TTS初始化失败!
简繁转换
@@ -581,7 +581,7 @@
类型:
文本
音频
- 转到后台
+ 后台
正在导入
正在导出
自定义翻页按键
@@ -599,7 +599,7 @@
夜间模式跟随系统
上级
在线朗读音色
- (%d/%d)
+ (%1$d/%2$d)
显示订阅
服务已停止
正在启动服务\n具体信息查看通知栏
diff --git a/build.gradle b/build.gradle
index 5eb9c16b8..839736b35 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.61'
+ ext.kotlin_version = '1.3.70'
repositories {
google()
jcenter()
@@ -29,4 +29,4 @@ allprojects {
task clean(type: Delete) {
delete rootProject.buildDir
-}
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 23339e0df..667087ef0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
+org.gradle.jvmargs=-Xmx2048m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects