mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Move home page over to use custom settings
This commit is contained in:
parent
9834991392
commit
ce4f8475b0
5 changed files with 150 additions and 60 deletions
|
|
@ -265,8 +265,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
server = current.server,
|
server = current.server,
|
||||||
startDestination =
|
startDestination =
|
||||||
requestedDestination
|
requestedDestination
|
||||||
// TODO Undo
|
?: Destination.Home(),
|
||||||
?: Destination.HomeSettings,
|
|
||||||
navigationManager = navigationManager,
|
navigationManager = navigationManager,
|
||||||
preferences = preferences,
|
preferences = preferences,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
|
|
||||||
|
|
@ -309,16 +309,15 @@ class HomeSettingsService
|
||||||
userDto: UserDto,
|
userDto: UserDto,
|
||||||
libraries: List<Library>,
|
libraries: List<Library>,
|
||||||
limit: Int = prefs.maxItemsPerRow,
|
limit: Int = prefs.maxItemsPerRow,
|
||||||
): List<HomeRowLoadingState> =
|
): HomeRowLoadingState =
|
||||||
when (row) {
|
when (row) {
|
||||||
is HomeRowConfig.ContinueWatching -> {
|
is HomeRowConfig.ContinueWatching -> {
|
||||||
val resume = latestNextUpService.getResume(userDto.id, limit, true)
|
val resume = latestNextUpService.getResume(userDto.id, limit, true)
|
||||||
listOf(
|
|
||||||
HomeRowLoadingState.Success(
|
HomeRowLoadingState.Success(
|
||||||
title = context.getString(R.string.continue_watching),
|
title = context.getString(R.string.continue_watching),
|
||||||
items = resume,
|
items = resume,
|
||||||
viewOptions = row.viewOptions,
|
viewOptions = row.viewOptions,
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,12 +329,11 @@ class HomeSettingsService
|
||||||
prefs.enableRewatchingNextUp,
|
prefs.enableRewatchingNextUp,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
listOf(
|
|
||||||
HomeRowLoadingState.Success(
|
HomeRowLoadingState.Success(
|
||||||
title = context.getString(R.string.next_up),
|
title = context.getString(R.string.next_up),
|
||||||
items = nextUp,
|
items = nextUp,
|
||||||
viewOptions = row.viewOptions,
|
viewOptions = row.viewOptions,
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,16 +348,14 @@ class HomeSettingsService
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
listOf(
|
HomeRowLoadingState.Success(
|
||||||
HomeRowLoadingState.Success(
|
title = context.getString(R.string.continue_watching),
|
||||||
title = context.getString(R.string.continue_watching),
|
items =
|
||||||
items =
|
latestNextUpService.buildCombined(
|
||||||
latestNextUpService.buildCombined(
|
resume,
|
||||||
resume,
|
nextUp,
|
||||||
nextUp,
|
),
|
||||||
),
|
viewOptions = row.viewOptions,
|
||||||
viewOptions = row.viewOptions,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -397,12 +393,11 @@ class HomeSettingsService
|
||||||
val title =
|
val title =
|
||||||
name?.let { context.getString(R.string.genres_in, it) }
|
name?.let { context.getString(R.string.genres_in, it) }
|
||||||
?: context.getString(R.string.genres)
|
?: context.getString(R.string.genres)
|
||||||
listOf(
|
|
||||||
HomeRowLoadingState.Success(
|
HomeRowLoadingState.Success(
|
||||||
title,
|
title,
|
||||||
genres,
|
genres,
|
||||||
viewOptions = row.viewOptions,
|
viewOptions = row.viewOptions,
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -435,7 +430,7 @@ class HomeSettingsService
|
||||||
row.viewOptions,
|
row.viewOptions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
listOf(latest)
|
latest
|
||||||
}
|
}
|
||||||
|
|
||||||
is HomeRowConfig.RecentlyReleased -> {
|
is HomeRowConfig.RecentlyReleased -> {
|
||||||
|
|
@ -461,12 +456,10 @@ class HomeSettingsService
|
||||||
.content.items
|
.content.items
|
||||||
.map { BaseItem.Companion.from(it, api, true) }
|
.map { BaseItem.Companion.from(it, api, true) }
|
||||||
.let {
|
.let {
|
||||||
listOf(
|
HomeRowLoadingState.Success(
|
||||||
HomeRowLoadingState.Success(
|
title,
|
||||||
title,
|
it,
|
||||||
it,
|
row.viewOptions,
|
||||||
row.viewOptions,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -491,12 +484,10 @@ class HomeSettingsService
|
||||||
.content.items
|
.content.items
|
||||||
.map { BaseItem(it, true) }
|
.map { BaseItem(it, true) }
|
||||||
.let {
|
.let {
|
||||||
listOf(
|
HomeRowLoadingState.Success(
|
||||||
HomeRowLoadingState.Success(
|
name ?: context.getString(R.string.collection),
|
||||||
name ?: context.getString(R.string.collection),
|
it,
|
||||||
it,
|
row.viewOptions,
|
||||||
row.viewOptions,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -529,12 +520,10 @@ class HomeSettingsService
|
||||||
.content.items
|
.content.items
|
||||||
.map { BaseItem.Companion.from(it, api, true) }
|
.map { BaseItem.Companion.from(it, api, true) }
|
||||||
.let {
|
.let {
|
||||||
listOf(
|
HomeRowLoadingState.Success(
|
||||||
HomeRowLoadingState.Success(
|
name ?: context.getString(R.string.collection),
|
||||||
name ?: context.getString(R.string.collection),
|
it,
|
||||||
it,
|
row.viewOptions,
|
||||||
row.viewOptions,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -90,12 +91,10 @@ fun HomePage(
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.init()
|
viewModel.init()
|
||||||
}
|
}
|
||||||
val loading by viewModel.loadingState.observeAsState(LoadingState.Loading)
|
val state by viewModel.state.collectAsState()
|
||||||
val refreshing by viewModel.refreshState.observeAsState(LoadingState.Loading)
|
val loading = state.loadingState
|
||||||
val watchingRows by viewModel.watchingRows.observeAsState(listOf())
|
val refreshing = state.refreshState
|
||||||
val latestRows by viewModel.latestRows.observeAsState(listOf())
|
val homeRows = state.homeRows
|
||||||
|
|
||||||
val homeRows = remember(watchingRows, latestRows) { watchingRows + latestRows }
|
|
||||||
|
|
||||||
when (val state = loading) {
|
when (val state = loading) {
|
||||||
is LoadingState.Error -> {
|
is LoadingState.Error -> {
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,16 @@ import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.NavDrawerItemRepository
|
import com.github.damontecres.wholphin.data.NavDrawerItemRepository
|
||||||
import com.github.damontecres.wholphin.data.ServerRepository
|
import com.github.damontecres.wholphin.data.ServerRepository
|
||||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.data.model.HomePageResolvedSettings
|
||||||
import com.github.damontecres.wholphin.services.BackdropService
|
import com.github.damontecres.wholphin.services.BackdropService
|
||||||
import com.github.damontecres.wholphin.services.DatePlayedService
|
import com.github.damontecres.wholphin.services.DatePlayedService
|
||||||
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||||
|
import com.github.damontecres.wholphin.services.HomeSettingsService
|
||||||
import com.github.damontecres.wholphin.services.LatestNextUpService
|
import com.github.damontecres.wholphin.services.LatestNextUpService
|
||||||
import com.github.damontecres.wholphin.services.NavigationManager
|
import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
|
import com.github.damontecres.wholphin.ui.main.settings.Library
|
||||||
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
|
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
|
||||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||||
import com.github.damontecres.wholphin.ui.showToast
|
import com.github.damontecres.wholphin.ui.showToast
|
||||||
|
|
@ -26,7 +28,15 @@ import com.github.damontecres.wholphin.util.LoadingState
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.api.client.ApiClient
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
import org.jellyfin.sdk.model.api.CollectionType
|
import org.jellyfin.sdk.model.api.CollectionType
|
||||||
|
|
@ -44,6 +54,7 @@ class HomeViewModel
|
||||||
val navigationManager: NavigationManager,
|
val navigationManager: NavigationManager,
|
||||||
val serverRepository: ServerRepository,
|
val serverRepository: ServerRepository,
|
||||||
val navDrawerItemRepository: NavDrawerItemRepository,
|
val navDrawerItemRepository: NavDrawerItemRepository,
|
||||||
|
private val homeSettingsService: HomeSettingsService,
|
||||||
private val favoriteWatchManager: FavoriteWatchManager,
|
private val favoriteWatchManager: FavoriteWatchManager,
|
||||||
private val datePlayedService: DatePlayedService,
|
private val datePlayedService: DatePlayedService,
|
||||||
private val latestNextUpService: LatestNextUpService,
|
private val latestNextUpService: LatestNextUpService,
|
||||||
|
|
@ -55,7 +66,8 @@ class HomeViewModel
|
||||||
val watchingRows = MutableLiveData<List<HomeRowLoadingState>>(listOf())
|
val watchingRows = MutableLiveData<List<HomeRowLoadingState>>(listOf())
|
||||||
val latestRows = MutableLiveData<List<HomeRowLoadingState>>(listOf())
|
val latestRows = MutableLiveData<List<HomeRowLoadingState>>(listOf())
|
||||||
|
|
||||||
private lateinit var preferences: UserPreferences
|
private val _state = MutableStateFlow(HomeState.EMPTY)
|
||||||
|
val state: StateFlow<HomeState> = _state
|
||||||
|
|
||||||
init {
|
init {
|
||||||
datePlayedService.invalidateAll()
|
datePlayedService.invalidateAll()
|
||||||
|
|
@ -76,12 +88,86 @@ class HomeViewModel
|
||||||
loadingState.setValueOnMain(LoadingState.Loading)
|
loadingState.setValueOnMain(LoadingState.Loading)
|
||||||
}
|
}
|
||||||
refreshState.setValueOnMain(LoadingState.Loading)
|
refreshState.setValueOnMain(LoadingState.Loading)
|
||||||
this@HomeViewModel.preferences = userPreferencesService.getCurrent()
|
val preferences = userPreferencesService.getCurrent()
|
||||||
val prefs = preferences.appPreferences.homePagePreferences
|
val prefs = preferences.appPreferences.homePagePreferences
|
||||||
val limit = prefs.maxItemsPerRow
|
val limit = prefs.maxItemsPerRow
|
||||||
if (reload) {
|
if (reload) {
|
||||||
backdropService.clearBackdrop()
|
backdropService.clearBackdrop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val navDrawerItems =
|
||||||
|
navDrawerItemRepository
|
||||||
|
.getNavDrawerItems()
|
||||||
|
val libraries =
|
||||||
|
navDrawerItems
|
||||||
|
.filter { it is ServerNavDrawerItem }
|
||||||
|
.map {
|
||||||
|
it as ServerNavDrawerItem
|
||||||
|
Library(it.itemId, it.name, it.type)
|
||||||
|
}
|
||||||
|
serverRepository.currentUserDto.value?.let { userDto ->
|
||||||
|
val settings =
|
||||||
|
homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY }
|
||||||
|
val state = state.value
|
||||||
|
|
||||||
|
// Refreshing if a load has already occurred and the rows haven't significantly changed
|
||||||
|
val refresh =
|
||||||
|
state.loadingState == LoadingState.Success && state.settings == settings
|
||||||
|
|
||||||
|
val semaphore = Semaphore(4)
|
||||||
|
val loadingRows =
|
||||||
|
if (refresh) {
|
||||||
|
state.homeRows
|
||||||
|
} else {
|
||||||
|
mutableListOf()
|
||||||
|
}
|
||||||
|
val deferred =
|
||||||
|
settings.rows.mapIndexed { index, row ->
|
||||||
|
if (refresh) {
|
||||||
|
(loadingRows as MutableList).add(HomeRowLoadingState.Loading(row.title))
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.async(Dispatchers.IO) {
|
||||||
|
semaphore.withPermit {
|
||||||
|
Timber.v("Fetching row: %s", row)
|
||||||
|
try {
|
||||||
|
homeSettingsService.fetchDataForRow(
|
||||||
|
row = row.config,
|
||||||
|
scope = viewModelScope,
|
||||||
|
prefs = prefs,
|
||||||
|
userDto = userDto,
|
||||||
|
libraries = libraries,
|
||||||
|
limit = prefs.maxItemsPerRow,
|
||||||
|
)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex, "Error on row %s", row)
|
||||||
|
HomeRowLoadingState.Error(row.title, exception = ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refresh) {
|
||||||
|
deferred.firstOrNull()?.await()?.let {
|
||||||
|
(loadingRows as MutableList)[0] = it
|
||||||
|
}
|
||||||
|
_state.update {
|
||||||
|
it.copy(
|
||||||
|
loadingState = LoadingState.Success,
|
||||||
|
homeRows = loadingRows,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val rows = deferred.awaitAll()
|
||||||
|
Timber.v("Got all rows")
|
||||||
|
_state.update {
|
||||||
|
it.copy(
|
||||||
|
loadingState = LoadingState.Success,
|
||||||
|
refreshState = LoadingState.Success,
|
||||||
|
homeRows = rows,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverRepository.currentUserDto.value?.let { userDto ->
|
serverRepository.currentUserDto.value?.let { userDto ->
|
||||||
val includedIds =
|
val includedIds =
|
||||||
|
|
@ -192,3 +278,20 @@ data class LatestData(
|
||||||
val title: String,
|
val title: String,
|
||||||
val request: GetLatestMediaRequest,
|
val request: GetLatestMediaRequest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class HomeState(
|
||||||
|
val loadingState: LoadingState,
|
||||||
|
val refreshState: LoadingState,
|
||||||
|
val homeRows: List<HomeRowLoadingState>,
|
||||||
|
val settings: HomePageResolvedSettings,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val EMPTY =
|
||||||
|
HomeState(
|
||||||
|
LoadingState.Pending,
|
||||||
|
LoadingState.Pending,
|
||||||
|
listOf(),
|
||||||
|
HomePageResolvedSettings.EMPTY,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ class HomeSettingsViewModel
|
||||||
libraries = state.libraries,
|
libraries = state.libraries,
|
||||||
limit = limit,
|
limit = limit,
|
||||||
)
|
)
|
||||||
}.flatten()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows?.let { rows ->
|
rows?.let { rows ->
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue