Merge pull request #33 from gedoor/master

up
pull/379/head
口口吕 5 years ago committed by GitHub
commit 613cb383ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      app/build.gradle
  2. 8
      app/src/main/assets/updateLog.md
  3. 14
      app/src/main/java/io/legado/app/data/entities/RssStar.kt
  4. 48
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  5. 6
      app/src/main/java/io/legado/app/model/Debug.kt
  6. 12
      app/src/main/java/io/legado/app/model/Rss.kt
  7. 8
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  8. 5
      app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt
  9. 6
      app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
  10. 5
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt
  11. 22
      app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt
  12. 5
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt
  13. 2
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  14. 33
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
  15. 5
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt
  16. 6
      app/src/main/java/io/legado/app/ui/widget/TitleBar.kt
  17. 4
      app/src/main/res/drawable/ic_help.xml
  18. 26
      app/src/main/res/layout-land/activity_book_info.xml
  19. 11
      app/src/main/res/layout/activity_audio_play.xml
  20. 7
      app/src/main/res/layout/activity_book_info.xml
  21. 11
      app/src/main/res/layout/view_book_page.xml

@ -136,12 +136,12 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
//room //room
def room_version = '2.2.4' def room_version = '2.2.5'
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version" kapt "androidx.room:room-compiler:$room_version"
//paging //paging
implementation 'androidx.paging:paging-runtime:2.1.1' implementation 'androidx.paging:paging-runtime:2.1.2'
//anko //anko
def anko_version = '0.10.8' def anko_version = '0.10.8'

