Merge pull request #1 from gedoor/master

merge
pull/59/head
Celeter 5 years ago committed by GitHub
commit 0068765022
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      app/build.gradle
  2. 14
      app/src/main/assets/readConfig.json
  3. 15
      app/src/main/assets/updateLog.md
  4. 6
      app/src/main/java/io/legado/app/App.kt
  5. 1
      app/src/main/java/io/legado/app/constant/Bus.kt
  6. 3
      app/src/main/java/io/legado/app/constant/PreferKey.kt
  7. 4
      app/src/main/java/io/legado/app/help/CrashHandler.kt
  8. 2
      app/src/main/java/io/legado/app/help/FileHelp.kt
  9. 11
      app/src/main/java/io/legado/app/help/IntentHelp.kt
  10. 7
      app/src/main/java/io/legado/app/help/permission/Permissions.kt
  11. 20
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  12. 19
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  13. 7
      app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt
  14. 7
      app/src/main/java/io/legado/app/service/WebService.kt
  15. 41
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt
  16. 10
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt
  17. 2
      app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt
  18. 73
      app/src/main/java/io/legado/app/ui/changecover/ChangeCoverDialog.kt
  19. 12
      app/src/main/java/io/legado/app/ui/changecover/ChangeCoverViewModel.kt
  20. 25
      app/src/main/java/io/legado/app/ui/changecover/CoverAdapter.kt
  21. 2
      app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt
  22. 15
      app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt
  23. 14
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  24. 88
      app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt
  25. 21
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  26. 17
      app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt
  27. 5
      app/src/main/java/io/legado/app/ui/widget/page/PageView.kt
  28. 8
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  29. 40
      app/src/main/res/layout/item_cover.xml
  30. 4
      app/src/main/res/values/strings.xml
  31. 2
      app/src/main/res/xml/about.xml
  32. 4
      app/src/main/res/xml/pref_config.xml
  33. 9
      app/src/main/res/xml/pref_config_theme.xml
  34. 4
      app/src/main/res/xml/pref_config_web_dav.xml
  35. 2
      build.gradle

@ -14,7 +14,7 @@ static def releaseTime() {
} }
def name = "legado" def name = "legado"
def version = "0." + releaseTime() def version = "3." + releaseTime()
def gitCommits = Integer.parseInt('git rev-list --count HEAD'.execute([], project.rootDir).text.trim()) def gitCommits = Integer.parseInt('git rev-list --count HEAD'.execute([], project.rootDir).text.trim())
android { android {

@ -4,7 +4,7 @@
"bgType": 1, "bgType": 1,
"darkStatusIcon": true, "darkStatusIcon": true,
"textColor": "#5E432E", "textColor": "#5E432E",
"textSize": 22, "textSize": 24,
"letterSpacing": 0, "letterSpacing": 0,
"lineSpacingExtra": 10, "lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2, "lineSpacingMultiplier": 1.2,
@ -14,11 +14,11 @@
"paddingBottom": 0 "paddingBottom": 0
}, },
{ {
"bgStr": "新羊皮纸.jpg", "bgStr": "#C6BAA1",
"bgType": 1, "bgType": 0,
"darkStatusIcon": true, "darkStatusIcon": true,
"textColor": "#5E432E", "textColor": "#5E432E",
"textSize": 22, "textSize": 24,
"letterSpacing": 0, "letterSpacing": 0,
"lineSpacingExtra": 10, "lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2, "lineSpacingMultiplier": 1.2,
@ -32,7 +32,7 @@
"bgType": 0, "bgType": 0,
"darkStatusIcon": false, "darkStatusIcon": false,
"textColor": "#FFFFFF", "textColor": "#FFFFFF",
"textSize": 22, "textSize": 24,
"letterSpacing": 0, "letterSpacing": 0,
"lineSpacingExtra": 10, "lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2, "lineSpacingMultiplier": 1.2,
@ -46,7 +46,7 @@
"bgType": 1, "bgType": 1,
"darkStatusIcon": false, "darkStatusIcon": false,
"textColor": "#adadad", "textColor": "#adadad",
"textSize": 22, "textSize": 24,
"letterSpacing": 0, "letterSpacing": 0,
"lineSpacingExtra": 10, "lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2, "lineSpacingMultiplier": 1.2,
@ -60,7 +60,7 @@
"bgType": 0, "bgType": 0,
"darkStatusIcon": false, "darkStatusIcon": false,
"textColor": "#adadad", "textColor": "#adadad",
"textSize": 22, "textSize": 24,
"letterSpacing": 0, "letterSpacing": 0,
"lineSpacingExtra": 10, "lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2, "lineSpacingMultiplier": 1.2,

@ -1,11 +1,20 @@
## 更新日志 ## 更新日志
* 旧版数据导入教程: * 旧版数据导入教程:
* 先在旧版阅读2.19.xxxxxx进行备份,再在新版阅读3.0的【我的】中,点击【备份与恢复】,选择【导入旧版本数据】,提示存储权限,选择允许即可导入成功。 * 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】,提示存储权限,选择允许即可导入成功。
* 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。 * 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。
**2019/12/12**
* [fix]web服务停止问题
* 默认显示沉浸式状态栏
**2019/12/09**
* [add]其他设置->清理缓存
* [mod]调整深色模式配色,预适配Android10
* [mod]启用web服务
**2019/12/03** **2019/12/03**
* from Celeter1、调试log修改 2、增加书源字符串分享(RSS未包含) 3、增加导出选中的源(包含书源、RSS、替换规则) * [by Celeter]1、调试log修改 2、增加书源字符串分享(RSS未包含) 3、增加导出选中的源(包含书源、RSS、替换规则)
* 一键缓存 * 一键缓存
* 修复bug * 修复bug
@ -15,4 +24,4 @@
* 音频添加速度调整 * 音频添加速度调整
* 后台朗读,长按返回,或点击按钮 * 后台朗读,长按返回,或点击按钮
* 订阅可以隐藏 * 订阅可以隐藏
* 优化老版本规则导入from Celeter * [by Celeter]优化老版本规则导入

@ -70,13 +70,13 @@ class App : Application() {
if (isNightTheme) { if (isNightTheme) {
ThemeStore.editTheme(this) ThemeStore.editTheme(this)
.primaryColor( .primaryColor(
getPrefInt("colorPrimaryNight", getCompatColor(R.color.md_blue_grey_600)) getPrefInt("colorPrimaryNight", getCompatColor(R.color.md_grey_900))
) )
.accentColor( .accentColor(
getPrefInt("colorAccentNight", getCompatColor(R.color.md_deep_orange_800)) getPrefInt("colorAccentNight", getCompatColor(R.color.md_deep_orange_800))
) )
.backgroundColor( .backgroundColor(
getPrefInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800)) getPrefInt("colorBackgroundNight", getCompatColor(R.color.md_black_1000))
) )
.apply() .apply()
} else { } else {
@ -101,7 +101,6 @@ class App : Application() {
initNightTheme() initNightTheme()
} }
private fun initNightTheme() { private fun initNightTheme() {
val targetMode = if (isNightTheme) { val targetMode = if (isNightTheme) {
AppCompatDelegate.MODE_NIGHT_YES AppCompatDelegate.MODE_NIGHT_YES
@ -111,7 +110,6 @@ class App : Application() {
AppCompatDelegate.setDefaultNightMode(targetMode) AppCompatDelegate.setDefaultNightMode(targetMode)
} }
/** /**
* 创建通知ID * 创建通知ID
*/ */

@ -17,4 +17,5 @@ object Bus {
const val AUDIO_PROGRESS = "audioProgress" const val AUDIO_PROGRESS = "audioProgress"
const val AUDIO_SIZE = "audioSize" const val AUDIO_SIZE = "audioSize"
const val AUDIO_SPEED = "audioSpeed" const val AUDIO_SPEED = "audioSpeed"
const val SHOW_RSS = "showRss"
} }

@ -10,4 +10,7 @@ object PreferKey {
const val nextKey = "nextKeyCode" const val nextKey = "nextKeyCode"
const val showRss = "showRss" const val showRss = "showRss"
const val bookshelfLayout = "bookshelfLayout" const val bookshelfLayout = "bookshelfLayout"
const val recordLog = "recordLog"
const val processText = "process_text"
const val cleanCache = "cleanCache"
} }

@ -103,7 +103,9 @@ class CrashHandler : Thread.UncaughtExceptionHandler {
kotlin.runCatching { kotlin.runCatching {
for (field in fields) { for (field in fields) {
field.isAccessible = true field.isAccessible = true
paramsMap[field.name] = field.get(null).toString() field.get(null)?.toString()?.let {
paramsMap[field.name] = it
}
} }
} }
} }

@ -47,7 +47,7 @@ object FileHelp {
if (file.isDirectory) { if (file.isDirectory) {
val files = file.listFiles() val files = file.listFiles()
for (subFile in files) { files?.forEach { subFile ->
val path = subFile.path val path = subFile.path
deleteFile(path) deleteFile(path)
} }

@ -21,6 +21,17 @@ object IntentHelp {
} }
} }
fun toInstallUnknown(context: Context) {
try {
val intent = Intent()
intent.action = "android.settings.MANAGE_UNKNOWN_APP_SOURCES"
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
} catch (ignored: Exception) {
context.toast("无法打开设置")
}
}
inline fun <reified T> servicePendingIntent(context: Context, action: String): PendingIntent? { inline fun <reified T> servicePendingIntent(context: Context, action: String): PendingIntent? {
return PendingIntent.getService( return PendingIntent.getService(
context, context,

@ -36,10 +36,12 @@ object Permissions {
const val WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE" const val WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"
object Group { object Group {
val CALENDAR = arrayOf(READ_CALENDAR, WRITE_CALENDAR) val STORAGE = arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE)
val CAMERA = arrayOf(Permissions.CAMERA) val CAMERA = arrayOf(Permissions.CAMERA)
val CALENDAR = arrayOf(READ_CALENDAR, WRITE_CALENDAR)
val CONTACTS = arrayOf(READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS) val CONTACTS = arrayOf(READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS)
val LOCATION = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION) val LOCATION = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
@ -65,8 +67,5 @@ object Permissions {
RECEIVE_WAP_PUSH, RECEIVE_WAP_PUSH,
RECEIVE_MMS RECEIVE_MMS
) )
val STORAGE = arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE)
} }
} }

@ -20,16 +20,14 @@ object Backup {
} }
val legadoPath by lazy { val legadoPath by lazy {
defaultPath + File.separator + "legadoBackUp" FileUtils.getSdCardPath() + File.separator + "YueDu3.0"
} }
val exportPath by lazy { val exportPath by lazy {
legadoPath + File.separator + "Export" legadoPath + File.separator + "Export"
} }
fun backup() { private fun pbackup(path :String = legadoPath){
doAsync {
val path = legadoPath
backupBookshelf(path) backupBookshelf(path)
backupBookSource(path) backupBookSource(path)
backupRssSource(path) backupRssSource(path)
@ -37,6 +35,11 @@ object Backup {
backupReadConfig(path) backupReadConfig(path)
backupPreference(path) backupPreference(path)
WebDavHelp.backUpWebDav(path) WebDavHelp.backUpWebDav(path)
}
fun backup() {
doAsync {
pbackup()
uiThread { uiThread {
App.INSTANCE.toast(R.string.backup_success) App.INSTANCE.toast(R.string.backup_success)
} }
@ -45,14 +48,7 @@ object Backup {
fun autoBackup() { fun autoBackup() {
doAsync { doAsync {
val path = legadoPath pbackup()
backupBookshelf(path)
backupBookSource(path)
backupRssSource(path)
backupReplaceRule(path)
backupReadConfig(path)
backupPreference(path)
WebDavHelp.backUpWebDav(path)
} }
} }

@ -7,6 +7,7 @@ import com.jayway.jsonpath.JsonPath
import com.jayway.jsonpath.Option import com.jayway.jsonpath.Option
import com.jayway.jsonpath.ParseContext import com.jayway.jsonpath.ParseContext
import io.legado.app.App import io.legado.app.App
import io.legado.app.R
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
@ -14,8 +15,6 @@ import io.legado.app.data.entities.ReplaceRule
import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssSource
import io.legado.app.help.FileHelp import io.legado.app.help.FileHelp
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.help.storage.Backup.defaultPath
import io.legado.app.help.storage.Backup.legadoPath
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
@ -37,7 +36,7 @@ object Restore {
) )
} }
fun restore(path: String = legadoPath) { fun restore(path: String = Backup.legadoPath) {
doAsync { doAsync {
try { try {
val file = FileHelp.getFile(path + File.separator + "bookshelf.json") val file = FileHelp.getFile(path + File.separator + "bookshelf.json")
@ -99,14 +98,14 @@ object Restore {
} }
edit.commit() edit.commit()
} }
uiThread { App.INSTANCE.toast("恢复完成") } uiThread { App.INSTANCE.toast(R.string.restore_success) }
} }
} }
fun importYueDuData(context: Context) { fun importYueDuData(context: Context) {
GlobalScope.launch(IO) { GlobalScope.launch(IO) {
try {// 导入书架 try {// 导入书架
val shelfFile = FileHelp.getFile(defaultPath + File.separator + "myBookShelf.json") val shelfFile = FileHelp.getFile(Backup.defaultPath + File.separator + "myBookShelf.json")
val books = mutableListOf<Book>() val books = mutableListOf<Book>()
val items: List<Map<String, Any>> = jsonPath.parse(shelfFile.readText()).read("$") val items: List<Map<String, Any>> = jsonPath.parse(shelfFile.readText()).read("$")
val existingBooks = App.db.bookDao().allBookUrls.toSet() val existingBooks = App.db.bookDao().allBookUrls.toSet()
@ -149,12 +148,14 @@ object Restore {
context.toast("成功导入书籍${books.size}") context.toast("成功导入书籍${books.size}")
} }
} catch (e: Exception) { } catch (e: Exception) {
withContext(Main) {
context.toast("导入书籍失败\n${e.localizedMessage}") context.toast("导入书籍失败\n${e.localizedMessage}")
} }
}
try {// Book source try {// Book source
val sourceFile = val sourceFile =
FileHelp.getFile(defaultPath + File.separator + "myBookSource.json") FileHelp.getFile(Backup.defaultPath + File.separator + "myBookSource.json")
val bookSources = mutableListOf<BookSource>() val bookSources = mutableListOf<BookSource>()
val items: List<Map<String, Any>> = jsonPath.parse(sourceFile.readText()).read("$") val items: List<Map<String, Any>> = jsonPath.parse(sourceFile.readText()).read("$")
for (item in items) { for (item in items) {
@ -168,12 +169,14 @@ object Restore {
context.toast("成功导入书源${bookSources.size}") context.toast("成功导入书源${bookSources.size}")
} }
} catch (e: Exception) { } catch (e: Exception) {
withContext(Main) {
context.toast("导入源失败\n${e.localizedMessage}") context.toast("导入源失败\n${e.localizedMessage}")
} }
}
try {// Replace rules try {// Replace rules
val ruleFile = val ruleFile =
FileHelp.getFile(defaultPath + File.separator + "myBookReplaceRule.json") FileHelp.getFile(Backup.defaultPath + File.separator + "myBookReplaceRule.json")
val replaceRules = mutableListOf<ReplaceRule>() val replaceRules = mutableListOf<ReplaceRule>()
val items: List<Map<String, Any>> = jsonPath.parse(ruleFile.readText()).read("$") val items: List<Map<String, Any>> = jsonPath.parse(ruleFile.readText()).read("$")
val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet()
@ -196,8 +199,10 @@ object Restore {
context.toast("成功导入替换规则${replaceRules.size}") context.toast("成功导入替换规则${replaceRules.size}")
} }
} catch (e: Exception) { } catch (e: Exception) {
withContext(Main) {
context.toast("导入替换规则失败\n${e.localizedMessage}") context.toast("导入替换规则失败\n${e.localizedMessage}")
} }
} }
} }
} }
}

@ -18,6 +18,9 @@ import kotlin.math.min
object WebDavHelp { object WebDavHelp {
private val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip" private val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip"
private val unzipFilesPath by lazy {
FileHelp.getCachePath()
}
private fun getWebDavUrl(): String? { private fun getWebDavUrl(): String? {
var url = App.INSTANCE.getPrefString("web_dav_url") var url = App.INSTANCE.getPrefString("web_dav_url")
@ -73,8 +76,8 @@ object WebDavHelp {
getWebDavUrl()?.let { getWebDavUrl()?.let {
val file = WebDav(it + "legado/" + name) val file = WebDav(it + "legado/" + name)
file.downloadTo(zipFilePath, true) file.downloadTo(zipFilePath, true)
ZipUtils.unzipFile(zipFilePath, Backup.legadoPath) ZipUtils.unzipFile(zipFilePath, unzipFilesPath)
Restore.restore() Restore.restore(unzipFilesPath)
} }
} }
} }

@ -34,7 +34,6 @@ class WebService : BaseService() {
context.startService(intent) context.startService(intent)
} }
} }
} }
private var httpServer: HttpServer? = null private var httpServer: HttpServer? = null
@ -49,6 +48,12 @@ class WebService : BaseService() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
isRun = false isRun = false
if (httpServer?.isAlive == true) {
httpServer?.stop()
}
if (webSocketServer?.isAlive == true) {
webSocketServer?.stop()
}
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

@ -8,12 +8,15 @@ import androidx.lifecycle.Observer
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.help.ImageLoader
import io.legado.app.ui.changecover.ChangeCoverDialog
import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_book_info_edit.* import kotlinx.android.synthetic.main.activity_book_info_edit.*
import org.jetbrains.anko.toast import org.jetbrains.anko.sdk27.listeners.onClick
class BookInfoEditActivity : class BookInfoEditActivity :
VMBaseActivity<BookInfoEditViewModel>(R.layout.activity_book_info_edit) { VMBaseActivity<BookInfoEditViewModel>(R.layout.activity_book_info_edit),
ChangeCoverDialog.CallBack {
override val viewModel: BookInfoEditViewModel override val viewModel: BookInfoEditViewModel
get() = getViewModel(BookInfoEditViewModel::class.java) get() = getViewModel(BookInfoEditViewModel::class.java)
@ -24,6 +27,7 @@ class BookInfoEditActivity :
viewModel.loadBook(it) viewModel.loadBook(it)
} }
} }
initEvent()
} }
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
@ -38,28 +42,47 @@ class BookInfoEditActivity :
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
} }
private fun initEvent() {
tv_change_cover.onClick {
viewModel.bookData.value?.let {
ChangeCoverDialog.show(supportFragmentManager, it.name, it.author)
}
}
}
private fun upView(book: Book) { private fun upView(book: Book) {
tie_book_name.setText(book.name) tie_book_name.setText(book.name)
tie_book_author.setText(book.author) tie_book_author.setText(book.author)
tie_cover_url.setText(book.getDisplayCover()) tie_cover_url.setText(book.getDisplayCover())
tie_book_intro.setText(book.getDisplayIntro()) tie_book_intro.setText(book.getDisplayIntro())
upCover()
}
private fun upCover() {
viewModel.book?.getDisplayCover()?.let {
ImageLoader.load(this, it)
.centerCrop()
.into(iv_cover)
}
} }
private fun saveData() { private fun saveData() {
viewModel.bookData.value?.let { book -> viewModel.book?.let { book ->
book.name = tie_book_name.text?.toString() ?: "" book.name = tie_book_name.text?.toString() ?: ""
book.author = tie_book_author.text?.toString() ?: "" book.author = tie_book_author.text?.toString() ?: ""
val customCoverUrl = tie_cover_url.text?.toString() val customCoverUrl = tie_cover_url.text?.toString()
book.customCoverUrl = if (customCoverUrl == book.coverUrl) null else customCoverUrl book.customCoverUrl = if (customCoverUrl == book.coverUrl) null else customCoverUrl
book.customIntro = tie_book_intro.text?.toString() book.customIntro = tie_book_intro.text?.toString()
viewModel.saveBook(book, viewModel.saveBook(book) {
success = {
setResult(Activity.RESULT_OK) setResult(Activity.RESULT_OK)
finish() finish()
},
error = {
toast(it)
})
} }
} }
} }
override fun coverChangeTo(coverUrl: String) {
viewModel.book?.customCoverUrl = coverUrl
tie_cover_url.setText(coverUrl)
upCover()
}
}

@ -7,25 +7,23 @@ import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
class BookInfoEditViewModel(application: Application) : BaseViewModel(application) { class BookInfoEditViewModel(application: Application) : BaseViewModel(application) {
var book: Book? = null
val bookData = MutableLiveData<Book>() val bookData = MutableLiveData<Book>()
fun loadBook(bookUrl: String) { fun loadBook(bookUrl: String) {
execute { execute {
App.db.bookDao().getBook(bookUrl)?.let { book = App.db.bookDao().getBook(bookUrl)
book?.let {
bookData.postValue(it) bookData.postValue(it)
} }
} }
} }
fun saveBook(book: Book, success: (() -> Unit)?, error: ((msg: String) -> Unit)?) { fun saveBook(book: Book, success: (() -> Unit)?) {
execute { execute {
App.db.bookDao().insert(book) App.db.bookDao().insert(book)
}.onSuccess { }.onSuccess {
success?.invoke() success?.invoke()
}.onError {
error?.invoke(it.localizedMessage)
} }
} }
} }

@ -182,7 +182,7 @@ class ReadStyleDialog : DialogFragment() {
requireContext().putPrefInt("pageAnim", i) requireContext().putPrefInt("pageAnim", i)
val activity = activity val activity = activity
if (activity is ReadBookActivity) { if (activity is ReadBookActivity) {
activity.page_view.upPageAnim() activity.page_view.upPageAnim(i)
} }
break break
} }

