diff --git a/app/build.gradle b/app/build.gradle index f2d9e96cf..7dadb803b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -136,12 +136,12 @@ dependencies { implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" //room - def room_version = '2.2.4' + def room_version = '2.2.5' implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" //paging - implementation 'androidx.paging:paging-runtime:2.1.1' + implementation 'androidx.paging:paging-runtime:2.1.2' //anko def anko_version = '0.10.8' diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index cb38140fe..d767bdc71 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -3,6 +3,14 @@ * 请关注[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 弄了个企业公众号[开源阅读](),后面弄好后会把原来的[开源阅读软件]()迁移过来 +**2020/03/21** +* 详情页点击书名搜索 + +**2020/03/20** +* 自动备份文件和手动备份文件分开 +* 修复一些rss收藏取消不了的bug +* 修复rss请求头无效bug + **2020/03/19** * 美化界面我的 by yangyxd * 优化搜索 diff --git a/app/src/main/java/io/legado/app/data/entities/RssStar.kt b/app/src/main/java/io/legado/app/data/entities/RssStar.kt index 5199b586d..1d0c266f8 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssStar.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssStar.kt @@ -16,4 +16,16 @@ data class RssStar( var description: String? = null, var content: String? = null, var image: String? = null -) \ No newline at end of file +) { + fun toRssArticle(): RssArticle { + return RssArticle( + origin = origin, + title = title, + link = link, + pubDate = pubDate, + description = description, + content = content, + image = image + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 32bc2b765..60d86d6a3 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -21,14 +21,6 @@ object Backup { FileUtils.getDirFile(App.INSTANCE.filesDir, "backup").absolutePath } - val legadoPath by lazy { - FileUtils.getSdCardPath() + File.separator + "YueDu3.0" - } - - val exportPath by lazy { - legadoPath + File.separator + "Export" - } - val backupFileNames by lazy { arrayOf( "bookshelf.json", "bookGroup.json", "bookSource.json", "rssSource.json", @@ -42,16 +34,13 @@ object Backup { return } Coroutine.async { - val backupPath = context.getPrefString(PreferKey.backupPath) - if (backupPath.isNullOrEmpty()) { - backup(context) - } else { - backup(context, backupPath) + context.getPrefString(PreferKey.backupPath)?.let { + backup(context, it, true) } } } - suspend fun backup(context: Context, path: String = legadoPath) { + suspend fun backup(context: Context, path: String, isAuto: Boolean = false) { context.putPrefLong(PreferKey.lastBackup, System.currentTimeMillis()) withContext(IO) { synchronized(this@Backup) { @@ -81,9 +70,9 @@ object Backup { } WebDavHelp.backUpWebDav(backupPath) if (path.isContentPath()) { - copyBackup(context, Uri.parse(path)) + copyBackup(context, Uri.parse(path), isAuto) } else { - copyBackup(File(path)) + copyBackup(File(path), isAuto) } } } @@ -97,28 +86,39 @@ object Backup { } @Throws(java.lang.Exception::class) - private fun copyBackup(context: Context, uri: Uri) { - + private fun copyBackup(context: Context, uri: Uri, isAuto: Boolean) { DocumentFile.fromTreeUri(context, uri)?.let { treeDoc -> for (fileName in backupFileNames) { val file = File(backupPath + File.separator + fileName) if (file.exists()) { - treeDoc.findFile(fileName)?.delete() - treeDoc.createFile("", fileName) - ?.writeBytes(context, file.readBytes()) + if (isAuto) { + treeDoc.findFile("auto")?.findFile(fileName)?.delete() + DocumentUtils.createFileIfNotExist( + treeDoc, + fileName, + subDirs = *arrayOf("auto") + )?.writeBytes(context, file.readBytes()) + } else { + treeDoc.findFile(fileName)?.delete() + treeDoc.createFile("", fileName) + ?.writeBytes(context, file.readBytes()) + } } } } } @Throws(java.lang.Exception::class) - private fun copyBackup(rootFile: File) { + private fun copyBackup(rootFile: File, isAuto: Boolean) { for (fileName in backupFileNames) { val file = File(backupPath + File.separator + fileName) if (file.exists()) { file.copyTo( - FileUtils.createFileIfNotExist(rootFile, fileName), - true + if (isAuto) { + FileUtils.createFileIfNotExist(rootFile, fileName, "auto") + } else { + FileUtils.createFileIfNotExist(rootFile, fileName) + }, true ) } } diff --git a/app/src/main/java/io/legado/app/model/Debug.kt b/app/src/main/java/io/legado/app/model/Debug.kt index 2acd8ac9e..51ae12afd 100644 --- a/app/src/main/java/io/legado/app/model/Debug.kt +++ b/app/src/main/java/io/legado/app/model/Debug.kt @@ -67,7 +67,7 @@ object Debug { if (ruleContent.isNullOrEmpty()) { log(debugSource, "⇒内容规则为空,默认获取整个网页", state = 1000) } else { - rssContentDebug(it.articles[0], ruleContent) + rssContentDebug(it.articles[0], ruleContent, rssSource) } } else { log(debugSource, "⇒存在描述规则,不解析内容页") @@ -80,9 +80,9 @@ object Debug { } } - private fun rssContentDebug(rssArticle: RssArticle, ruleContent: String) { + private fun rssContentDebug(rssArticle: RssArticle, ruleContent: String, rssSource: RssSource) { log(debugSource, "︾开始解析内容页") - Rss.getContent(rssArticle, ruleContent) + Rss.getContent(rssArticle, ruleContent, rssSource) .onSuccess { log(debugSource, it) log(debugSource, "︽内容页解析完成", state = 1000) diff --git a/app/src/main/java/io/legado/app/model/Rss.kt b/app/src/main/java/io/legado/app/model/Rss.kt index b3622b40b..24dadade0 100644 --- a/app/src/main/java/io/legado/app/model/Rss.kt +++ b/app/src/main/java/io/legado/app/model/Rss.kt @@ -21,7 +21,10 @@ object Rss { context: CoroutineContext = Dispatchers.IO ): Coroutine { return Coroutine.async(scope, context) { - val analyzeUrl = AnalyzeUrl(pageUrl ?: rssSource.sourceUrl) + val analyzeUrl = AnalyzeUrl( + pageUrl ?: rssSource.sourceUrl, + headerMapF = rssSource.getHeaderMap() + ) val body = analyzeUrl.getResponseAwait(rssSource.sourceUrl).body RssParserByRule.parseXML(body, rssSource) } @@ -30,12 +33,15 @@ object Rss { fun getContent( rssArticle: RssArticle, ruleContent: String, + rssSource: RssSource?, scope: CoroutineScope = Coroutine.DEFAULT, context: CoroutineContext = Dispatchers.IO ): Coroutine { return Coroutine.async(scope, context) { - val body = AnalyzeUrl(rssArticle.link, baseUrl = rssArticle.origin) - .getResponseAwait(rssArticle.origin) + val body = AnalyzeUrl( + rssArticle.link, baseUrl = rssArticle.origin, + headerMapF = rssSource?.getHeaderMap() + ).getResponseAwait(rssArticle.origin) .body val analyzeRule = AnalyzeRule() analyzeRule.setContent( diff --git a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt index 568615aa1..873b6b3a9 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt @@ -2,6 +2,7 @@ package io.legado.app.model.webBook import io.legado.app.App import io.legado.app.R +import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource @@ -39,7 +40,12 @@ object BookContent { var contentData = analyzeContent( book, baseUrl, body, contentRule, bookChapter, bookSource ) - content.append(contentData.content.replace(bookChapter.title, "")).append("\n") + if (bookSource.bookSourceType == BookType.default) { + content.append(contentData.content.replace(bookChapter.title, "")).append("\n") + } else { + content.append(contentData.content).append("\n") + } + if (contentData.nextUrl.size == 1) { var nextUrl = contentData.nextUrl[0] val nextChapterUrl = if (!nextChapterUrlF.isNullOrEmpty()) diff --git a/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt b/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt index bece64c93..3c960093b 100644 --- a/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt +++ b/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt @@ -46,9 +46,8 @@ class AudioPlayActivity : private var adjustProgress = false override fun onActivityCreated(savedInstanceState: Bundle?) { - setSupportActionBar(toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - AudioPlay.titleData.observe(this, Observer { toolbar.title = it }) + title_bar.transparent() + AudioPlay.titleData.observe(this, Observer { title_bar.title = it }) AudioPlay.coverData.observe(this, Observer { upCover(it) }) viewModel.initData(intent) initView() diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index bd9b3700f..e0b6f275a 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -57,8 +57,7 @@ class BookInfoActivity : get() = getViewModel(BookInfoViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { - setSupportActionBar(toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + title_bar.transparent() viewModel.bookData.observe(this, Observer { showBook(it) }) viewModel.chapterListData.observe(this, Observer { upLoading(false, it) }) viewModel.initData(intent) @@ -231,6 +230,9 @@ class BookInfoActivity : tv_author.onClick { startActivity(Pair("key", viewModel.bookData.value?.author)) } + tv_name.onClick { + startActivity(Pair("key", viewModel.bookData.value?.name)) + } } @SuppressLint("InflateParams") diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index d44efd3ad..c84497536 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -8,7 +8,6 @@ import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.BookSource import io.legado.app.help.http.HttpHelper -import io.legado.app.help.storage.Backup import io.legado.app.help.storage.OldRule import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.utils.* @@ -96,7 +95,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) FileUtils.createFileIfNotExist(file, "exportBookSource.json") .writeText(json) }.onSuccess { - context.toast("成功导出至\n${Backup.exportPath}") + context.toast("成功导出至\n${file.absolutePath}") }.onError { context.toast("导出失败\n${it.localizedMessage}") } @@ -109,7 +108,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) doc.createFile("", "exportBookSource.json") ?.writeText(context, json) }.onSuccess { - context.toast("成功导出至\n${Backup.exportPath}") + context.toast("成功导出至\n${doc.uri.path}") }.onError { context.toast("导出失败\n${it.localizedMessage}") } diff --git a/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt b/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt index 409638a4c..c849ae1de 100644 --- a/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt +++ b/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt @@ -48,30 +48,24 @@ object BackupRestoreUi { selectBackupFolder(fragment, backupSelectRequestCode) } } else { - backupUsePermission(fragment, requestCode = backupSelectRequestCode) + backupUsePermission(fragment, backupPath) } } } private fun backupUsePermission( fragment: Fragment, - path: String = Backup.legadoPath, - requestCode: Int = selectFolderRequestCode + path: String ) { PermissionsCompat.Builder(fragment) .addPermissions(*Permissions.Group.STORAGE) .rationale(R.string.tip_perm_request_storage) .onGranted { - when (requestCode) { - selectFolderRequestCode -> AppConfig.backupPath = Backup.legadoPath - else -> { - Coroutine.async { - AppConfig.backupPath = path - Backup.backup(fragment.requireContext(), path) - }.onSuccess { - fragment.toast(R.string.backup_success) - } - } + Coroutine.async { + AppConfig.backupPath = path + Backup.backup(fragment.requireContext(), path) + }.onSuccess { + fragment.toast(R.string.backup_success) } } .request() @@ -107,7 +101,7 @@ object BackupRestoreUi { } } - private fun restoreUsePermission(fragment: Fragment, path: String = Backup.legadoPath) { + private fun restoreUsePermission(fragment: Fragment, path: String) { PermissionsCompat.Builder(fragment) .addPermissions(*Permissions.Group.STORAGE) .rationale(R.string.tip_perm_request_storage) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index a63d7ea38..7187c6b88 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -8,7 +8,6 @@ import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.http.HttpHelper -import io.legado.app.help.storage.Backup import io.legado.app.help.storage.ImportOldData import io.legado.app.utils.* import org.jetbrains.anko.toast @@ -93,7 +92,7 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application FileUtils.createFileIfNotExist(file, "exportReplaceRule.json") .writeText(json) }.onSuccess { - context.toast("成功导出至\n${Backup.exportPath}") + context.toast("成功导出至\n${file.absolutePath}") }.onError { context.toast("导出失败\n${it.localizedMessage}") } @@ -106,7 +105,7 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application doc.createFile("", "exportReplaceRule.json") ?.writeText(context, json) }.onSuccess { - context.toast("成功导出至\n${Backup.exportPath}") + context.toast("成功导出至\n${doc.uri.path}") }.onError { context.toast("导出失败\n${it.localizedMessage}") } 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 9aa30235b..73c55961b 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 @@ -193,7 +193,7 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r } override fun upStarMenu() { - if (viewModel.star) { + if (viewModel.rssStar != null) { starMenuItem?.setIcon(R.drawable.ic_star) starMenuItem?.setTitle(R.string.in_favorites) } else { 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 fd721e09b..f5b84642f 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 @@ -15,6 +15,7 @@ import io.legado.app.base.BaseViewModel import io.legado.app.constant.AppConst import io.legado.app.data.entities.RssArticle import io.legado.app.data.entities.RssSource +import io.legado.app.data.entities.RssStar import io.legado.app.help.http.HttpHelper import io.legado.app.model.Rss import io.legado.app.model.analyzeRule.AnalyzeUrl @@ -22,6 +23,7 @@ import io.legado.app.utils.DocumentUtils import io.legado.app.utils.FileUtils import io.legado.app.utils.isContentPath import io.legado.app.utils.writeBytes +import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import java.io.File import java.util.* @@ -34,7 +36,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), var rssArticle: RssArticle? = null val contentLiveData = MutableLiveData() val urlLiveData = MutableLiveData() - var star = false + var rssStar: RssStar? = null var textToSpeech: TextToSpeech? = null private var ttsInitFinish = false private var ttsTextList = arrayListOf() @@ -45,8 +47,8 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), val link = intent.getStringExtra("link") if (origin != null && link != null) { rssSource = App.db.rssSourceDao().getByKey(origin) - star = App.db.rssStarDao().get(origin, link) != null - rssArticle = App.db.rssArticleDao().get(origin, link) + rssStar = App.db.rssStarDao().get(origin, link) + rssArticle = rssStar?.toRssArticle() ?: App.db.rssArticleDao().get(origin, link) rssArticle?.let { rssArticle -> if (!rssArticle.description.isNullOrBlank()) { contentLiveData.postValue(rssArticle.description) @@ -78,21 +80,26 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), } private fun loadContent(rssArticle: RssArticle, ruleContent: String) { - Rss.getContent(rssArticle, ruleContent, this) - .onSuccess { - contentLiveData.postValue(it) + Rss.getContent(rssArticle, ruleContent, rssSource, this) + .onSuccess(IO) { body -> + rssArticle.description = body + App.db.rssArticleDao().insert(rssArticle) + rssStar?.let { + it.description = body + App.db.rssStarDao().insert(it) + } + contentLiveData.postValue(body) } } fun favorite() { execute { - rssArticle?.let { - if (star) { - App.db.rssStarDao().delete(it.origin, it.link) - } else { - App.db.rssStarDao().insert(it.toStar()) - } - star = !star + rssStar?.let { + App.db.rssStarDao().delete(it.origin, it.link) + rssStar = null + } ?: rssArticle?.toStar()?.let { + App.db.rssStarDao().insert(it) + rssStar = it } }.onSuccess { callBack?.upStarMenu() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index 82bad9584..300d7468c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -9,7 +9,6 @@ import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssSource import io.legado.app.help.http.HttpHelper -import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.utils.* import org.jetbrains.anko.toast @@ -74,7 +73,7 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) FileUtils.createFileIfNotExist(file, "exportRssSource.json") .writeText(json) }.onSuccess { - context.toast("成功导出至\n${Backup.exportPath}") + context.toast("成功导出至\n${file.absolutePath}") }.onError { context.toast("导出失败\n${it.localizedMessage}") } @@ -87,7 +86,7 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) doc.createFile("", "exportRssSource.json") ?.writeText(context, json) }.onSuccess { - context.toast("成功导出至\n${Backup.exportPath}") + context.toast("成功导出至\n${doc.uri.path}") }.onError { context.toast("导出失败\n${it.localizedMessage}") } diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 663bb55a8..94d3b7be6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.widget import android.content.Context import android.content.res.ColorStateList +import android.graphics.Color import android.util.AttributeSet import android.view.Menu import android.view.View @@ -186,6 +187,11 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a toolbar.setSubtitleTextAppearance(context, resId) } + fun transparent() { + elevation = 0f + backgroundColor = Color.TRANSPARENT + } + private fun attachToActivity() { if (attachToActivity) { activity?.let { diff --git a/app/src/main/res/drawable/ic_help.xml b/app/src/main/res/drawable/ic_help.xml index d5ecd8235..32838437b 100644 --- a/app/src/main/res/drawable/ic_help.xml +++ b/app/src/main/res/drawable/ic_help.xml @@ -1,6 +1,6 @@ - @@ -81,7 +78,8 @@ android:paddingLeft="10dp" android:paddingTop="8dp" android:paddingRight="16dp" - android:paddingBottom="3dp"> + android:paddingBottom="3dp" + tools:ignore="RtlHardcoded"> + android:scrollbars="vertical" + tools:ignore="NestedWeights"> + tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" /> + tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" /> @@ -290,7 +288,7 @@ android:text="@string/group_s" android:textColor="@color/tv_text_summary" android:textSize="13sp" - tools:ignore="NestedWeights" /> + tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" /> + tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" /> + android:background="@color/background" /> - + app:layout_constraintTop_toBottomOf="@+id/title_bar" /> - diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index 922819b1e..3f09664a3 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -18,6 +18,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:maxLines="1" + android:ellipsize="end" android:textSize="12sp" /> @@ -62,7 +66,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:singleLine="true" + android:maxLines="1" + android:ellipsize="end" android:textSize="12sp" />