diff --git a/app/build.gradle b/app/build.gradle index 43c822e3b..c2bc779e2 100644 --- a/app/build.gradle +++ b/app/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 { diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 21cea9f69..ee546dc37 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -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, diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index e08399579..a669fb6a6 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -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 \ No newline at end of file +* [by Celeter]优化老版本规则导入 \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index a9fbf72d4..37dd40e25 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -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 */ diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 517bafc93..395d51ec4 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -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" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index 24ac981e9..446efc0bf 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -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" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt index a8fe0d05f..9a5c7131a 100644 --- a/app/src/main/java/io/legado/app/help/CrashHandler.kt +++ b/app/src/main/java/io/legado/app/help/CrashHandler.kt @@ -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 + } } } } diff --git a/app/src/main/java/io/legado/app/help/FileHelp.kt b/app/src/main/java/io/legado/app/help/FileHelp.kt index a208a74a2..5a7678563 100644 --- a/app/src/main/java/io/legado/app/help/FileHelp.kt +++ b/app/src/main/java/io/legado/app/help/FileHelp.kt @@ -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) } diff --git a/app/src/main/java/io/legado/app/help/IntentHelp.kt b/app/src/main/java/io/legado/app/help/IntentHelp.kt index 815867694..d02e13392 100644 --- a/app/src/main/java/io/legado/app/help/IntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/IntentHelp.kt @@ -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 servicePendingIntent(context: Context, action: String): PendingIntent? { return PendingIntent.getService( context, diff --git a/app/src/main/java/io/legado/app/help/permission/Permissions.kt b/app/src/main/java/io/legado/app/help/permission/Permissions.kt index e1c0893e3..236691f7f 100644 --- a/app/src/main/java/io/legado/app/help/permission/Permissions.kt +++ b/app/src/main/java/io/legado/app/help/permission/Permissions.kt @@ -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) } - } diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 2f0b040a4..7062d1951 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -20,23 +20,26 @@ object Backup { } val legadoPath by lazy { - defaultPath + File.separator + "legadoBackUp" + FileUtils.getSdCardPath() + File.separator + "YueDu3.0" } val exportPath by lazy { legadoPath + File.separator + "Export" } + private fun pbackup(path :String = legadoPath){ + backupBookshelf(path) + backupBookSource(path) + backupRssSource(path) + backupReplaceRule(path) + backupReadConfig(path) + backupPreference(path) + WebDavHelp.backUpWebDav(path) + } + fun backup() { doAsync { - val path = legadoPath - backupBookshelf(path) - backupBookSource(path) - backupRssSource(path) - backupReplaceRule(path) - backupReadConfig(path) - backupPreference(path) - WebDavHelp.backUpWebDav(path) + 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() } } diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 0b8e66db5..53b040f28 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -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() val items: List> = 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) { - context.toast("导入书籍失败\n${e.localizedMessage}") + 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() val items: List> = jsonPath.parse(sourceFile.readText()).read("$") for (item in items) { @@ -168,12 +169,14 @@ object Restore { context.toast("成功导入书源${bookSources.size}") } } catch (e: Exception) { - context.toast("导入源失败\n${e.localizedMessage}") + 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() val items: List> = jsonPath.parse(ruleFile.readText()).read("$") val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() @@ -196,7 +199,9 @@ object Restore { context.toast("成功导入替换规则${replaceRules.size}") } } catch (e: Exception) { - context.toast("导入替换规则失败\n${e.localizedMessage}") + withContext(Main) { + context.toast("导入替换规则失败\n${e.localizedMessage}") + } } } } diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index 7d2022b5b..a4ac7fbcc 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -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) } } } diff --git a/app/src/main/java/io/legado/app/service/WebService.kt b/app/src/main/java/io/legado/app/service/WebService.kt index 012623865..b32e6d6bc 100644 --- a/app/src/main/java/io/legado/app/service/WebService.kt +++ b/app/src/main/java/io/legado/app/service/WebService.kt @@ -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 { @@ -113,4 +118,4 @@ class WebService : BaseService() { val notification = builder.build() startForeground(AppConst.notificationIdWeb, notification) } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt index 9b44da8bc..a4e420af1 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt @@ -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(R.layout.activity_book_info_edit) { + VMBaseActivity(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 = { - setResult(Activity.RESULT_OK) - finish() - }, - error = { - toast(it) - }) + viewModel.saveBook(book) { + setResult(Activity.RESULT_OK) + finish() + } } } + + override fun coverChangeTo(coverUrl: String) { + viewModel.book?.customCoverUrl = coverUrl + tie_cover_url.setText(coverUrl) + upCover() + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt index a947719cd..66602c1d7 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt @@ -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() - 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) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index 822ca033c..a816677f0 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -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 } diff --git a/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverDialog.kt b/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverDialog.kt new file mode 100644 index 000000000..f566cbbbb --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverDialog.kt @@ -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) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverViewModel.kt b/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverViewModel.kt new file mode 100644 index 000000000..5f12c56b2 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverViewModel.kt @@ -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 = "" + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changecover/CoverAdapter.kt b/app/src/main/java/io/legado/app/ui/changecover/CoverAdapter.kt new file mode 100644 index 000000000..408acbeb4 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/changecover/CoverAdapter.kt @@ -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(context, R.layout.item_cover) { + + override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { + with(holder.itemView) { + item.coverUrl?.let { + ImageLoader.load(context, it) + .centerCrop() + .into(iv_cover) + } + tv_source.text = item.originName + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt b/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt index 52d197a08..a926a8ae2 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt @@ -19,7 +19,7 @@ class ConfigActivity : VMBaseActivity(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() diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index cee764420..0410b34a6 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -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(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") } } diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 642a57578..a47fb4360 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -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() diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index a29c34057..9eb761712 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -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("web_dav_url")?.let { it.setOnBindEditTextListener { editText -> @@ -82,61 +91,60 @@ 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 = "需要打开「安装外部来源应用」权限才能导入旧版数据,请去设置中开启" + "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()) + } + .request() + "import_old" -> needInstallApps { + alert(title = "导入") { + message = "是否导入旧版本数据" yesButton { - val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES) - startActivityForResult(intent, 666) + PermissionsCompat.Builder(this@WebDavConfigFragment) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { + Restore.importYueDuData(requireContext()) + } + .request() } noButton { } }.show().applyTint() } - } else { - startImport() } + return super.onPreferenceTreeClick(preference) } - private fun startImport() { - alert(title = "导入") { - message = "是否导入旧版本数据" - yesButton { - PermissionsCompat.Builder(this@WebDavConfigFragment) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { - Restore.importYueDuData(requireContext()) - } - .request() - } - noButton { + private fun needInstallApps(callback: () -> Unit) { + + fun canRequestPackageInstalls() :Boolean { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + return requireContext().packageManager.canRequestPackageInstalls() } - }.show().applyTint() + return true + } + if (!canRequestPackageInstalls()) { + alert(title = "开启权限提示") { + message = "需要打开「安装外部来源应用」权限才能导入旧版数据,请去设置中开启" + yesButton { + IntentHelp.toInstallUnknown(requireContext()) + } + noButton { + } + }.show().applyTint() + } else { + LogUtils.d("xxx","import old") + callback() + } } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 83f515a0c..1b5966efb 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -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(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(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(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(R.layout.activity_main), observeEvent(Bus.RECREATE) { recreate() } - observeEvent(PreferKey.showRss) { - bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = showRss() + observeEvent(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(R.layout.activity_main), } override fun getCount(): Int { - return if (showRss()) 4 else 3 + return if (isShowRSS) 4 else 3 } } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index b2747f97e..b84538aa1 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -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() } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 2a05969f7..ec4693ffb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -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) diff --git a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt index c51be0b80..f47a0a2a8 100644 --- a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt @@ -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") \ No newline at end of file + get() = getPrefBoolean("transparentStatusBar", true) + +val Context.isShowRSS: Boolean + get() = getPrefBoolean("showRss", true) \ No newline at end of file diff --git a/app/src/main/res/layout/item_cover.xml b/app/src/main/res/layout/item_cover.xml new file mode 100644 index 000000000..018b5f2f8 --- /dev/null +++ b/app/src/main/res/layout/item_cover.xml @@ -0,0 +1,40 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9e6327377..602c75ca4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -160,6 +160,7 @@ 作者:%s 朗读停止 清除缓存 + 成功清理缓存 保存 编辑源 编辑书源 @@ -202,7 +203,7 @@ 替换规则名称 选择操作 全选 - 暗色主题 + 深色模式 启动页 开始下载 取消下载 @@ -313,6 +314,7 @@ 替换范围,选填书名或者源名 分组 内容缓存路径 + 清理缓存 系统文件选择器 新版本 下载更新 diff --git a/app/src/main/res/xml/about.xml b/app/src/main/res/xml/about.xml index 0391f9d86..9bf6b7b71 100644 --- a/app/src/main/res/xml/about.xml +++ b/app/src/main/res/xml/about.xml @@ -5,7 +5,7 @@ + \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config_theme.xml b/app/src/main/res/xml/pref_config_theme.xml index 607359962..f9f3df963 100644 --- a/app/src/main/res/xml/pref_config_theme.xml +++ b/app/src/main/res/xml/pref_config_theme.xml @@ -4,9 +4,10 @@ - + - + - + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index cb1547a01..be4632b0d 100644 --- a/build.gradle +++ b/build.gradle @@ -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'