@ -0,0 +1,73 @@
package io.legado.app.ui.changecover
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.GridLayoutManager
import io.legado.app.R
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.dialog_change_source.*
class ChangeCoverDialog : DialogFragment() {
companion object {
const val tag = "changeCoverDialog"
fun show(manager: FragmentManager, name: String, author: String) {
val fragment = (manager.findFragmentByTag(tag) as? ChangeCoverDialog)
?: ChangeCoverDialog().apply {
val bundle = Bundle()
bundle.putString("name", name)
bundle.putString("author", author)
arguments = bundle
}
fragment.show(manager, tag)
}
}
private var callBack: CallBack? = null
private lateinit var viewModel: ChangeCoverViewModel
private lateinit var adapter: CoverAdapter
override fun onStart() {
super.onStart()
val dm = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel = getViewModel(ChangeCoverViewModel::class.java)
return inflater.inflate(R.layout.dialog_change_source, container)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
callBack = activity as? CallBack
tool_bar.setTitle(R.string.change_cover_source)
arguments?.let { bundle ->
bundle.getString("name")?.let {
viewModel.name = it
}
bundle.getString("author")?.let {
viewModel.author = it
}
}
recycler_view.layoutManager = GridLayoutManager(requireContext(), 3)
adapter = CoverAdapter(requireContext())
recycler_view.adapter = adapter
}
interface CallBack {
fun coverChangeTo(coverUrl: String)
}
}

@ -0,0 +1,12 @@
package io.legado.app.ui.changecover
import android.app.Application
import io.legado.app.base.BaseViewModel
class ChangeCoverViewModel(application: Application) : BaseViewModel(application) {
var name: String = ""
var author: String = ""
}

@ -0,0 +1,25 @@
package io.legado.app.ui.changecover
import android.content.Context
import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.SimpleRecyclerAdapter
import io.legado.app.data.entities.SearchBook
import io.legado.app.help.ImageLoader
import kotlinx.android.synthetic.main.item_cover.view.*
class CoverAdapter(context: Context) :
SimpleRecyclerAdapter<SearchBook>(context, R.layout.item_cover) {
override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList<Any>) {
with(holder.itemView) {
item.coverUrl?.let {
ImageLoader.load(context, it)
.centerCrop()
.into(iv_cover)
}
tv_source.text = item.originName
}
}
}

@ -19,7 +19,7 @@ class ConfigActivity : VMBaseActivity<ConfigViewModel>(R.layout.activity_config)
when (viewModel.configType) { when (viewModel.configType) {
ConfigViewModel.TYPE_CONFIG -> { ConfigViewModel.TYPE_CONFIG -> {
title_bar.title = getString(R.string.setting) title_bar.title = getString(R.string.other_setting)
val fTag = "configFragment" val fTag = "configFragment"
var configFragment = supportFragmentManager.findFragmentByTag(fTag) var configFragment = supportFragmentManager.findFragmentByTag(fTag)
if (configFragment == null) configFragment = ConfigFragment() if (configFragment == null) configFragment = ConfigFragment()

@ -10,8 +10,10 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
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.Bus
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.FileHelp
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.receiver.SharedReceiverActivity import io.legado.app.receiver.SharedReceiverActivity
import io.legado.app.ui.filechooser.FileChooserDialog import io.legado.app.ui.filechooser.FileChooserDialog
@ -59,6 +61,13 @@ class ConfigFragment : PreferenceFragmentCompat(),
mode = FileChooserDialog.DIRECTORY, mode = FileChooserDialog.DIRECTORY,
initPath = getPreferenceString(PreferKey.downloadPath) initPath = getPreferenceString(PreferKey.downloadPath)
) )
PreferKey.cleanCache -> {
getPreferenceString(PreferKey.downloadPath).let {
FileHelp.deleteFile(it)
FileHelp.getFolder(it)
}
toast(R.string.clear_cache_success)
}
} }
return super.onPreferenceTreeClick(preference) return super.onPreferenceTreeClick(preference)
} }
@ -69,11 +78,11 @@ class ConfigFragment : PreferenceFragmentCompat(),
BookHelp.upDownloadPath() BookHelp.upDownloadPath()
findPreference<Preference>(key)?.summary = getPreferenceString(key) findPreference<Preference>(key)?.summary = getPreferenceString(key)
} }
"recordLog" -> LogUtils.upLevel() PreferKey.recordLog -> LogUtils.upLevel()
"process_text" -> sharedPreferences?.let { PreferKey.processText -> sharedPreferences?.let {
setProcessTextEnable(it.getBoolean("process_text", true)) setProcessTextEnable(it.getBoolean("process_text", true))
} }
PreferKey.showRss -> postEvent(PreferKey.showRss, PreferKey.showRss) PreferKey.showRss -> postEvent(Bus.SHOW_RSS, "unused")
} }
} }

@ -100,18 +100,14 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
.setMessage("是否确认恢复?") .setMessage("是否确认恢复?")
.setPositiveButton(R.string.ok) { _, _ -> .setPositiveButton(R.string.ok) { _, _ ->
preferenceManager.sharedPreferences.edit() preferenceManager.sharedPreferences.edit()
// light mode
.putInt("colorPrimary", getCompatColor(R.color.md_light_blue_500)) .putInt("colorPrimary", getCompatColor(R.color.md_light_blue_500))
.putInt("colorAccent", getCompatColor(R.color.md_pink_800)) .putInt("colorAccent", getCompatColor(R.color.md_pink_800))
.putInt("colorBackground", getCompatColor(R.color.md_grey_100)) .putInt("colorBackground", getCompatColor(R.color.md_grey_100))
.putInt( // dark mode
"colorPrimaryNight", .putInt("colorPrimaryNight", getCompatColor(R.color.md_grey_900))
getCompatColor(R.color.md_blue_grey_600) .putInt("colorAccentNight", getCompatColor(R.color.md_deep_orange_800))
) .putInt("colorBackgroundNight", getCompatColor(R.color.md_black_1000))
.putInt(
"colorAccentNight",
getCompatColor(R.color.md_deep_orange_800)
)
.putInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800))
.apply() .apply()
App.INSTANCE.applyTheme() App.INSTANCE.applyTheme()
recreateActivities() recreateActivities()