@ -3,6 +3,14 @@
* 请关注[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 请关注[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
* 弄了个企业公众号[开源阅读](),后面弄好后会把原来的[开源阅读软件]()迁移过来 * 弄了个企业公众号[开源阅读](),后面弄好后会把原来的[开源阅读软件]()迁移过来
**2020/03/21**
* 详情页点击书名搜索
**2020/03/20**
* 自动备份文件和手动备份文件分开
* 修复一些rss收藏取消不了的bug
* 修复rss请求头无效bug
**2020/03/19** **2020/03/19**
* 美化界面我的 by yangyxd * 美化界面我的 by yangyxd
* 优化搜索 * 优化搜索

@ -16,4 +16,16 @@ data class RssStar(
var description: String? = null, var description: String? = null,
var content: String? = null, var content: String? = null,
var image: String? = null var image: String? = null
) ) {
fun toRssArticle(): RssArticle {
return RssArticle(
origin = origin,
title = title,
link = link,
pubDate = pubDate,
description = description,
content = content,
image = image
)
}
}

@ -21,14 +21,6 @@ object Backup {
FileUtils.getDirFile(App.INSTANCE.filesDir, "backup").absolutePath 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 { val backupFileNames by lazy {
arrayOf( arrayOf(
"bookshelf.json", "bookGroup.json", "bookSource.json", "rssSource.json", "bookshelf.json", "bookGroup.json", "bookSource.json", "rssSource.json",
@ -42,16 +34,13 @@ object Backup {
return return
} }
Coroutine.async { Coroutine.async {
val backupPath = context.getPrefString(PreferKey.backupPath) context.getPrefString(PreferKey.backupPath)?.let {
if (backupPath.isNullOrEmpty()) { backup(context, it, true)
backup(context)
} else {
backup(context, backupPath)
} }
} }
} }
suspend fun backup(context: Context, path: String = legadoPath) { suspend fun backup(context: Context, path: String, isAuto: Boolean = false) {
context.putPrefLong(PreferKey.lastBackup, System.currentTimeMillis()) context.putPrefLong(PreferKey.lastBackup, System.currentTimeMillis())
withContext(IO) { withContext(IO) {
synchronized(this@Backup) { synchronized(this@Backup) {
@ -81,9 +70,9 @@ object Backup {
} }
WebDavHelp.backUpWebDav(backupPath) WebDavHelp.backUpWebDav(backupPath)
if (path.isContentPath()) { if (path.isContentPath()) {
copyBackup(context, Uri.parse(path)) copyBackup(context, Uri.parse(path), isAuto)
} else { } else {
copyBackup(File(path)) copyBackup(File(path), isAuto)
} }
} }
} }
@ -97,28 +86,39 @@ object Backup {
} }
@Throws(java.lang.Exception::class) @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 -> DocumentFile.fromTreeUri(context, uri)?.let { treeDoc ->
for (fileName in backupFileNames) { for (fileName in backupFileNames) {
val file = File(backupPath + File.separator + fileName) val file = File(backupPath + File.separator + fileName)
if (file.exists()) { if (file.exists()) {
treeDoc.findFile(fileName)?.delete() if (isAuto) {
treeDoc.createFile("", fileName) treeDoc.findFile("auto")?.findFile(fileName)?.delete()
?.writeBytes(context, file.readBytes()) 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) @Throws(java.lang.Exception::class)
private fun copyBackup(rootFile: File) { private fun copyBackup(rootFile: File, isAuto: Boolean) {
for (fileName in backupFileNames) { for (fileName in backupFileNames) {
val file = File(backupPath + File.separator + fileName) val file = File(backupPath + File.separator + fileName)
if (file.exists()) { if (file.exists()) {
file.copyTo( file.copyTo(
FileUtils.createFileIfNotExist(rootFile, fileName), if (isAuto) {
true FileUtils.createFileIfNotExist(rootFile, fileName, "auto")
} else {
FileUtils.createFileIfNotExist(rootFile, fileName)
}, true
) )
} }
} }

@ -67,7 +67,7 @@ object Debug {
if (ruleContent.isNullOrEmpty()) { if (ruleContent.isNullOrEmpty()) {
log(debugSource, "⇒内容规则为空,默认获取整个网页", state = 1000) log(debugSource, "⇒内容规则为空,默认获取整个网页", state = 1000)
} else { } else {
rssContentDebug(it.articles[0], ruleContent) rssContentDebug(it.articles[0], ruleContent, rssSource)
} }
} else { } else {
log(debugSource, "⇒存在描述规则,不解析内容页") 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, "︾开始解析内容页") log(debugSource, "︾开始解析内容页")
Rss.getContent(rssArticle, ruleContent) Rss.getContent(rssArticle, ruleContent, rssSource)
.onSuccess { .onSuccess {
log(debugSource, it) log(debugSource, it)
log(debugSource, "︽内容页解析完成", state = 1000) log(debugSource, "︽内容页解析完成", state = 1000)

@ -21,7 +21,10 @@ object Rss {
context: CoroutineContext = Dispatchers.IO context: CoroutineContext = Dispatchers.IO
): Coroutine<Result> { ): Coroutine<Result> {
return Coroutine.async(scope, context) { 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 val body = analyzeUrl.getResponseAwait(rssSource.sourceUrl).body
RssParserByRule.parseXML(body, rssSource) RssParserByRule.parseXML(body, rssSource)
} }
@ -30,12 +33,15 @@ object Rss {
fun getContent( fun getContent(
rssArticle: RssArticle, rssArticle: RssArticle,
ruleContent: String, ruleContent: String,
rssSource: RssSource?,
scope: CoroutineScope = Coroutine.DEFAULT, scope: CoroutineScope = Coroutine.DEFAULT,
context: CoroutineContext = Dispatchers.IO context: CoroutineContext = Dispatchers.IO
): Coroutine<String> { ): Coroutine<String> {
return Coroutine.async(scope, context) { return Coroutine.async(scope, context) {
val body = AnalyzeUrl(rssArticle.link, baseUrl = rssArticle.origin) val body = AnalyzeUrl(
.getResponseAwait(rssArticle.origin) rssArticle.link, baseUrl = rssArticle.origin,
headerMapF = rssSource?.getHeaderMap()
).getResponseAwait(rssArticle.origin)
.body .body
val analyzeRule = AnalyzeRule() val analyzeRule = AnalyzeRule()
analyzeRule.setContent( analyzeRule.setContent(

@ -2,6 +2,7 @@ package io.legado.app.model.webBook
import io.legado.app.App import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.BookType
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
@ -39,7 +40,12 @@ object BookContent {
var contentData = analyzeContent( var contentData = analyzeContent(
book, baseUrl, body, contentRule, bookChapter, bookSource 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) { if (contentData.nextUrl.size == 1) {
var nextUrl = contentData.nextUrl[0] var nextUrl = contentData.nextUrl[0]
val nextChapterUrl = if (!nextChapterUrlF.isNullOrEmpty()) val nextChapterUrl = if (!nextChapterUrlF.isNullOrEmpty())

@ -46,9 +46,8 @@ class AudioPlayActivity :
private var adjustProgress = false private var adjustProgress = false
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
setSupportActionBar(toolbar) title_bar.transparent()
supportActionBar?.setDisplayHomeAsUpEnabled(true) AudioPlay.titleData.observe(this, Observer { title_bar.title = it })
AudioPlay.titleData.observe(this, Observer { toolbar.title = it })
AudioPlay.coverData.observe(this, Observer { upCover(it) }) AudioPlay.coverData.observe(this, Observer { upCover(it) })
viewModel.initData(intent) viewModel.initData(intent)
initView() initView()

@ -57,8 +57,7 @@ class BookInfoActivity :
get() = getViewModel(BookInfoViewModel::class.java) get() = getViewModel(BookInfoViewModel::class.java)
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
setSupportActionBar(toolbar) title_bar.transparent()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
viewModel.bookData.observe(this, Observer { showBook(it) }) viewModel.bookData.observe(this, Observer { showBook(it) })
viewModel.chapterListData.observe(this, Observer { upLoading(false, it) }) viewModel.chapterListData.observe(this, Observer { upLoading(false, it) })
viewModel.initData(intent) viewModel.initData(intent)
@ -231,6 +230,9 @@ class BookInfoActivity :
tv_author.onClick { tv_author.onClick {
startActivity<SearchActivity>(Pair("key", viewModel.bookData.value?.author)) startActivity<SearchActivity>(Pair("key", viewModel.bookData.value?.author))
} }
tv_name.onClick {
startActivity<SearchActivity>(Pair("key", viewModel.bookData.value?.name))
}
} }
@SuppressLint("InflateParams") @SuppressLint("InflateParams")

@ -8,7 +8,6 @@ import io.legado.app.App
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.help.http.HttpHelper 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.OldRule
import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.help.storage.Restore.jsonPath
import io.legado.app.utils.* import io.legado.app.utils.*
@ -96,7 +95,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
FileUtils.createFileIfNotExist(file, "exportBookSource.json") FileUtils.createFileIfNotExist(file, "exportBookSource.json")
.writeText(json) .writeText(json)
}.onSuccess { }.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}") context.toast("成功导出至\n${file.absolutePath}")
}.onError { }.onError {
context.toast("导出失败\n${it.localizedMessage}") context.toast("导出失败\n${it.localizedMessage}")
} }
@ -109,7 +108,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
doc.createFile("", "exportBookSource.json") doc.createFile("", "exportBookSource.json")
?.writeText(context, json) ?.writeText(context, json)
}.onSuccess { }.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}") context.toast("成功导出至\n${doc.uri.path}")
}.onError { }.onError {
context.toast("导出失败\n${it.localizedMessage}") context.toast("导出失败\n${it.localizedMessage}")
} }

@ -48,30 +48,24 @@ object BackupRestoreUi {
selectBackupFolder(fragment, backupSelectRequestCode) selectBackupFolder(fragment, backupSelectRequestCode)
} }
} else { } else {
backupUsePermission(fragment, requestCode = backupSelectRequestCode) backupUsePermission(fragment, backupPath)
} }
} }
} }
private fun backupUsePermission( private fun backupUsePermission(
fragment: Fragment, fragment: Fragment,
path: String = Backup.legadoPath, path: String
requestCode: Int = selectFolderRequestCode
) { ) {
PermissionsCompat.Builder(fragment) PermissionsCompat.Builder(fragment)
.addPermissions(*Permissions.Group.STORAGE) .addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage) .rationale(R.string.tip_perm_request_storage)
.onGranted { .onGranted {
when (requestCode) { Coroutine.async {
selectFolderRequestCode -> AppConfig.backupPath = Backup.legadoPath AppConfig.backupPath = path
else -> { Backup.backup(fragment.requireContext(), path)
Coroutine.async { }.onSuccess {
AppConfig.backupPath = path fragment.toast(R.string.backup_success)
Backup.backup(fragment.requireContext(), path)
}.onSuccess {
fragment.toast(R.string.backup_success)
}
}
} }
} }
.request() .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) PermissionsCompat.Builder(fragment)
.addPermissions(*Permissions.Group.STORAGE) .addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage) .rationale(R.string.tip_perm_request_storage)

@ -8,7 +8,6 @@ import io.legado.app.R
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.http.HttpHelper 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.help.storage.ImportOldData
import io.legado.app.utils.* import io.legado.app.utils.*
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@ -93,7 +92,7 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application
FileUtils.createFileIfNotExist(file, "exportReplaceRule.json") FileUtils.createFileIfNotExist(file, "exportReplaceRule.json")
.writeText(json) .writeText(json)
}.onSuccess { }.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}") context.toast("成功导出至\n${file.absolutePath}")
}.onError { }.onError {
context.toast("导出失败\n${it.localizedMessage}") context.toast("导出失败\n${it.localizedMessage}")
} }
@ -106,7 +105,7 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application
doc.createFile("", "exportReplaceRule.json") doc.createFile("", "exportReplaceRule.json")
?.writeText(context, json) ?.writeText(context, json)
}.onSuccess { }.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}") context.toast("成功导出至\n${doc.uri.path}")
}.onError { }.onError {
context.toast("导出失败\n${it.localizedMessage}") context.toast("导出失败\n${it.localizedMessage}")
} }

