pull/737/head
Robot 4 years ago
commit 73960e5921
  1. 1
      app/src/main/assets/help/ruleHelp.md
  2. 1
      app/src/main/assets/updateLog.md
  3. 2
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  4. 41
      app/src/main/java/io/legado/app/help/storage/BookWebDav.kt
  5. 50
      app/src/main/java/io/legado/app/help/storage/SyncBookProgress.kt
  6. 12
      app/src/main/java/io/legado/app/service/help/ReadBook.kt
  7. 6
      app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
  8. 7
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  9. 29
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
  10. 4
      app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt
  11. 5
      app/src/main/res/menu/book_read.xml
  12. 1
      app/src/main/res/values-zh-rHK/strings.xml
  13. 1
      app/src/main/res/values-zh-rTW/strings.xml
  14. 1
      app/src/main/res/values-zh/strings.xml
  15. 1
      app/src/main/res/values/strings.xml

@ -38,6 +38,7 @@ cookie 变量-cookie操作类,方法见 io.legado.app.help.http.CookieStore
cache 变量-缓存操作类,方法见 io.legado.app.help.CacheManager cache 变量-缓存操作类,方法见 io.legado.app.help.CacheManager
chapter 变量-当前目录类,方法见 io.legado.app.data.entities.BookChapter chapter 变量-当前目录类,方法见 io.legado.app.data.entities.BookChapter
title 变量-当前标题,String title 变量-当前标题,String
src 内容,源码
``` ```
## 部分js对象属性说明 ## 部分js对象属性说明

@ -8,6 +8,7 @@
* 优化中文排序 * 优化中文排序
* 优化编码识别 * 优化编码识别
* 选择文字时优先选词 * 选择文字时优先选词
* 优化进度同步,进入书籍时同步,每次同步单本书,减少同步文件大小
**2020/12/06** **2020/12/06**
* 添加规则订阅功能,订阅界面第一个图标,可以订阅书源/订阅源/替换规则 * 添加规则订阅功能,订阅界面第一个图标,可以订阅书源/订阅源/替换规则

@ -95,7 +95,7 @@ object Backup {
} }
edit.commit() edit.commit()
} }
WebDavHelp.backUpWebDav(backupPath) BookWebDav.backUpWebDav(backupPath)
if (path.isContentScheme()) { if (path.isContentScheme()) {
copyBackup(context, Uri.parse(path), isAuto) copyBackup(context, Uri.parse(path), isAuto)
} else { } else {

@ -6,6 +6,8 @@ import android.os.Looper
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.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookProgress
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.lib.dialogs.selector import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.webdav.HttpAuth import io.legado.app.lib.webdav.HttpAuth
@ -19,8 +21,9 @@ import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
object WebDavHelp { object BookWebDav {
private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/" private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/"
private val bookProgressUrl = "${rootWebDavUrl}bookProgress/"
private val zipFilePath = "${FileUtils.getCachePath()}${File.separator}backup.zip" private val zipFilePath = "${FileUtils.getCachePath()}${File.separator}backup.zip"
val rootWebDavUrl: String val rootWebDavUrl: String
@ -42,6 +45,7 @@ object WebDavHelp {
if (!account.isNullOrBlank() && !password.isNullOrBlank()) { if (!account.isNullOrBlank() && !password.isNullOrBlank()) {
HttpAuth.auth = HttpAuth.Auth(account, password) HttpAuth.auth = HttpAuth.Auth(account, password)
WebDav(rootWebDavUrl).makeAsDir() WebDav(rootWebDavUrl).makeAsDir()
WebDav(bookProgressUrl).makeAsDir()
return true return true
} }
return false return false
@ -139,4 +143,39 @@ object WebDavHelp {
} }
} }
} }
fun uploadBookProgress(book: Book) {
Coroutine.async {
val bookProgress = BookProgress(
name = book.name,
author = book.author,
durChapterIndex = book.durChapterIndex,
durChapterPos = book.durChapterPos,
durChapterTime = book.durChapterTime,
durChapterTitle = book.durChapterTitle
)
val json = GSON.toJson(bookProgress)
val url = getUrl(book)
if (initWebDav()) {
WebDav(url).upload(json.toByteArray())
}
}
}
fun getBookProgress(book: Book): BookProgress? {
if (initWebDav()) {
val url = getUrl(book)
WebDav(url).download()?.let { byteArray ->
val json = String(byteArray)
GSON.fromJsonObject<BookProgress>(json)?.let {
return it
}
}
}
return null
}
private fun getUrl(book: Book): String {
return bookProgressUrl + book.name + "_" + book.author + ".json"
}
} }

