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 version = "0." + releaseTime()
def version = "3." + releaseTime()
def gitCommits = Integer.parseInt('git rev-list --count HEAD'.execute([], project.rootDir).text.trim())
android {

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

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

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

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

@ -10,4 +10,7 @@ object PreferKey {
const val nextKey = "nextKeyCode"
const val showRss = "showRss"
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 {
for (field in fields) {
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) {
val files = file.listFiles()
for (subFile in files) {
files?.forEach { subFile ->
val path = subFile.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? {
return PendingIntent.getService(
context,

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

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

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

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

@ -34,7 +34,6 @@ class WebService : BaseService() {
context.startService(intent)
}
}
}
private var httpServer: HttpServer? = null
@ -49,6 +48,12 @@ class WebService : BaseService() {
override fun onDestroy() {
super.onDestroy()
isRun = false
if (httpServer?.isAlive == true) {
httpServer?.stop()
}
if (webSocketServer?.isAlive == true) {
webSocketServer?.stop()
}
}
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.base.VMBaseActivity
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 kotlinx.android.synthetic.main.activity_book_info_edit.*
import org.jetbrains.anko.toast
import org.jetbrains.anko.sdk27.listeners.onClick
class BookInfoEditActivity :
VMBaseActivity<BookInfoEditViewModel>(R.layout.activity_book_info_edit) {
VMBaseActivity<BookInfoEditViewModel>(R.layout.activity_book_info_edit),
ChangeCoverDialog.CallBack {
override val viewModel: BookInfoEditViewModel
get() = getViewModel(BookInfoEditViewModel::class.java)
@ -24,6 +27,7 @@ class BookInfoEditActivity :
viewModel.loadBook(it)
}
}
initEvent()
}
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
@ -38,28 +42,47 @@ class BookInfoEditActivity :
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) {
tie_book_name.setText(book.name)
tie_book_author.setText(book.author)
tie_cover_url.setText(book.getDisplayCover())
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() {
viewModel.bookData.value?.let { book ->
viewModel.book?.let { book ->
book.name = tie_book_name.text?.toString() ?: ""
book.author = tie_book_author.text?.toString() ?: ""
val customCoverUrl = tie_cover_url.text?.toString()
book.customCoverUrl = if (customCoverUrl == book.coverUrl) null else customCoverUrl
book.customIntro = tie_book_intro.text?.toString()
viewModel.saveBook(book,
success = {
viewModel.saveBook(book) {
setResult(Activity.RESULT_OK)
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
class BookInfoEditViewModel(application: Application) : BaseViewModel(application) {
var book: Book? = null
val bookData = MutableLiveData<Book>()
fun loadBook(bookUrl: String) {
execute {
App.db.bookDao().getBook(bookUrl)?.let {
book = App.db.bookDao().getBook(bookUrl)
book?.let {
bookData.postValue(it)
}
}
}
fun saveBook(book: Book, success: (() -> Unit)?, error: ((msg: String) -> Unit)?) {
fun saveBook(book: Book, success: (() -> Unit)?) {
execute {
App.db.bookDao().insert(book)
}.onSuccess {
success?.invoke()
}.onError {
error?.invoke(it.localizedMessage)
}
}
}

@ -182,7 +182,7 @@ class ReadStyleDialog : DialogFragment() {
requireContext().putPrefInt("pageAnim", i)
val activity = activity
if (activity is ReadBookActivity) {
activity.page_view.upPageAnim()
activity.page_view.upPageAnim(i)
}
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) {
ConfigViewModel.TYPE_CONFIG -> {
title_bar.title = getString(R.string.setting)
title_bar.title = getString(R.string.other_setting)
val fTag = "configFragment"
var configFragment = supportFragmentManager.findFragmentByTag(fTag)
if (configFragment == null) configFragment = ConfigFragment()

@ -10,8 +10,10 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import io.legado.app.App
import io.legado.app.R
import io.legado.app.constant.Bus
import io.legado.app.constant.PreferKey
import io.legado.app.help.BookHelp
import io.legado.app.help.FileHelp
import io.legado.app.lib.theme.ATH
import io.legado.app.receiver.SharedReceiverActivity
import io.legado.app.ui.filechooser.FileChooserDialog
@ -59,6 +61,13 @@ class ConfigFragment : PreferenceFragmentCompat(),
mode = FileChooserDialog.DIRECTORY,
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)
}
@ -69,11 +78,11 @@ class ConfigFragment : PreferenceFragmentCompat(),
BookHelp.upDownloadPath()
findPreference<Preference>(key)?.summary = getPreferenceString(key)
}
"recordLog" -> LogUtils.upLevel()
"process_text" -> sharedPreferences?.let {
PreferKey.recordLog -> LogUtils.upLevel()
PreferKey.processText -> sharedPreferences?.let {
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("是否确认恢复?")
.setPositiveButton(R.string.ok) { _, _ ->
preferenceManager.sharedPreferences.edit()
// light mode
.putInt("colorPrimary", getCompatColor(R.color.md_light_blue_500))
.putInt("colorAccent", getCompatColor(R.color.md_pink_800))
.putInt("colorBackground", getCompatColor(R.color.md_grey_100))
.putInt(
"colorPrimaryNight",
getCompatColor(R.color.md_blue_grey_600)
)
.putInt(
"colorAccentNight",
getCompatColor(R.color.md_deep_orange_800)
)
.putInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800))
// dark mode
.putInt("colorPrimaryNight", getCompatColor(R.color.md_grey_900))
.putInt("colorAccentNight", getCompatColor(R.color.md_deep_orange_800))
.putInt("colorBackgroundNight", getCompatColor(R.color.md_black_1000))
.apply()
App.INSTANCE.applyTheme()
recreateActivities()

@ -1,9 +1,7 @@
package io.legado.app.ui.config
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.text.InputType
import android.view.View
import androidx.preference.EditTextPreference
@ -11,6 +9,7 @@ import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import io.legado.app.R
import io.legado.app.help.IntentHelp
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
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.theme.ATH
import io.legado.app.lib.theme.accentColor
import io.legado.app.utils.LogUtils
import io.legado.app.utils.applyTint
import io.legado.app.utils.getPrefString
class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
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)
findPreference<EditTextPreference>("web_dav_url")?.let {
it.setOnBindEditTextListener { editText ->
@ -82,47 +91,21 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference
return true
}
private fun bindPreferenceSummaryToValue(preference: Preference?) {
preference?.apply {
onPreferenceChangeListener = this@WebDavConfigFragment
onPreferenceChange(
this,
context.getPrefString(key)
)
}
}
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
when (preference?.key) {
"web_dav_backup" -> Backup.backup()
"web_dav_restore" -> WebDavHelp.showRestoreDialog(requireContext())
"import_old" -> importOld()
}
return super.onPreferenceTreeClick(preference)
}
private fun importOld() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
val haveInstallPermission = context!!.packageManager.canRequestPackageInstalls()
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()
}
"web_dav_backup" -> PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted { Backup.backup() }
.request()
"web_dav_restore" -> PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
WebDavHelp.showRestoreDialog(requireContext())
}
private fun startImport() {
.request()
"import_old" -> needInstallApps {
alert(title = "导入") {
message = "是否导入旧版本数据"
yesButton {
@ -138,5 +121,30 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference
}
}.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.base.VMBaseActivity
import io.legado.app.constant.Bus
import io.legado.app.constant.PreferKey
import io.legado.app.help.ActivityHelp
import io.legado.app.help.storage.Backup
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.addOnPageChangeListener(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()
}
@ -66,10 +65,10 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
fragmentList.add(RssFragment())
fragmentList.add(MyFragment())
}
if (showRss() && fragmentList.size < 4) {
if (isShowRSS && fragmentList.size < 4) {
fragmentList.add(2, RssFragment())
}
if (!showRss() && fragmentList.size == 4) {
if (!isShowRSS && fragmentList.size == 4) {
fragmentList.removeAt(2)
}
}
@ -87,7 +86,7 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
pagePosition = position
when (position) {
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
} else {
bottom_navigation_view.menu.getItem(3).isChecked = true
@ -133,20 +132,16 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
observeEvent<String>(Bus.RECREATE) {
recreate()
}
observeEvent<String>(PreferKey.showRss) {
bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = showRss()
observeEvent<String>(Bus.SHOW_RSS) {
bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = isShowRSS
upFragmentList()
view_pager_main.adapter?.notifyDataSetChanged()
if (showRss()) {
if (isShowRSS) {
view_pager_main.setCurrentItem(3, false)
}
}
}
private fun showRss(): Boolean {
return getPrefBoolean("showRss", true)
}
private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) :
FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
@ -159,7 +154,7 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
}
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.WebDavHelp
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.DonateActivity
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.replacerule.ReplaceRuleActivity
import io.legado.app.utils.LogUtils
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.startActivity
import io.legado.app.utils.toast
import kotlinx.android.synthetic.main.view_title_bar.*
import org.jetbrains.anko.startActivity
@ -79,12 +82,18 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) {
super.onPause()
}
override fun onSharedPreferenceChanged(
sharedPreferences: SharedPreferences?,
key: String?
) {
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (key) {
"isNightTheme" -> App.INSTANCE.applyDayNight()
"webService" -> {
if (requireContext().getPrefBoolean("webService")) {
WebService.start(requireContext())
toast("正在启动服务\n具体信息查看通知栏")
}else{
WebService.stop(requireContext())
toast("服务已停止")
}
}
"recordLog" -> LogUtils.upLevel()
"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.delegate.*
import io.legado.app.utils.activity
import io.legado.app.utils.getPrefInt
class PageView(context: Context, attrs: AttributeSet) :
FrameLayout(context, attrs),
@ -89,13 +88,13 @@ class PageView(context: Context, attrs: AttributeSet) :
}
}
fun upPageAnim() {
fun upPageAnim(pageAnim: Int = 0) {
if (curlView != null) {
removeView(curlView)
curlView = null
}
pageDelegate = null
pageDelegate = when (context.getPrefInt("pageAnim")) {
pageDelegate = when (pageAnim) {
0 -> CoverPageDelegate(this)
1 -> SlidePageDelegate(this)
2 -> SimulationPageDelegate(this)

@ -7,11 +7,8 @@ import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.core.content.edit
import org.jetbrains.anko.connectivityManager
import org.jetbrains.anko.defaultSharedPreferences
fun Context.isOnline() = connectivityManager.activeNetworkInfo?.isConnected == true
fun Context.getPrefBoolean(key: String, defValue: Boolean = false) =
defaultSharedPreferences.getBoolean(key, defValue)
@ -67,4 +64,7 @@ val Context.isNightTheme: Boolean
get() = getPrefBoolean("isNightTheme")
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="aloud_stop">朗读停止</string>
<string name="clear_cache">清除缓存</string>
<string name="clear_cache_success">成功清理缓存</string>
<string name="action_save">保存</string>
<string name="edit_source">编辑源</string>
<string name="edit_book_source">编辑书源</string>
@ -202,7 +203,7 @@
<string name="replace_rule_summary">替换规则名称</string>
<string name="select_action">选择操作</string>
<string name="select_all">全选</string>
<string name="dark_theme">暗色主题</string>
<string name="dark_theme">深色模式</string>
<string name="welcome">启动页</string>
<string name="download_start">开始下载</string>
<string name="download_cancel">取消下载</string>
@ -313,6 +314,7 @@
<string name="use_to">替换范围,选填书名或者源名</string>
<string name="menu_action_group">分组</string>
<string name="download_path">内容缓存路径</string>
<string name="cleancache">清理缓存</string>
<string name="sys_file_picker">系统文件选择器</string>
<string name="new_version">新版本</string>
<string name="download_update">下载更新</string>

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

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

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

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

@ -9,7 +9,7 @@ buildscript {
maven { url 'https://plugins.gradle.org/m2/' }
}
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 'de.timfreiheit.resourceplaceholders:placeholders:0.3'
classpath 'com.google.gms:google-services:4.3.3'

Loading…
Cancel
Save