|
@@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.asSharedFlow
|
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
|
import kotlinx.coroutines.flow.combine
|
|
import kotlinx.coroutines.flow.combine
|
|
|
import kotlinx.coroutines.flow.update
|
|
import kotlinx.coroutines.flow.update
|
|
|
|
|
+import kotlinx.coroutines.delay
|
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.launch
|
|
|
import splitties.init.appCtx
|
|
import splitties.init.appCtx
|
|
|
|
|
|
|
@@ -44,6 +45,12 @@ class ExploreShowViewModel(
|
|
|
private var sourceUrl: String? = null
|
|
private var sourceUrl: String? = null
|
|
|
private var exploreUrl: String? = null
|
|
private var exploreUrl: String? = null
|
|
|
private var page = 1
|
|
private var page = 1
|
|
|
|
|
+ private var autoPageCount = 0
|
|
|
|
|
+
|
|
|
|
|
+ companion object {
|
|
|
|
|
+ private const val MAX_AUTO_PAGES = 3
|
|
|
|
|
+ private const val AUTO_PAGE_DELAY_MS = 500L
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
private val _uiState = MutableStateFlow(
|
|
private val _uiState = MutableStateFlow(
|
|
|
ExploreShowUiState(
|
|
ExploreShowUiState(
|
|
@@ -65,6 +72,7 @@ class ExploreShowViewModel(
|
|
|
when (intent) {
|
|
when (intent) {
|
|
|
is ExploreShowIntent.InitData -> initData(intent.sourceUrl, intent.exploreUrl)
|
|
is ExploreShowIntent.InitData -> initData(intent.sourceUrl, intent.exploreUrl)
|
|
|
ExploreShowIntent.LoadMore -> loadMore()
|
|
ExploreShowIntent.LoadMore -> loadMore()
|
|
|
|
|
+ ExploreShowIntent.ForceLoadNext -> loadMore(forceLoad = true)
|
|
|
ExploreShowIntent.Refresh -> loadMore(isRefresh = true)
|
|
ExploreShowIntent.Refresh -> loadMore(isRefresh = true)
|
|
|
is ExploreShowIntent.SwitchKind -> switchKind(intent.kind)
|
|
is ExploreShowIntent.SwitchKind -> switchKind(intent.kind)
|
|
|
ExploreShowIntent.ToggleLayout -> toggleLayout()
|
|
ExploreShowIntent.ToggleLayout -> toggleLayout()
|
|
@@ -161,6 +169,7 @@ class ExploreShowViewModel(
|
|
|
sourceUrl = incomingSourceUrl
|
|
sourceUrl = incomingSourceUrl
|
|
|
exploreUrl = incomingExploreUrl
|
|
exploreUrl = incomingExploreUrl
|
|
|
page = 1
|
|
page = 1
|
|
|
|
|
+ autoPageCount = 0
|
|
|
bookSource = null
|
|
bookSource = null
|
|
|
_rawBooks.value = emptyList()
|
|
_rawBooks.value = emptyList()
|
|
|
_isEnd.value = false
|
|
_isEnd.value = false
|
|
@@ -191,6 +200,7 @@ class ExploreShowViewModel(
|
|
|
_selectedKindTitle.value = kind.title
|
|
_selectedKindTitle.value = kind.title
|
|
|
exploreUrl = kind.url
|
|
exploreUrl = kind.url
|
|
|
_isEnd.value = false
|
|
_isEnd.value = false
|
|
|
|
|
+ autoPageCount = 0
|
|
|
loadMore(isRefresh = true)
|
|
loadMore(isRefresh = true)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -207,10 +217,10 @@ class ExploreShowViewModel(
|
|
|
_uiState.update { it.copy(gridCount = count) }
|
|
_uiState.update { it.copy(gridCount = count) }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private fun loadMore(isRefresh: Boolean = false) {
|
|
|
|
|
|
|
+ private fun loadMore(isRefresh: Boolean = false, forceLoad: Boolean = false) {
|
|
|
val source = bookSource
|
|
val source = bookSource
|
|
|
val url = exploreUrl ?: source?.exploreUrl
|
|
val url = exploreUrl ?: source?.exploreUrl
|
|
|
- if (source == null || url == null || _isLoading.value || (_isEnd.value && !isRefresh)) return
|
|
|
|
|
|
|
+ if (source == null || url == null || _isLoading.value || (_isEnd.value && !isRefresh && !forceLoad)) return
|
|
|
|
|
|
|
|
viewModelScope.launch {
|
|
viewModelScope.launch {
|
|
|
_isLoading.value = true
|
|
_isLoading.value = true
|
|
@@ -219,36 +229,63 @@ class ExploreShowViewModel(
|
|
|
if (isRefresh) {
|
|
if (isRefresh) {
|
|
|
page = 1
|
|
page = 1
|
|
|
_isEnd.value = false
|
|
_isEnd.value = false
|
|
|
|
|
+ autoPageCount = 0
|
|
|
_rawBooks.value = emptyList()
|
|
_rawBooks.value = emptyList()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- kotlin.runCatching {
|
|
|
|
|
- exploreBooksUseCase.execute(source.bookSourceUrl, url, args = null, page)
|
|
|
|
|
- }.onSuccess { result ->
|
|
|
|
|
- if (result.books.isEmpty()) {
|
|
|
|
|
|
|
+ if (forceLoad) {
|
|
|
|
|
+ autoPageCount = 0
|
|
|
|
|
+ _isEnd.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fetchPage(source, url)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private suspend fun fetchPage(source: BookSource, url: String) {
|
|
|
|
|
+ kotlin.runCatching {
|
|
|
|
|
+ exploreBooksUseCase.execute(source.bookSourceUrl, url, args = null, page)
|
|
|
|
|
+ }.onSuccess { result ->
|
|
|
|
|
+ if (result.books.isEmpty()) {
|
|
|
|
|
+ page++
|
|
|
|
|
+ autoPageCount++
|
|
|
|
|
+ if (autoPageCount >= MAX_AUTO_PAGES) {
|
|
|
_isEnd.value = true
|
|
_isEnd.value = true
|
|
|
|
|
+ _isLoading.value = false
|
|
|
} else {
|
|
} else {
|
|
|
- saveSearchBooksUseCase.save(result.books)
|
|
|
|
|
|
|
+ delay(AUTO_PAGE_DELAY_MS)
|
|
|
|
|
+ fetchPage(source, url)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ saveSearchBooksUseCase.save(result.books)
|
|
|
|
|
|
|
|
- val currentList = _rawBooks.value
|
|
|
|
|
- val existingUrls = currentList.map { it.bookUrl }.toSet()
|
|
|
|
|
|
|
+ val currentList = _rawBooks.value
|
|
|
|
|
+ val existingUrls = currentList.map { it.bookUrl }.toSet()
|
|
|
|
|
|
|
|
- val uniqueNewBooks = result.books
|
|
|
|
|
- .filter { it.bookUrl !in existingUrls }
|
|
|
|
|
- .distinctBy { it.bookUrl }
|
|
|
|
|
|
|
+ val uniqueNewBooks = result.books
|
|
|
|
|
+ .filter { it.bookUrl !in existingUrls }
|
|
|
|
|
+ .distinctBy { it.bookUrl }
|
|
|
|
|
|
|
|
- if (uniqueNewBooks.isEmpty()) {
|
|
|
|
|
|
|
+ if (uniqueNewBooks.isEmpty()) {
|
|
|
|
|
+ page++
|
|
|
|
|
+ autoPageCount++
|
|
|
|
|
+ if (autoPageCount >= MAX_AUTO_PAGES) {
|
|
|
_isEnd.value = true
|
|
_isEnd.value = true
|
|
|
|
|
+ _isLoading.value = false
|
|
|
} else {
|
|
} else {
|
|
|
- _rawBooks.value = currentList + uniqueNewBooks
|
|
|
|
|
- page++
|
|
|
|
|
- _isEnd.value = false
|
|
|
|
|
|
|
+ delay(AUTO_PAGE_DELAY_MS)
|
|
|
|
|
+ fetchPage(source, url)
|
|
|
}
|
|
}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _rawBooks.value = currentList + uniqueNewBooks
|
|
|
|
|
+ page++
|
|
|
|
|
+ autoPageCount = 0
|
|
|
|
|
+ _isEnd.value = false
|
|
|
|
|
+ _isLoading.value = false
|
|
|
}
|
|
}
|
|
|
- }.onFailure {
|
|
|
|
|
- _errorMsg.value = it.stackTraceStr
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+ }.onFailure {
|
|
|
|
|
+ _errorMsg.value = it.stackTraceStr
|
|
|
_isLoading.value = false
|
|
_isLoading.value = false
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|