@ -1,9 +1,7 @@
package io.legado.app.ui.config package io.legado.app.ui.config
import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings
import android.text.InputType import android.text.InputType
import android.view.View import android.view.View
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
@ -11,6 +9,7 @@ import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import io.legado.app.R import io.legado.app.R
import io.legado.app.help.IntentHelp
import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Backup
@ -21,12 +20,22 @@ import io.legado.app.lib.dialogs.noButton
import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.dialogs.yesButton
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.accentColor
import io.legado.app.utils.LogUtils
import io.legado.app.utils.applyTint import io.legado.app.utils.applyTint
import io.legado.app.utils.getPrefString import io.legado.app.utils.getPrefString
class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener { class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
fun bindPreferenceSummaryToValue(preference: Preference?) {
preference?.apply {
onPreferenceChangeListener = this@WebDavConfigFragment
onPreferenceChange(
this,
context.getPrefString(key)
)
}
}
addPreferencesFromResource(R.xml.pref_config_web_dav) addPreferencesFromResource(R.xml.pref_config_web_dav)
findPreference<EditTextPreference>("web_dav_url")?.let { findPreference<EditTextPreference>("web_dav_url")?.let {
it.setOnBindEditTextListener { editText -> it.setOnBindEditTextListener { editText ->
@ -82,47 +91,21 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference
return true return true
} }
private fun bindPreferenceSummaryToValue(preference: Preference?) {
preference?.apply {
onPreferenceChangeListener = this@WebDavConfigFragment
onPreferenceChange(
this,
context.getPrefString(key)
)
}
}
override fun onPreferenceTreeClick(preference: Preference?): Boolean { override fun onPreferenceTreeClick(preference: Preference?): Boolean {
when (preference?.key) { when (preference?.key) {
"web_dav_backup" -> Backup.backup() "web_dav_backup" -> PermissionsCompat.Builder(this)
"web_dav_restore" -> WebDavHelp.showRestoreDialog(requireContext()) .addPermissions(*Permissions.Group.STORAGE)
"import_old" -> importOld() .rationale(R.string.tip_perm_request_storage)
} .onGranted { Backup.backup() }
return super.onPreferenceTreeClick(preference) .request()
} "web_dav_restore" -> PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
private fun importOld() { .rationale(R.string.tip_perm_request_storage)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { .onGranted {
val haveInstallPermission = context!!.packageManager.canRequestPackageInstalls() WebDavHelp.showRestoreDialog(requireContext())
if (haveInstallPermission) {
startImport()
} else { //没有安装外部来源应用的权限
alert(title = "开启权限提示") {
message = "需要打开「安装外部来源应用」权限才能导入旧版数据,请去设置中开启"
yesButton {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
startActivityForResult(intent, 666)
}
noButton {
}
}.show().applyTint()
}
} else {
startImport()
}
} }
.request()
private fun startImport() { "import_old" -> needInstallApps {
alert(title = "导入") { alert(title = "导入") {
message = "是否导入旧版本数据" message = "是否导入旧版本数据"
yesButton { yesButton {
@ -138,5 +121,30 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference
} }
}.show().applyTint() }.show().applyTint()
} }
}
return super.onPreferenceTreeClick(preference)
}
private fun needInstallApps(callback: () -> Unit) {
fun canRequestPackageInstalls() :Boolean {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
return requireContext().packageManager.canRequestPackageInstalls()
}
return true
}
if (!canRequestPackageInstalls()) {
alert(title = "开启权限提示") {
message = "需要打开「安装外部来源应用」权限才能导入旧版数据,请去设置中开启"
yesButton {
IntentHelp.toInstallUnknown(requireContext())
}
noButton {
}
}.show().applyTint()
} else {
LogUtils.d("xxx","import old")
callback()
}
}
} }

