mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Fix always listing next up/continue watching rows first (#1288)
## Description Previously the home page always tried to load the "watching rows" (Next up, Continue watching, or combined) first. This meant that even if the user's customized home page did not put these rows at the top, they would always be listed first anyway. This PR fixes this so rows on the home page are always listed in the right order. ### Related issues Fixes #1275 ### Testing Emulator ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
c9cab7a5c2
commit
0e37084a16
1 changed files with 67 additions and 39 deletions
|
|
@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.selects.select
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlinx.coroutines.sync.withPermit
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -87,26 +88,30 @@ class HomeViewModel
|
||||||
// Refreshing if a load has already occurred and the rows haven't significantly changed
|
// Refreshing if a load has already occurred and the rows haven't significantly changed
|
||||||
val refresh =
|
val refresh =
|
||||||
state.loadingState == LoadingState.Success && state.settings == settings
|
state.loadingState == LoadingState.Success && state.settings == settings
|
||||||
Timber.v("refresh=$refresh, state.loadingState=${state.loadingState}")
|
Timber.v(
|
||||||
|
"refresh=%s, state.loadingState=%s, %s rows",
|
||||||
|
refresh,
|
||||||
|
state.loadingState,
|
||||||
|
settings.rows.size,
|
||||||
|
)
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
loadingState = if (refresh) LoadingState.Success else LoadingState.Loading,
|
loadingState = if (refresh) LoadingState.Success else LoadingState.Loading,
|
||||||
refreshState = LoadingState.Loading,
|
refreshState = LoadingState.Loading,
|
||||||
settings = settings,
|
settings = settings,
|
||||||
|
homeRows =
|
||||||
|
if (refresh) {
|
||||||
|
it.homeRows
|
||||||
|
} else {
|
||||||
|
List(settings.rows.size) { HomeRowLoadingState.Pending("") }
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val semaphore = Semaphore(4)
|
val semaphore = Semaphore(4)
|
||||||
|
|
||||||
val watchingRowIndexes =
|
|
||||||
settings.rows
|
|
||||||
.mapIndexedNotNull { index, row ->
|
|
||||||
if (isWatchingRow(row.config)) index else null
|
|
||||||
}
|
|
||||||
val deferred =
|
val deferred =
|
||||||
settings.rows
|
settings.rows
|
||||||
// Load the watching rows first
|
|
||||||
.sortedByDescending { isWatchingRow(it.config) }
|
|
||||||
.map { row ->
|
.map { row ->
|
||||||
viewModelScope.async(Dispatchers.IO) {
|
viewModelScope.async(Dispatchers.IO) {
|
||||||
semaphore.withPermit {
|
semaphore.withPermit {
|
||||||
|
|
@ -123,32 +128,53 @@ class HomeViewModel
|
||||||
)
|
)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Timber.e(ex, "Error on row %s", row)
|
Timber.e(ex, "Error on row %s", row)
|
||||||
HomeRowLoadingState.Error(row.title, exception = ex)
|
HomeRowLoadingState.Error(
|
||||||
|
row.title,
|
||||||
|
exception = ex,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refresh && state.homeRows.isNotEmpty() && watchingRowIndexes.isNotEmpty()) {
|
if (refresh) {
|
||||||
// Replace watching rows first
|
// Replace rows as they complete
|
||||||
Timber.v("Refreshing rows: %s", watchingRowIndexes)
|
val remaining = deferred.withIndex().toMutableList()
|
||||||
val rows =
|
while (remaining.isNotEmpty()) {
|
||||||
deferred
|
val (rowIndex, rowData) =
|
||||||
.filterIndexed { index, _ -> index in watchingRowIndexes }
|
select {
|
||||||
.awaitAll()
|
// "Return" the first remaining that is completed
|
||||||
_state.update {
|
remaining
|
||||||
|
.forEach { (rowIndex, deferred) ->
|
||||||
|
deferred.onAwait { rowIndex to it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timber.v("Got row data index=%s", rowIndex)
|
||||||
|
remaining.removeIf { it.index == rowIndex }
|
||||||
|
// Include only errors & non-empty successes
|
||||||
|
if (rowData is HomeRowLoadingState.Error ||
|
||||||
|
(rowData is HomeRowLoadingState.Success && rowData.items.isNotEmpty())
|
||||||
|
) {
|
||||||
|
_state.update { state ->
|
||||||
val newRows =
|
val newRows =
|
||||||
it.homeRows.toMutableList().apply {
|
state.homeRows.toMutableList().apply {
|
||||||
rows.forEachIndexed { index, row ->
|
set(rowIndex, rowData)
|
||||||
set(watchingRowIndexes[index], row)
|
|
||||||
}
|
}
|
||||||
}
|
state.copy(
|
||||||
it.copy(
|
|
||||||
loadingState = LoadingState.Success,
|
|
||||||
homeRows = newRows,
|
homeRows = newRows,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Timber.d("Skipping invalid row %s: %s", rowIndex, rowData)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
_state.update {
|
||||||
|
it.copy(
|
||||||
|
loadingState = LoadingState.Success,
|
||||||
|
refreshState = LoadingState.Success,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
val rows =
|
val rows =
|
||||||
deferred
|
deferred
|
||||||
.awaitAll()
|
.awaitAll()
|
||||||
|
|
@ -166,6 +192,8 @@ class HomeViewModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Timber.d("Home page load complete")
|
||||||
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Timber.e(ex, "Exception during home page loading")
|
Timber.e(ex, "Exception during home page loading")
|
||||||
if (state.value.loadingState == LoadingState.Success) {
|
if (state.value.loadingState == LoadingState.Success) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue