From 7fcd66f4073642f83f9f848ea50ac8c44630de97 Mon Sep 17 00:00:00 2001 From: Ray <154766448+damontecres@users.noreply.github.com> Date: Thu, 12 Feb 2026 21:19:33 -0500 Subject: [PATCH] Integrate nav drawer settings for default home page (#888) ## Description Customizing the home page (#803) and nav drawer (#886) were developed independently, so this PR just cleans up somethings so that those two changes work together. This PR restores the default home page when there is no customization to be the same as before: continue watching/next up row(s) followed by the order of the nav drawer libraries' recently added rows. Finally gets rid of `NavDrawerIteRepository` and related functions which all had weird, hard to follow code. ### Related issues Related to #803 & #886 ### Testing Emulator testing ## Screenshots N/A ## AI or LLM usage None --- .../wholphin/data/NavDrawerItemRepository.kt | 97 ------------------- .../wholphin/services/HomeSettingsService.kt | 34 +++---- .../wholphin/services/NavDrawerService.kt | 25 +++++ .../wholphin/ui/main/HomeViewModel.kt | 17 +--- .../ui/main/settings/HomeSettingsViewModel.kt | 20 ++-- .../damontecres/wholphin/ui/nav/NavDrawer.kt | 10 +- .../ui/preferences/PreferencesViewModel.kt | 5 - .../wholphin/test/TestHomeRowSamples.kt | 3 +- 8 files changed, 58 insertions(+), 153 deletions(-) delete mode 100644 app/src/main/java/com/github/damontecres/wholphin/data/NavDrawerItemRepository.kt diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/NavDrawerItemRepository.kt b/app/src/main/java/com/github/damontecres/wholphin/data/NavDrawerItemRepository.kt deleted file mode 100644 index 2312c62c..00000000 --- a/app/src/main/java/com/github/damontecres/wholphin/data/NavDrawerItemRepository.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.github.damontecres.wholphin.data - -import android.content.Context -import com.github.damontecres.wholphin.data.model.BaseItem -import com.github.damontecres.wholphin.data.model.NavDrawerPinnedItem -import com.github.damontecres.wholphin.data.model.NavPinType -import com.github.damontecres.wholphin.services.SeerrServerRepository -import com.github.damontecres.wholphin.ui.nav.Destination -import com.github.damontecres.wholphin.ui.nav.NavDrawerItem -import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem -import com.github.damontecres.wholphin.util.supportedCollectionTypes -import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.flow.first -import org.jellyfin.sdk.api.client.ApiClient -import org.jellyfin.sdk.api.client.extensions.liveTvApi -import org.jellyfin.sdk.api.client.extensions.userViewsApi -import org.jellyfin.sdk.model.api.CollectionType -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class NavDrawerItemRepository - @Inject - constructor( - @param:ApplicationContext private val context: Context, - private val api: ApiClient, - private val serverRepository: ServerRepository, - private val serverPreferencesDao: ServerPreferencesDao, - private val seerrServerRepository: SeerrServerRepository, - ) { - suspend fun getNavDrawerItems(): List { - val user = serverRepository.currentUser.value - val tvAccess = - serverRepository.currentUserDto.value - ?.policy - ?.enableLiveTvAccess ?: false - val userViews = - api.userViewsApi - .getUserViews(userId = user?.id) - .content.items - val recordingFolders = - if (tvAccess) { - api.liveTvApi - .getRecordingFolders(userId = user?.id) - .content.items - .map { it.id } - .toSet() - } else { - setOf() - } - - val builtins = - if (seerrServerRepository.active.first()) { - listOf(NavDrawerItem.Favorites, NavDrawerItem.Discover) - } else { - listOf(NavDrawerItem.Favorites) - } - - val libraries = - userViews - .filter { it.collectionType in supportedCollectionTypes || it.id in recordingFolders } - .map { - val destination = - if (it.id in recordingFolders) { - Destination.Recordings(it.id) - } else { - BaseItem.from(it, api).destination() - } - ServerNavDrawerItem( - itemId = it.id, - name = it.name ?: it.id.toString(), - destination = destination, - type = it.collectionType ?: CollectionType.UNKNOWN, - ) - } - return builtins + libraries - } - - suspend fun getFilteredNavDrawerItems(items: List): List { - val user = serverRepository.currentUser.value - val navDrawerPins = - user - ?.let { - serverPreferencesDao.getNavDrawerPinnedItems(it) - }.orEmpty() - val filtered = items.filter { navDrawerPins.isPinned(it.id) } - if (items.size != filtered.size) { - // Some were filtered out, check if should include More - if (navDrawerPins.isPinned(NavDrawerItem.More.id)) { - return filtered + listOf(NavDrawerItem.More) - } - } - return filtered - } - } - -fun List.isPinned(id: String) = (firstOrNull { it.itemId == id }?.type ?: NavPinType.PINNED) == NavPinType.PINNED diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt index a868692a..083d461d 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt @@ -2,7 +2,7 @@ package com.github.damontecres.wholphin.services import android.content.Context import com.github.damontecres.wholphin.R -import com.github.damontecres.wholphin.data.NavDrawerItemRepository +import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomeRowConfig @@ -12,8 +12,8 @@ import com.github.damontecres.wholphin.preferences.HomePagePreferences import com.github.damontecres.wholphin.ui.DefaultItemFields import com.github.damontecres.wholphin.ui.SlimItemFields import com.github.damontecres.wholphin.ui.components.getGenreImageMap +import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.main.settings.Library -import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.util.GetGenresRequestHandler import com.github.damontecres.wholphin.util.GetItemsRequestHandler @@ -64,8 +64,9 @@ class HomeSettingsService constructor( @param:ApplicationContext private val context: Context, private val api: ApiClient, + private val serverRepository: ServerRepository, private val userPreferencesService: UserPreferencesService, - private val navDrawerItemRepository: NavDrawerItemRepository, + private val navDrawerService: NavDrawerService, private val latestNextUpService: LatestNextUpService, private val imageUrlService: ImageUrlService, private val suggestionService: SuggestionService, @@ -233,7 +234,7 @@ class HomeSettingsService } HomePageResolvedSettings(resolvedRows) } else { - createDefault() + createDefault(userId) } currentSettings.update { resolvedSettings } @@ -251,25 +252,24 @@ class HomeSettingsService /** * Create a default [HomePageResolvedSettings] using the available libraries */ - suspend fun createDefault(): HomePageResolvedSettings { + suspend fun createDefault(userId: UUID): HomePageResolvedSettings { Timber.v("Creating default settings") - val navDrawerItems = navDrawerItemRepository.getNavDrawerItems() + val user = serverRepository.currentUser.value?.takeIf { it.id == userId } val libraries = - navDrawerItems - .filter { it is ServerNavDrawerItem } - .map { - it as ServerNavDrawerItem - Library(it.itemId, it.name, it.type) - } + if (user != null) { + navDrawerService.getFilteredUserLibraries(user) + } else { + navDrawerService.getAllUserLibraries(userId) + } + val prefs = userPreferencesService.getCurrent().appPreferences.homePagePreferences + val includedIds = - navDrawerItemRepository - .getFilteredNavDrawerItems(navDrawerItems) - .filter { it is ServerNavDrawerItem } + libraries .mapIndexed { index, it -> - val parentId = (it as ServerNavDrawerItem).itemId - val name = libraries.firstOrNull { it.itemId == parentId }?.name + val parentId = it.itemId + val name = it.name.takeIf { it.isNotNullOrBlank() } val title = name?.let { context.getString(R.string.recently_added_in, it) } ?: context.getString(R.string.recently_added) diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/NavDrawerService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/NavDrawerService.kt index 785eb676..fbce042c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/NavDrawerService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/NavDrawerService.kt @@ -8,6 +8,7 @@ import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.JellyfinUser import com.github.damontecres.wholphin.data.model.NavPinType import com.github.damontecres.wholphin.services.hilt.DefaultCoroutineScope +import com.github.damontecres.wholphin.ui.main.settings.Library import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.nav.NavDrawerItem import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem @@ -26,6 +27,7 @@ import org.jellyfin.sdk.api.client.extensions.userViewsApi import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.UserDto import timber.log.Timber +import java.util.UUID import javax.inject.Inject import javax.inject.Singleton @@ -66,6 +68,29 @@ class NavDrawerService }.launchIn(coroutineScope) } + suspend fun getAllUserLibraries(userId: UUID): List { + val userViews = + api.userViewsApi + .getUserViews(userId = userId) + .content.items + val libraries = + userViews + .filter { it.collectionType in supportedCollectionTypes } + .map { Library(it.id, it.name ?: "", it.collectionType ?: CollectionType.UNKNOWN) } + return libraries + } + + suspend fun getFilteredUserLibraries(user: JellyfinUser): List { + val pins = + serverPreferencesDao + .getNavDrawerPinnedItems(user) + .associateBy { it.itemId } + val libraries = + getAllUserLibraries(user.id) + .filterNot { pins[ServerNavDrawerItem.getId(it.itemId)]?.type == NavPinType.UNPINNED } + return libraries + } + suspend fun updateNavDrawer( user: JellyfinUser, userDto: UserDto, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomeViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomeViewModel.kt index 7ee22902..1e72830f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomeViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomeViewModel.kt @@ -3,7 +3,6 @@ package com.github.damontecres.wholphin.ui.main import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.github.damontecres.wholphin.data.NavDrawerItemRepository import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.HomeRowConfig @@ -13,11 +12,10 @@ import com.github.damontecres.wholphin.services.FavoriteWatchManager import com.github.damontecres.wholphin.services.HomePageResolvedSettings import com.github.damontecres.wholphin.services.HomeSettingsService import com.github.damontecres.wholphin.services.MediaReportService +import com.github.damontecres.wholphin.services.NavDrawerService import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.UserPreferencesService 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.showToast import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.HomeRowLoadingState @@ -46,8 +44,8 @@ class HomeViewModel @param:ApplicationContext private val context: Context, val navigationManager: NavigationManager, val serverRepository: ServerRepository, - val navDrawerItemRepository: NavDrawerItemRepository, val mediaReportService: MediaReportService, + private val navDrawerService: NavDrawerService, private val homeSettingsService: HomeSettingsService, private val favoriteWatchManager: FavoriteWatchManager, private val datePlayedService: DatePlayedService, @@ -69,17 +67,8 @@ class HomeViewModel val preferences = userPreferencesService.getCurrent() val prefs = preferences.appPreferences.homePagePreferences - 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 libraries = navDrawerService.getAllUserLibraries(userDto.id) val settings = homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY } val state = state.value diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt index 3a5f088a..53c457ff 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt @@ -7,7 +7,6 @@ import androidx.datastore.core.DataStore import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.damontecres.wholphin.R -import com.github.damontecres.wholphin.data.NavDrawerItemRepository import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.HomePageSettings @@ -26,12 +25,12 @@ import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.HomePageResolvedSettings import com.github.damontecres.wholphin.services.HomeRowConfigDisplay import com.github.damontecres.wholphin.services.HomeSettingsService +import com.github.damontecres.wholphin.services.NavDrawerService import com.github.damontecres.wholphin.services.SeerrServerRepository import com.github.damontecres.wholphin.services.UnsupportedHomeSettingsVersionException import com.github.damontecres.wholphin.services.UserPreferencesService import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope import com.github.damontecres.wholphin.ui.launchIO -import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem import com.github.damontecres.wholphin.ui.showToast import com.github.damontecres.wholphin.util.HomeRowLoadingState import com.github.damontecres.wholphin.util.LoadingState @@ -68,7 +67,7 @@ class HomeSettingsViewModel private val homeSettingsService: HomeSettingsService, private val serverRepository: ServerRepository, private val userPreferencesService: UserPreferencesService, - private val navDrawerItemRepository: NavDrawerItemRepository, + private val navDrawerService: NavDrawerService, private val backdropService: BackdropService, private val seerrServerRepository: SeerrServerRepository, val preferencesDataStore: DataStore, @@ -84,16 +83,8 @@ class HomeSettingsViewModel init { addCloseable { saveToLocal() } viewModelScope.launchIO { - val navDrawerItems = - navDrawerItemRepository - .getNavDrawerItems() - val libraries = - navDrawerItems - .filter { it is ServerNavDrawerItem } - .map { - it as ServerNavDrawerItem - Library(it.itemId, it.name, it.type) - } + val userId = serverRepository.currentUser.value?.id ?: return@launchIO + val libraries = navDrawerService.getAllUserLibraries(userId) val currentSettings = homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY } Timber.v("currentSettings=%s", currentSettings) @@ -525,8 +516,9 @@ class HomeSettingsViewModel fun resetToDefault() { viewModelScope.launchIO { + val userId = serverRepository.currentUser.value?.id ?: return@launchIO _state.update { it.copy(loading = LoadingState.Loading) } - val result = homeSettingsService.createDefault() + val result = homeSettingsService.createDefault(userId) _state.update { it.copy(rows = result.rows) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt index f1c43618..3527a95e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt @@ -65,7 +65,6 @@ import androidx.tv.material3.ProvideTextStyle import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation import com.github.damontecres.wholphin.R -import com.github.damontecres.wholphin.data.NavDrawerItemRepository import com.github.damontecres.wholphin.data.model.JellyfinServer import com.github.damontecres.wholphin.data.model.JellyfinUser import com.github.damontecres.wholphin.preferences.AppThemeColors @@ -73,7 +72,6 @@ import com.github.damontecres.wholphin.preferences.UserPreferences import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.NavDrawerService import com.github.damontecres.wholphin.services.NavigationManager -import com.github.damontecres.wholphin.services.SeerrServerRepository import com.github.damontecres.wholphin.services.SetupDestination import com.github.damontecres.wholphin.services.SetupNavigationManager import com.github.damontecres.wholphin.ui.FontAwesome @@ -98,11 +96,9 @@ class NavDrawerViewModel constructor( private val api: ApiClient, private val navDrawerService: NavDrawerService, - private val navDrawerItemRepository: NavDrawerItemRepository, val navigationManager: NavigationManager, val setupNavigationManager: SetupNavigationManager, val backdropService: BackdropService, - private val seerrServerRepository: SeerrServerRepository, ) : ViewModel() { val state = navDrawerService.state @@ -184,9 +180,13 @@ data class ServerNavDrawerItem( val destination: Destination, val type: CollectionType, ) : NavDrawerItem { - override val id: String = "s_" + itemId.toServerString() + override val id: String = getId(itemId) override fun name(context: Context): String = name + + companion object { + fun getId(itemId: UUID) = "s_" + itemId.toServerString() + } } /** diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesViewModel.kt index 4113dbea..97223b89 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/PreferencesViewModel.kt @@ -5,7 +5,6 @@ import androidx.datastore.core.DataStore import androidx.lifecycle.ViewModel import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope -import com.github.damontecres.wholphin.data.NavDrawerItemRepository import com.github.damontecres.wholphin.data.ServerPreferencesDao import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.JellyfinUser @@ -50,7 +49,6 @@ class PreferencesViewModel val backdropService: BackdropService, private val rememberTabManager: RememberTabManager, private val serverRepository: ServerRepository, - private val navDrawerItemRepository: NavDrawerItemRepository, private val navDrawerService: NavDrawerService, private val serverPreferencesDao: ServerPreferencesDao, private val seerrServerRepository: SeerrServerRepository, @@ -58,9 +56,6 @@ class PreferencesViewModel private val clientInfo: ClientInfo, ) : ViewModel(), RememberTabManager by rememberTabManager { - private lateinit var allNavDrawerItems: List -// val navDrawerPins = MutableLiveData>(emptyList()) - val navDrawerPins = navDrawerService.state .combine( diff --git a/app/src/test/java/com/github/damontecres/wholphin/test/TestHomeRowSamples.kt b/app/src/test/java/com/github/damontecres/wholphin/test/TestHomeRowSamples.kt index 3aedb3ba..675b8b26 100644 --- a/app/src/test/java/com/github/damontecres/wholphin/test/TestHomeRowSamples.kt +++ b/app/src/test/java/com/github/damontecres/wholphin/test/TestHomeRowSamples.kt @@ -121,8 +121,9 @@ class TestHomeRowSamples { HomeSettingsService( context = mockk(), api = mockk(), + serverRepository = mockk(), userPreferencesService = mockk(), - navDrawerItemRepository = mockk(), + navDrawerService = mockk(), latestNextUpService = mockk(), imageUrlService = mockk(), suggestionService = mockk(),