@ -13,7 +13,6 @@ import io.legado.app.BuildConfig
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.Bus import io.legado.app.constant.Bus
import io.legado.app.constant.PreferKey
import io.legado.app.help.ActivityHelp import io.legado.app.help.ActivityHelp
import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Backup
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
@ -45,7 +44,7 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
view_pager_main.adapter = TabFragmentPageAdapter(supportFragmentManager) view_pager_main.adapter = TabFragmentPageAdapter(supportFragmentManager)
view_pager_main.addOnPageChangeListener(this) view_pager_main.addOnPageChangeListener(this)
bottom_navigation_view.setOnNavigationItemSelectedListener(this) bottom_navigation_view.setOnNavigationItemSelectedListener(this)
bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = showRss() bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = isShowRSS
upVersion() upVersion()
} }
@ -66,10 +65,10 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
fragmentList.add(RssFragment()) fragmentList.add(RssFragment())
fragmentList.add(MyFragment()) fragmentList.add(MyFragment())
} }
if (showRss() && fragmentList.size < 4) { if (isShowRSS && fragmentList.size < 4) {
fragmentList.add(2, RssFragment()) fragmentList.add(2, RssFragment())
} }
if (!showRss() && fragmentList.size == 4) { if (!isShowRSS && fragmentList.size == 4) {
fragmentList.removeAt(2) fragmentList.removeAt(2)
} }
} }
@ -87,7 +86,7 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
pagePosition = position pagePosition = position
when (position) { when (position) {
0, 1, 3 -> bottom_navigation_view.menu.getItem(position).isChecked = true 0, 1, 3 -> bottom_navigation_view.menu.getItem(position).isChecked = true
2 -> if (showRss()) { 2 -> if (isShowRSS) {
bottom_navigation_view.menu.getItem(position).isChecked = true bottom_navigation_view.menu.getItem(position).isChecked = true
} else { } else {
bottom_navigation_view.menu.getItem(3).isChecked = true bottom_navigation_view.menu.getItem(3).isChecked = true
@ -133,20 +132,16 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
observeEvent<String>(Bus.RECREATE) { observeEvent<String>(Bus.RECREATE) {
recreate() recreate()
} }
observeEvent<String>(PreferKey.showRss) { observeEvent<String>(Bus.SHOW_RSS) {
bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = showRss() bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = isShowRSS
upFragmentList() upFragmentList()
view_pager_main.adapter?.notifyDataSetChanged() view_pager_main.adapter?.notifyDataSetChanged()
if (showRss()) { if (isShowRSS) {
view_pager_main.setCurrentItem(3, false) view_pager_main.setCurrentItem(3, false)
} }
} }
} }
private fun showRss(): Boolean {
return getPrefBoolean("showRss", true)
}
private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) :
FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
@ -159,7 +154,7 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
} }
override fun getCount(): Int { override fun getCount(): Int {
return if (showRss()) 4 else 3 return if (isShowRSS) 4 else 3
} }
} }