@ -1,50 +0,0 @@
package io.legado.app.help.storage
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookProgress
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.lib.webdav.WebDav
import io.legado.app.utils.GSON
import io.legado.app.utils.fromJsonObject
@Suppress("BlockingMethodInNonBlockingContext")
object SyncBookProgress {
private val webDavUrl = "${WebDavHelp.rootWebDavUrl}bookProgress/"
fun uploadBookProgress(book: Book) {
Coroutine.async {
val bookProgress = BookProgress(
name = book.name,
author = book.author,
durChapterIndex = book.durChapterIndex,
durChapterPos = book.durChapterPos,
durChapterTime = book.durChapterTime,
durChapterTitle = book.durChapterTitle
)
val json = GSON.toJson(bookProgress)
val url = getUrl(book)
if (WebDavHelp.initWebDav()) {
WebDav(webDavUrl).makeAsDir()
WebDav(url).upload(json.toByteArray())
}
}
}
fun getBookProgress(book: Book): BookProgress? {
if (WebDavHelp.initWebDav()) {
val url = getUrl(book)
WebDav(url).download()?.let { byteArray ->
val json = String(byteArray)
GSON.fromJsonObject<BookProgress>(json)?.let {
return it
}
}
}
return null
}
private fun getUrl(book: Book): String {
return webDavUrl + book.name + "_" + book.author + ".json"
}
}

