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