@ -16,6 +16,7 @@ import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.WebDavHelp import io.legado.app.help.storage.WebDavHelp
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.service.WebService
import io.legado.app.ui.about.AboutActivity import io.legado.app.ui.about.AboutActivity
import io.legado.app.ui.about.DonateActivity import io.legado.app.ui.about.DonateActivity
import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.book.source.manage.BookSourceActivity
@ -23,7 +24,9 @@ import io.legado.app.ui.config.ConfigActivity
import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.config.ConfigViewModel
import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity
import io.legado.app.utils.LogUtils import io.legado.app.utils.LogUtils
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import io.legado.app.utils.toast
import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.android.synthetic.main.view_title_bar.*
import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivity
@ -79,12 +82,18 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) {
super.onPause() super.onPause()
} }
override fun onSharedPreferenceChanged( override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
sharedPreferences: SharedPreferences?,
key: String?
) {
when (key) { when (key) {
"isNightTheme" -> App.INSTANCE.applyDayNight() "isNightTheme" -> App.INSTANCE.applyDayNight()
"webService" -> {
if (requireContext().getPrefBoolean("webService")) {
WebService.start(requireContext())
toast("正在启动服务\n具体信息查看通知栏")
}else{
WebService.stop(requireContext())
toast("服务已停止")
}
}
"recordLog" -> LogUtils.upLevel() "recordLog" -> LogUtils.upLevel()
"downloadPath" -> BookHelp.upDownloadPath() "downloadPath" -> BookHelp.upDownloadPath()
} }

@ -11,7 +11,6 @@ import io.legado.app.service.help.ReadBook
import io.legado.app.ui.widget.page.curl.CurlView import io.legado.app.ui.widget.page.curl.CurlView
import io.legado.app.ui.widget.page.delegate.* import io.legado.app.ui.widget.page.delegate.*
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.getPrefInt
class PageView(context: Context, attrs: AttributeSet) : class PageView(context: Context, attrs: AttributeSet) :
FrameLayout(context, attrs), FrameLayout(context, attrs),
@ -89,13 +88,13 @@ class PageView(context: Context, attrs: AttributeSet) :
} }
} }
fun upPageAnim() { fun upPageAnim(pageAnim: Int = 0) {
if (curlView != null) { if (curlView != null) {
removeView(curlView) removeView(curlView)
curlView = null curlView = null
} }
pageDelegate = null pageDelegate = null
pageDelegate = when (context.getPrefInt("pageAnim")) { pageDelegate = when (pageAnim) {
0 -> CoverPageDelegate(this) 0 -> CoverPageDelegate(this)
1 -> SlidePageDelegate(this) 1 -> SlidePageDelegate(this)
2 -> SimulationPageDelegate(this) 2 -> SimulationPageDelegate(this)

@ -7,11 +7,8 @@ import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.edit import androidx.core.content.edit
import org.jetbrains.anko.connectivityManager
import org.jetbrains.anko.defaultSharedPreferences import org.jetbrains.anko.defaultSharedPreferences
fun Context.isOnline() = connectivityManager.activeNetworkInfo?.isConnected == true
fun Context.getPrefBoolean(key: String, defValue: Boolean = false) = fun Context.getPrefBoolean(key: String, defValue: Boolean = false) =
defaultSharedPreferences.getBoolean(key, defValue) defaultSharedPreferences.getBoolean(key, defValue)
@ -67,4 +64,7 @@ val Context.isNightTheme: Boolean
get() = getPrefBoolean("isNightTheme") get() = getPrefBoolean("isNightTheme")
val Context.isTransparentStatusBar: Boolean val Context.isTransparentStatusBar: Boolean
get() = getPrefBoolean("transparentStatusBar") get() = getPrefBoolean("transparentStatusBar", true)
val Context.isShowRSS: Boolean
get() = getPrefBoolean("showRss", true)

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:clickable="true"
android:focusable="true"
tools:ignore="UnusedAttribute">
<io.legado.app.ui.widget.image.CoverImageView
android:id="@+id/iv_cover"
android:layout_width="match_parent"
android:layout_height="100dp"
android:contentDescription="@string/img_cover"
android:scaleType="centerCrop"
android:src="@drawable/image_cover_default"
android:transitionName="img_cover"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UnusedAttribute" />
<TextView
android:id="@+id/tv_source"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:gravity="center"
android:singleLine="true"
android:text="@string/book_source"
android:textColor="@color/tv_text_default"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="@+id/iv_cover"
app:layout_constraintRight_toRightOf="@+id/iv_cover"
app:layout_constraintTop_toBottomOf="@+id/iv_cover"
tools:ignore="RtlHardcoded,RtlSymmetry" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -160,6 +160,7 @@
<string name="author_show">作者:%s</string> <string name="author_show">作者:%s</string>
<string name="aloud_stop">朗读停止</string> <string name="aloud_stop">朗读停止</string>
<string name="clear_cache">清除缓存</string> <string name="clear_cache">清除缓存</string>
<string name="clear_cache_success">成功清理缓存</string>
<string name="action_save">保存</string> <string name="action_save">保存</string>
<string name="edit_source">编辑源</string> <string name="edit_source">编辑源</string>
<string name="edit_book_source">编辑书源</string> <string name="edit_book_source">编辑书源</string>
@ -202,7 +203,7 @@
<string name="replace_rule_summary">替换规则名称</string> <string name="replace_rule_summary">替换规则名称</string>
<string name="select_action">选择操作</string> <string name="select_action">选择操作</string>
<string name="select_all">全选</string> <string name="select_all">全选</string>
<string name="dark_theme">暗色主题</string> <string name="dark_theme">深色模式</string>
<string name="welcome">启动页</string> <string name="welcome">启动页</string>
<string name="download_start">开始下载</string> <string name="download_start">开始下载</string>
<string name="download_cancel">取消下载</string> <string name="download_cancel">取消下载</string>
@ -313,6 +314,7 @@
<string name="use_to">替换范围,选填书名或者源名</string> <string name="use_to">替换范围,选填书名或者源名</string>
<string name="menu_action_group">分组</string> <string name="menu_action_group">分组</string>
<string name="download_path">内容缓存路径</string> <string name="download_path">内容缓存路径</string>
<string name="cleancache">清理缓存</string>
<string name="sys_file_picker">系统文件选择器</string> <string name="sys_file_picker">系统文件选择器</string>
<string name="new_version">新版本</string> <string name="new_version">新版本</string>
<string name="download_update">下载更新</string> <string name="download_update">下载更新</string>

@ -5,7 +5,7 @@
<androidx.preference.Preference <androidx.preference.Preference
android:key="isNightTheme" android:key="isNightTheme"
android:title="开发人员" android:title="开发人员"
android:summary="gedoor, Invinciblelee, atbest, Antecer, mabDc" android:summary="gedoor, Invinciblelee, atbest, Antecer, mabDc, Ca1e"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<androidx.preference.Preference <androidx.preference.Preference

@ -39,4 +39,8 @@
android:key="recordLog" android:key="recordLog"
android:title="记录日志" android:title="记录日志"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<Preference
android:key="cleanCache"
android:title="@string/cleancache"
app:iconSpaceReserved="false" />
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>

@ -4,9 +4,10 @@
<io.legado.app.lib.theme.prefs.ATESwitchPreference <io.legado.app.lib.theme.prefs.ATESwitchPreference
android:defaultValue="false" android:defaultValue="true"
android:key="transparentStatusBar" android:key="transparentStatusBar"
android:title="@string/status_bar_immersion" android:summary="@string/status_bar_immersion"
android:title="@string/immersion_status_bar"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legado.app.lib.theme.prefs.ATESwitchPreference <io.legado.app.lib.theme.prefs.ATESwitchPreference
@ -57,7 +58,7 @@
app:iconSpaceReserved="false"> app:iconSpaceReserved="false">
<io.legado.app.lib.theme.prefs.ATEColorPreference <io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/md_blue_grey_600" android:defaultValue="@color/md_grey_900"
android:key="colorPrimaryNight" android:key="colorPrimaryNight"
android:summary="夜间,主色调" android:summary="夜间,主色调"
android:title="主色调" android:title="主色调"
@ -73,7 +74,7 @@
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legado.app.lib.theme.prefs.ATEColorPreference <io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/md_grey_800" android:defaultValue="@color/md_black_1000"
android:key="colorBackgroundNight" android:key="colorBackgroundNight"
android:summary="夜间,背景色" android:summary="夜间,背景色"
android:title="背景色" android:title="背景色"

@ -20,6 +20,8 @@
android:summary="@string/web_dav_pw_s" android:summary="@string/web_dav_pw_s"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legado.app.lib.theme.prefs.ATEPreferenceCategory app:iconSpaceReserved="false">
<androidx.preference.Preference <androidx.preference.Preference
android:key="web_dav_backup" android:key="web_dav_backup"
android:title="备份" android:title="备份"
@ -35,4 +37,6 @@
android:title="导入旧版本数据" android:title="导入旧版本数据"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
</io.legado.app.lib.theme.prefs.ATEPreferenceCategory>
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>

@ -9,7 +9,7 @@ buildscript {
maven { url 'https://plugins.gradle.org/m2/' } maven { url 'https://plugins.gradle.org/m2/' }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.2' classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3'
classpath 'com.google.gms:google-services:4.3.3' classpath 'com.google.gms:google-services:4.3.3'

Loading…
Cancel
Save