@ -52,10 +52,8 @@ object ReadBook {
durChapterIndex = book.durChapterIndex durChapterIndex = book.durChapterIndex
durChapterPos = book.durChapterPos durChapterPos = book.durChapterPos
isLocalBook = book.origin == BookType.local isLocalBook = book.origin == BookType.local
chapterSize = 0 chapterSize = book.totalChapterNum
prevTextChapter = null clearTextChapter()
curTextChapter = null
nextTextChapter = null
titleDate.postValue(book.name) titleDate.postValue(book.name)
callBack?.upPageAnim() callBack?.upPageAnim()
upWebBook(book) upWebBook(book)
@ -80,6 +78,12 @@ object ReadBook {
} }
} }
fun clearTextChapter() {
prevTextChapter = null
curTextChapter = null
nextTextChapter = null
}
fun upReadStartTime() { fun upReadStartTime() {
Coroutine.async { Coroutine.async {
readRecord.readTime = readRecord.readTime + System.currentTimeMillis() - readStartTime readRecord.readTime = readRecord.readTime + System.currentTimeMillis() - readStartTime

@ -11,7 +11,7 @@ import io.legado.app.constant.PreferKey
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.ContentProcessor import io.legado.app.help.ContentProcessor
import io.legado.app.help.storage.WebDavHelp import io.legado.app.help.storage.BookWebDav
import io.legado.app.utils.* import io.legado.app.utils.*
import java.io.File import java.io.File
@ -47,7 +47,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
filename filename
).writeText(content) // 写出文件到cache目录 ).writeText(content) // 写出文件到cache目录
// 导出到webdav // 导出到webdav
WebDavHelp.exportWebDav(FileUtils.getCachePath(), filename) BookWebDav.exportWebDav(FileUtils.getCachePath(), filename)
// 上传完删除cache文件 // 上传完删除cache文件
FileUtils.deleteFile("${FileUtils.getCachePath()}${File.separator}${filename}") FileUtils.deleteFile("${FileUtils.getCachePath()}${File.separator}${filename}")
} }
@ -68,7 +68,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
FileUtils.createFileIfNotExist(file, filename) FileUtils.createFileIfNotExist(file, filename)
.writeText(getAllContents(book)) .writeText(getAllContents(book))
if (App.INSTANCE.getPrefBoolean(PreferKey.webDavCacheBackup, false)) { if (App.INSTANCE.getPrefBoolean(PreferKey.webDavCacheBackup, false)) {
WebDavHelp.exportWebDav(file.absolutePath, filename) // 导出到webdav BookWebDav.exportWebDav(file.absolutePath, filename) // 导出到webdav
} }
getSrcList(book).forEach { getSrcList(book).forEach {
val vFile = BookHelp.getImage(book, it.third) val vFile = BookHelp.getImage(book, it.third)

@ -23,7 +23,7 @@ import io.legado.app.data.entities.BookChapter
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.help.ReadTipConfig import io.legado.app.help.ReadTipConfig
import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.SyncBookProgress import io.legado.app.help.storage.BookWebDav
import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.accentColor
import io.legado.app.receiver.TimeBatteryReceiver import io.legado.app.receiver.TimeBatteryReceiver
@ -139,7 +139,7 @@ class ReadBookActivity : ReadBookBaseActivity(),
upSystemUiVisibility() upSystemUiVisibility()
if (!BuildConfig.DEBUG) { if (!BuildConfig.DEBUG) {
ReadBook.book?.let { ReadBook.book?.let {
SyncBookProgress.uploadBookProgress(it) BookWebDav.uploadBookProgress(it)
} }
Backup.autoBack(this) Backup.autoBack(this)
} }
@ -234,6 +234,9 @@ class ReadBookActivity : ReadBookBaseActivity(),
) )
} }
R.id.menu_set_charset -> showCharsetConfig() R.id.menu_set_charset -> showCharsetConfig()
R.id.menu_get_progress -> ReadBook.book?.let {
viewModel.syncBookProgress(it)
}
R.id.menu_help -> showReadMenuHelp() R.id.menu_help -> showReadMenuHelp()
} }
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)