@ -193,7 +193,7 @@ class ReadRssActivity : VMBaseActivity<ReadRssViewModel>(R.layout.activity_rss_r
} }
override fun upStarMenu() { override fun upStarMenu() {
if (viewModel.star) { if (viewModel.rssStar != null) {
starMenuItem?.setIcon(R.drawable.ic_star) starMenuItem?.setIcon(R.drawable.ic_star)
starMenuItem?.setTitle(R.string.in_favorites) starMenuItem?.setTitle(R.string.in_favorites)
} else { } else {

@ -15,6 +15,7 @@ import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.data.entities.RssArticle import io.legado.app.data.entities.RssArticle
import io.legado.app.data.entities.RssSource 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.help.http.HttpHelper
import io.legado.app.model.Rss import io.legado.app.model.Rss
import io.legado.app.model.analyzeRule.AnalyzeUrl 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.FileUtils
import io.legado.app.utils.isContentPath import io.legado.app.utils.isContentPath
import io.legado.app.utils.writeBytes import io.legado.app.utils.writeBytes
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -34,7 +36,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
var rssArticle: RssArticle? = null var rssArticle: RssArticle? = null
val contentLiveData = MutableLiveData<String>() val contentLiveData = MutableLiveData<String>()
val urlLiveData = MutableLiveData<AnalyzeUrl>() val urlLiveData = MutableLiveData<AnalyzeUrl>()
var star = false var rssStar: RssStar? = null
var textToSpeech: TextToSpeech? = null var textToSpeech: TextToSpeech? = null
private var ttsInitFinish = false private var ttsInitFinish = false
private var ttsTextList = arrayListOf<String>() private var ttsTextList = arrayListOf<String>()
@ -45,8 +47,8 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
val link = intent.getStringExtra("link") val link = intent.getStringExtra("link")
if (origin != null && link != null) { if (origin != null && link != null) {
rssSource = App.db.rssSourceDao().getByKey(origin) rssSource = App.db.rssSourceDao().getByKey(origin)
star = App.db.rssStarDao().get(origin, link) != null rssStar = App.db.rssStarDao().get(origin, link)
rssArticle = App.db.rssArticleDao().get(origin, link) rssArticle = rssStar?.toRssArticle() ?: App.db.rssArticleDao().get(origin, link)
rssArticle?.let { rssArticle -> rssArticle?.let { rssArticle ->
if (!rssArticle.description.isNullOrBlank()) { if (!rssArticle.description.isNullOrBlank()) {
contentLiveData.postValue(rssArticle.description) contentLiveData.postValue(rssArticle.description)
@ -78,21 +80,26 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
} }
private fun loadContent(rssArticle: RssArticle, ruleContent: String) { private fun loadContent(rssArticle: RssArticle, ruleContent: String) {
Rss.getContent(rssArticle, ruleContent, this) Rss.getContent(rssArticle, ruleContent, rssSource, this)
.onSuccess { .onSuccess(IO) { body ->
contentLiveData.postValue(it) rssArticle.description = body
App.db.rssArticleDao().insert(rssArticle)
rssStar?.let {
it.description = body
App.db.rssStarDao().insert(it)
}
contentLiveData.postValue(body)
} }
} }
fun favorite() { fun favorite() {
execute { execute {
rssArticle?.let { rssStar?.let {
if (star) { App.db.rssStarDao().delete(it.origin, it.link)
App.db.rssStarDao().delete(it.origin, it.link) rssStar = null
} else { } ?: rssArticle?.toStar()?.let {
App.db.rssStarDao().insert(it.toStar()) App.db.rssStarDao().insert(it)
} rssStar = it
star = !star
} }
}.onSuccess { }.onSuccess {
callBack?.upStarMenu() callBack?.upStarMenu()

@ -9,7 +9,6 @@ import io.legado.app.R
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssSource
import io.legado.app.help.http.HttpHelper import io.legado.app.help.http.HttpHelper
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.help.storage.Restore.jsonPath
import io.legado.app.utils.* import io.legado.app.utils.*
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@ -74,7 +73,7 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application)
FileUtils.createFileIfNotExist(file, "exportRssSource.json") FileUtils.createFileIfNotExist(file, "exportRssSource.json")
.writeText(json) .writeText(json)
}.onSuccess { }.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}") context.toast("成功导出至\n${file.absolutePath}")
}.onError { }.onError {
context.toast("导出失败\n${it.localizedMessage}") context.toast("导出失败\n${it.localizedMessage}")
} }
@ -87,7 +86,7 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application)
doc.createFile("", "exportRssSource.json") doc.createFile("", "exportRssSource.json")
?.writeText(context, json) ?.writeText(context, json)
}.onSuccess { }.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}") context.toast("成功导出至\n${doc.uri.path}")
}.onError { }.onError {
context.toast("导出失败\n${it.localizedMessage}") context.toast("导出失败\n${it.localizedMessage}")
} }

@ -2,6 +2,7 @@ package io.legado.app.ui.widget
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color
import android.util.AttributeSet import android.util.AttributeSet
import android.view.Menu import android.view.Menu
import android.view.View import android.view.View
@ -186,6 +187,11 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a
toolbar.setSubtitleTextAppearance(context, resId) toolbar.setSubtitleTextAppearance(context, resId)
} }
fun transparent() {
elevation = 0f
backgroundColor = Color.TRANSPARENT
}
private fun attachToActivity() { private fun attachToActivity() {
if (attachToActivity) { if (attachToActivity) {
activity?.let { activity?.let {

@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp" android:width="24dp"
android:height="22dp" android:height="24dp"
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <path

@ -14,13 +14,10 @@
android:contentDescription="@string/bg_image" android:contentDescription="@string/bg_image"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.Toolbar <io.legado.app.ui.widget.TitleBar
android:id="@+id/toolbar" android:id="@+id/title_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle"
android:fitsSystemWindows="true"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:title="@string/book_info" /> app:title="@string/book_info" />
@ -81,7 +78,8 @@
android:paddingLeft="10dp" android:paddingLeft="10dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:paddingBottom="3dp"> android:paddingBottom="3dp"
tools:ignore="RtlHardcoded">
<TextView <TextView
android:id="@+id/tv_name" android:id="@+id/tv_name"
@ -147,14 +145,13 @@
android:layout_weight="1.0" android:layout_weight="1.0"
android:orientation="vertical" android:orientation="vertical"
android:layout_marginTop="65dp" android:layout_marginTop="65dp"
android:layout_marginLeft="1px"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:background="@color/background" android:background="@color/background"
android:fillViewport="true" android:fillViewport="true"
@ -162,7 +159,8 @@
android:focusable="true" android:focusable="true"
android:padding="0dp" android:padding="0dp"
android:scrollbarStyle="outsideInset" android:scrollbarStyle="outsideInset"
android:scrollbars="vertical"> android:scrollbars="vertical"
tools:ignore="NestedWeights">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -212,7 +210,7 @@
android:text="@string/origin_format" android:text="@string/origin_format"
android:textColor="@color/tv_text_summary" android:textColor="@color/tv_text_summary"
android:textSize="13sp" android:textSize="13sp"
tools:ignore="NestedWeights" /> tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" />
<io.legado.app.ui.widget.text.AccentBgTextView <io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_change_source" android:id="@+id/tv_change_source"
@ -257,7 +255,7 @@
android:text="@string/read_dur_progress" android:text="@string/read_dur_progress"
android:textColor="@color/tv_text_summary" android:textColor="@color/tv_text_summary"
android:textSize="13sp" android:textSize="13sp"
tools:ignore="NestedWeights" /> tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" />
</LinearLayout> </LinearLayout>
@ -290,7 +288,7 @@
android:text="@string/group_s" android:text="@string/group_s"
android:textColor="@color/tv_text_summary" android:textColor="@color/tv_text_summary"
android:textSize="13sp" android:textSize="13sp"
tools:ignore="NestedWeights" /> tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" />
<io.legado.app.ui.widget.text.AccentBgTextView <io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_change_group" android:id="@+id/tv_change_group"
@ -334,7 +332,7 @@
android:text="@string/toc_s" android:text="@string/toc_s"
android:textColor="@color/tv_text_summary" android:textColor="@color/tv_text_summary"
android:textSize="13sp" android:textSize="13sp"
tools:ignore="NestedWeights" /> tools:ignore="NestedWeights,RtlHardcoded,RtlSymmetry" />
<io.legado.app.ui.widget.text.AccentBgTextView <io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_toc_view" android:id="@+id/tv_toc_view"
@ -373,7 +371,7 @@
android:layout_marginBottom="1px" android:layout_marginBottom="1px"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="8dp" android:layout_height="8dp"
android:background="@color/background"></View> android:background="@color/background" />
<LinearLayout <LinearLayout
android:id="@+id/fl_action" android:id="@+id/fl_action"

@ -21,13 +21,10 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#50000000" /> android:background="#50000000" />
<androidx.appcompat.widget.Toolbar <io.legado.app.ui.widget.TitleBar
android:id="@+id/toolbar" android:id="@+id/title_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle"
android:fitsSystemWindows="true"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
@ -40,7 +37,7 @@
android:paddingStart="3dp" android:paddingStart="3dp"
android:paddingEnd="3dp" android:paddingEnd="3dp"
android:visibility="invisible" android:visibility="invisible"
app:layout_constraintTop_toBottomOf="@id/toolbar" app:layout_constraintTop_toBottomOf="@id/title_bar"
app:layout_constraintRight_toRightOf="parent" /> app:layout_constraintRight_toRightOf="parent" />
<io.legado.app.ui.widget.image.CircleImageView <io.legado.app.ui.widget.image.CircleImageView
@ -54,7 +51,7 @@
app:layout_constraintBottom_toTopOf="@+id/ll_player_progress" app:layout_constraintBottom_toTopOf="@+id/ll_player_progress"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" /> app:layout_constraintTop_toBottomOf="@+id/title_bar" />
<TextView <TextView
android:id="@+id/tv_sub_title" android:id="@+id/tv_sub_title"

@ -21,13 +21,10 @@
android:background="#50000000" android:background="#50000000"
android:orientation="vertical"> android:orientation="vertical">
<androidx.appcompat.widget.Toolbar <io.legado.app.ui.widget.TitleBar
android:id="@+id/toolbar" android:id="@+id/title_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle"
android:fitsSystemWindows="true"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:title="@string/book_info" /> app:title="@string/book_info" />

@ -18,6 +18,8 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:maxLines="1"
android:ellipsize="end"
android:textSize="12sp" /> android:textSize="12sp" />
<TextView <TextView
@ -26,6 +28,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="3dp" android:layout_marginLeft="3dp"
android:textSize="12sp" android:textSize="12sp"
android:maxLines="1"
android:ellipsize="end"
tools:ignore="RtlHardcoded,RtlSymmetry" /> tools:ignore="RtlHardcoded,RtlSymmetry" />
</LinearLayout> </LinearLayout>
@ -62,7 +66,8 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:singleLine="true" android:maxLines="1"
android:ellipsize="end"
android:textSize="12sp" /> android:textSize="12sp" />
<TextView <TextView
@ -71,6 +76,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="3dp" android:layout_marginLeft="3dp"
android:textSize="12sp" android:textSize="12sp"
android:maxLines="1"
android:ellipsize="end"
tools:ignore="RtlHardcoded,RtlSymmetry" /> tools:ignore="RtlHardcoded,RtlSymmetry" />
<io.legado.app.ui.widget.BatteryView <io.legado.app.ui.widget.BatteryView
@ -79,6 +86,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="3dp" android:layout_marginLeft="3dp"
android:textSize="10sp" android:textSize="10sp"
android:maxLines="1"
android:ellipsize="end"
tools:ignore="RtlHardcoded,RtlSymmetry,SmallSp" /> tools:ignore="RtlHardcoded,RtlSymmetry,SmallSp" />
</LinearLayout> </LinearLayout>

Loading…
Cancel
Save