[优化] 下载优化
This commit is contained in:
@@ -55,6 +55,7 @@ class CacheBookModel(
|
|||||||
private val onDownloadSet = linkedSetOf<Int>()
|
private val onDownloadSet = linkedSetOf<Int>()
|
||||||
private val canceledDownloadSet = hashSetOf<Int>()
|
private val canceledDownloadSet = hashSetOf<Int>()
|
||||||
private val pausedChapterSet = linkedSetOf<Int>()
|
private val pausedChapterSet = linkedSetOf<Int>()
|
||||||
|
private val pendingReadRequestMap = hashMapOf<Int, Boolean>()
|
||||||
private val chapterTasks = hashMapOf<Int, Coroutine<*>>()
|
private val chapterTasks = hashMapOf<Int, Coroutine<*>>()
|
||||||
private val tasks = CompositeCoroutine()
|
private val tasks = CompositeCoroutine()
|
||||||
private val repository = CacheDownloadRepository()
|
private val repository = CacheDownloadRepository()
|
||||||
@@ -197,6 +198,7 @@ class CacheBookModel(
|
|||||||
canceledDownloadSet.clear()
|
canceledDownloadSet.clear()
|
||||||
pausedChapterSet.clear()
|
pausedChapterSet.clear()
|
||||||
chapterTasks.clear()
|
chapterTasks.clear()
|
||||||
|
pendingReadRequestMap.clear()
|
||||||
tasks.clear()
|
tasks.clear()
|
||||||
retryCountMap.clear()
|
retryCountMap.clear()
|
||||||
isStopped = true
|
isStopped = true
|
||||||
@@ -492,12 +494,17 @@ class CacheBookModel(
|
|||||||
) {
|
) {
|
||||||
task.onSuccess {
|
task.onSuccess {
|
||||||
onSuccess(chapter)
|
onSuccess(chapter)
|
||||||
|
(it as? String)?.let { content ->
|
||||||
|
emitPendingReadContent(chapter, content)
|
||||||
|
}
|
||||||
}.onError {
|
}.onError {
|
||||||
onPreError(chapter, it)
|
onPreError(chapter, it)
|
||||||
delay(1000)
|
delay(1000)
|
||||||
onPostError(chapter, it)
|
onPostError(chapter, it)
|
||||||
|
emitPendingReadError(chapter, it)
|
||||||
}.onCancel {
|
}.onCancel {
|
||||||
onCancel(chapterIndex)
|
onCancel(chapterIndex)
|
||||||
|
emitPendingReadCanceled(chapter)
|
||||||
}.onFinally {
|
}.onFinally {
|
||||||
chapterTasks.remove(chapterIndex)?.let { tasks.delete(it) }
|
chapterTasks.remove(chapterIndex)?.let { tasks.delete(it) }
|
||||||
onFinally()
|
onFinally()
|
||||||
@@ -536,7 +543,10 @@ class CacheBookModel(
|
|||||||
semaphore: Semaphore?,
|
semaphore: Semaphore?,
|
||||||
resetPageOffset: Boolean = false
|
resetPageOffset: Boolean = false
|
||||||
) {
|
) {
|
||||||
if (!markChapterDownloadStarted(chapter.index)) return
|
if (!markChapterDownloadStarted(chapter.index)) {
|
||||||
|
markPendingReadRequest(chapter.index, resetPageOffset)
|
||||||
|
return
|
||||||
|
}
|
||||||
repository.downloadContentTask(
|
repository.downloadContentTask(
|
||||||
scope = scope,
|
scope = scope,
|
||||||
bookSource = bookSource,
|
bookSource = bookSource,
|
||||||
@@ -551,11 +561,13 @@ class CacheBookModel(
|
|||||||
ReadBook.downloadedChapters.add(chapter.index)
|
ReadBook.downloadedChapters.add(chapter.index)
|
||||||
ReadBook.downloadFailChapters.remove(chapter.index)
|
ReadBook.downloadFailChapters.remove(chapter.index)
|
||||||
downloadFinish(chapter, content, resetPageOffset)
|
downloadFinish(chapter, content, resetPageOffset)
|
||||||
|
emitPendingReadContent(chapter, content)
|
||||||
}.onError {
|
}.onError {
|
||||||
onError(chapter, it)
|
onError(chapter, it)
|
||||||
ReadBook.downloadFailChapters[chapter.index] =
|
ReadBook.downloadFailChapters[chapter.index] =
|
||||||
(ReadBook.downloadFailChapters[chapter.index] ?: 0) + 1
|
(ReadBook.downloadFailChapters[chapter.index] ?: 0) + 1
|
||||||
downloadFinish(chapter, "获取正文失败\n${it.localizedMessage}", resetPageOffset)
|
downloadFinish(chapter, "获取正文失败\n${it.localizedMessage}", resetPageOffset)
|
||||||
|
emitPendingReadError(chapter, it)
|
||||||
}.onCancel {
|
}.onCancel {
|
||||||
onCancel(chapter.index, requeue = false)
|
onCancel(chapter.index, requeue = false)
|
||||||
downloadFinish(chapter, "download canceled", resetPageOffset, true)
|
downloadFinish(chapter, "download canceled", resetPageOffset, true)
|
||||||
@@ -573,6 +585,31 @@ class CacheBookModel(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
private fun markPendingReadRequest(index: Int, resetPageOffset: Boolean) {
|
||||||
|
pendingReadRequestMap[index] = pendingReadRequestMap[index] == true || resetPageOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
private fun consumePendingReadRequest(index: Int): Boolean? {
|
||||||
|
return pendingReadRequestMap.remove(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun emitPendingReadContent(chapter: BookChapter, content: String) {
|
||||||
|
val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
|
||||||
|
downloadFinish(chapter, content, resetPageOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun emitPendingReadError(chapter: BookChapter, error: Throwable) {
|
||||||
|
val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
|
||||||
|
downloadFinish(chapter, "获取正文失败\n${error.localizedMessage}", resetPageOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun emitPendingReadCanceled(chapter: BookChapter) {
|
||||||
|
val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
|
||||||
|
downloadFinish(chapter, "download canceled", resetPageOffset)
|
||||||
|
}
|
||||||
|
|
||||||
private fun downloadFinish(
|
private fun downloadFinish(
|
||||||
chapter: BookChapter,
|
chapter: BookChapter,
|
||||||
content: String,
|
content: String,
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class CacheDownloadRepository {
|
|||||||
context: CoroutineContext,
|
context: CoroutineContext,
|
||||||
start: CoroutineStart = CoroutineStart.LAZY,
|
start: CoroutineStart = CoroutineStart.LAZY,
|
||||||
executeContext: CoroutineContext = context,
|
executeContext: CoroutineContext = context,
|
||||||
): Coroutine<Unit> {
|
): Coroutine<String> {
|
||||||
return Coroutine.async(
|
return Coroutine.async(
|
||||||
scope = scope,
|
scope = scope,
|
||||||
context = context,
|
context = context,
|
||||||
|
|||||||
@@ -126,15 +126,17 @@ class SearchViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
SearchIntent.SelectAllScope -> {
|
SearchIntent.SelectAllScope -> {
|
||||||
|
val oldScope = searchScope.toString()
|
||||||
searchScope.update("")
|
searchScope.update("")
|
||||||
syncScopeState()
|
syncScopeState(restartSearch = true, oldScope = oldScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
is SearchIntent.ToggleScopeGroup -> toggleScopeGroup(intent.groupName)
|
is SearchIntent.ToggleScopeGroup -> toggleScopeGroup(intent.groupName)
|
||||||
is SearchIntent.ToggleScopeSource -> toggleScopeSource(intent.source)
|
is SearchIntent.ToggleScopeSource -> toggleScopeSource(intent.source)
|
||||||
is SearchIntent.RemoveScopeItem -> {
|
is SearchIntent.RemoveScopeItem -> {
|
||||||
|
val oldScope = searchScope.toString()
|
||||||
searchScope.remove(intent.scopeName)
|
searchScope.remove(intent.scopeName)
|
||||||
syncScopeState()
|
syncScopeState(restartSearch = true, oldScope = oldScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
is SearchIntent.TogglePrecision -> {
|
is SearchIntent.TogglePrecision -> {
|
||||||
@@ -370,6 +372,7 @@ class SearchViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleScopeGroup(groupName: String) {
|
private fun toggleScopeGroup(groupName: String) {
|
||||||
|
val oldScope = searchScope.toString()
|
||||||
if (searchScope.isSource()) {
|
if (searchScope.isSource()) {
|
||||||
searchScope.update("")
|
searchScope.update("")
|
||||||
}
|
}
|
||||||
@@ -380,10 +383,11 @@ class SearchViewModel(
|
|||||||
selected.add(groupName)
|
selected.add(groupName)
|
||||||
}
|
}
|
||||||
searchScope.update(selected.toList())
|
searchScope.update(selected.toList())
|
||||||
syncScopeState()
|
syncScopeState(restartSearch = true, oldScope = oldScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleScopeSource(source: BookSourcePart) {
|
private fun toggleScopeSource(source: BookSourcePart) {
|
||||||
|
val oldScope = searchScope.toString()
|
||||||
val selectedUrls = if (searchScope.isSource()) {
|
val selectedUrls = if (searchScope.isSource()) {
|
||||||
searchScope.sourceUrls.toMutableSet()
|
searchScope.sourceUrls.toMutableSet()
|
||||||
} else {
|
} else {
|
||||||
@@ -404,7 +408,7 @@ class SearchViewModel(
|
|||||||
}
|
}
|
||||||
searchScope.updateSources(selectedSources)
|
searchScope.updateSources(selectedSources)
|
||||||
}
|
}
|
||||||
syncScopeState()
|
syncScopeState(restartSearch = true, oldScope = oldScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEmptyScopeActionConfirmed() {
|
private fun handleEmptyScopeActionConfirmed() {
|
||||||
@@ -429,7 +433,11 @@ class SearchViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun syncScopeState() {
|
private fun syncScopeState(
|
||||||
|
restartSearch: Boolean = false,
|
||||||
|
oldScope: String? = null,
|
||||||
|
) {
|
||||||
|
val scopeChanged = oldScope == null || oldScope != searchScope.toString()
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
scopeDisplay = searchScope.display,
|
scopeDisplay = searchScope.display,
|
||||||
@@ -439,6 +447,9 @@ class SearchViewModel(
|
|||||||
isSourceScope = searchScope.isSource(),
|
isSourceScope = searchScope.isSource(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (restartSearch && scopeChanged) {
|
||||||
|
restartCommittedSearchIfNeeded()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<SearchBook>.toSearchResultItems(
|
private fun List<SearchBook>.toSearchResultItems(
|
||||||
|
|||||||
Reference in New Issue
Block a user