@ -11,7 +11,7 @@ import io.legado.app.data.entities.SearchBook
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.IntentDataHelp import io.legado.app.help.IntentDataHelp
import io.legado.app.help.storage.SyncBookProgress import io.legado.app.help.storage.BookWebDav
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.service.BaseReadAloudService import io.legado.app.service.BaseReadAloudService
@ -47,12 +47,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
private fun initBook(book: Book) { private fun initBook(book: Book) {
if (ReadBook.book?.bookUrl != book.bookUrl) { if (ReadBook.book?.bookUrl != book.bookUrl) {
SyncBookProgress.getBookProgress(book)?.let { downloadProgress(book)
book.durChapterIndex = it.durChapterIndex
book.durChapterPos = it.durChapterPos
book.durChapterTime = it.durChapterTime
book.durChapterTitle = it.durChapterTitle
}
ReadBook.resetData(book) ReadBook.resetData(book)
isInitFinish = true isInitFinish = true
if (!book.isLocalBook() && ReadBook.webBook == null) { if (!book.isLocalBook() && ReadBook.webBook == null) {
@ -105,6 +100,15 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
} }
} }
private fun downloadProgress(book: Book) {
BookWebDav.getBookProgress(book)?.let {
book.durChapterIndex = it.durChapterIndex
book.durChapterPos = it.durChapterPos
book.durChapterTime = it.durChapterTime
book.durChapterTitle = it.durChapterTitle
}
}
private fun loadBookInfo( private fun loadBookInfo(
book: Book, book: Book,
changeDruChapterIndex: ((chapters: List<BookChapter>) -> Unit)? = null, changeDruChapterIndex: ((chapters: List<BookChapter>) -> Unit)? = null,
@ -162,6 +166,17 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
} }
} }
fun syncBookProgress(book: Book) {
execute {
downloadProgress(book)
ReadBook.durChapterIndex = book.durChapterIndex
ReadBook.durChapterPos = book.durChapterPos
ReadBook.prevTextChapter = null
ReadBook.clearTextChapter()
ReadBook.loadContent(resetPageOffset = true)
}
}
fun changeTo(newBook: Book) { fun changeTo(newBook: Book) {
execute { execute {
var oldTocSize: Int = newBook.totalChapterNum var oldTocSize: Int = newBook.totalChapterNum

@ -13,9 +13,9 @@ import io.legado.app.help.coroutine.Coroutine
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
import io.legado.app.help.storage.BookWebDav
import io.legado.app.help.storage.ImportOldData import io.legado.app.help.storage.ImportOldData
import io.legado.app.help.storage.Restore import io.legado.app.help.storage.Restore
import io.legado.app.help.storage.WebDavHelp
import io.legado.app.ui.filepicker.FilePicker import io.legado.app.ui.filepicker.FilePicker
import io.legado.app.utils.getPrefString import io.legado.app.utils.getPrefString
import io.legado.app.utils.isContentScheme import io.legado.app.utils.isContentScheme
@ -77,7 +77,7 @@ object BackupRestoreUi {
fun restore(fragment: Fragment) { fun restore(fragment: Fragment) {
Coroutine.async(context = Main) { Coroutine.async(context = Main) {
WebDavHelp.showRestoreDialog(fragment.requireContext()) BookWebDav.showRestoreDialog(fragment.requireContext())
}.onError { }.onError {
fragment.longToast("WebDavError:${it.localizedMessage}\n将从本地备份恢复。") fragment.longToast("WebDavError:${it.localizedMessage}\n将从本地备份恢复。")
val backupPath = fragment.getPrefString(PreferKey.backupPath) val backupPath = fragment.getPrefString(PreferKey.backupPath)

@ -76,6 +76,11 @@
android:title="@string/book_page_anim" android:title="@string/book_page_anim"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_get_progress"
android:title="@string/get_book_progress"
app:showAsAction="never" />
<item <item
android:id="@+id/menu_enable_replace" android:id="@+id/menu_enable_replace"
android:title="@string/replace_rule_title" android:title="@string/replace_rule_title"

@ -788,5 +788,6 @@
<string name="header_footer">页眉<![CDATA[&]]>页脚</string> <string name="header_footer">页眉<![CDATA[&]]>页脚</string>
<string name="rule_subscription">规则订阅</string> <string name="rule_subscription">规则订阅</string>
<string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string> <string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string>
<string name="get_book_progress">拉取云端进度</string>
</resources> </resources>

@ -789,5 +789,6 @@
<string name="header_footer">页眉<![CDATA[&]]>页脚</string> <string name="header_footer">页眉<![CDATA[&]]>页脚</string>
<string name="rule_subscription">规则订阅</string> <string name="rule_subscription">规则订阅</string>
<string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string> <string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string>
<string name="get_book_progress">拉取云端进度</string>
</resources> </resources>

@ -792,5 +792,6 @@
<string name="header_footer">页眉<![CDATA[&]]>页脚</string> <string name="header_footer">页眉<![CDATA[&]]>页脚</string>
<string name="rule_subscription">规则订阅</string> <string name="rule_subscription">规则订阅</string>
<string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string> <string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string>
<string name="get_book_progress">拉取云端进度</string>
</resources> </resources>

@ -795,5 +795,6 @@
<string name="header_footer">footer <![CDATA[&]]> header</string> <string name="header_footer">footer <![CDATA[&]]> header</string>
<string name="rule_subscription">规则订阅</string> <string name="rule_subscription">规则订阅</string>
<string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string> <string name="rule_sub_empty_msg">添加大佬们提供的规则导入地址\n添加后点击可导入规则</string>
<string name="get_book_progress">拉取云端进度</string>
</resources> </resources>

Loading…
Cancel
Save