Save remembered tabs per user (#57)

If the remember tab setting is enabled, tabs will be remembered per user
profile now
This commit is contained in:
damontecres 2025-10-22 19:24:17 -04:00 committed by GitHub
parent f5ee5eceab
commit b5771db54e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 98 additions and 39 deletions

View file

@ -3,13 +3,23 @@ package com.github.damontecres.wholphin.hilt
import android.annotation.SuppressLint
import android.content.Context
import android.provider.Settings
import androidx.datastore.core.DataStore
import com.github.damontecres.wholphin.BuildConfig
import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.preferences.updateInterfacePreferences
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.RememberTabManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import org.jellyfin.sdk.Jellyfin
import org.jellyfin.sdk.api.client.util.AuthorizationHeaderBuilder
@ -17,6 +27,7 @@ import org.jellyfin.sdk.api.okhttp.OkHttpFactory
import org.jellyfin.sdk.createJellyfin
import org.jellyfin.sdk.model.ClientInfo
import org.jellyfin.sdk.model.DeviceInfo
import java.util.UUID
import javax.inject.Qualifier
import javax.inject.Singleton
@ -28,6 +39,10 @@ annotation class AuthOkHttpClient
@Retention(AnnotationRetention.BINARY)
annotation class StandardOkHttpClient
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class IoCoroutineScope
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@ -118,4 +133,51 @@ object AppModule {
@Provides
@Singleton
fun apiClient(jellyfin: Jellyfin) = jellyfin.createApi()
/**
* Implementation of [RememberTabManager] which remembers by server, user, & item
*/
@Provides
@Singleton
fun rememberTabManager(
serverRepository: ServerRepository,
appPreference: DataStore<AppPreferences>,
@IoCoroutineScope scope: CoroutineScope,
) = object : RememberTabManager {
fun key(itemId: UUID) = "${serverRepository.currentServer?.id}_${serverRepository.currentUser?.id}_$itemId"
override fun getRememberedTab(
preferences: UserPreferences,
itemId: UUID,
defaultTab: Int,
): Int {
if (preferences.appPreferences.interfacePreferences.rememberSelectedTab) {
return preferences.appPreferences.interfacePreferences
.getRememberedTabsOrDefault(key(itemId), defaultTab)
} else {
return defaultTab
}
}
override fun saveRememberedTab(
preferences: UserPreferences,
itemId: UUID,
tabIndex: Int,
) {
if (preferences.appPreferences.interfacePreferences.rememberSelectedTab) {
scope.launch(ExceptionHandler()) {
appPreference.updateData {
preferences.appPreferences.updateInterfacePreferences {
putRememberedTabs(key(itemId), tabIndex)
}
}
}
}
}
}
@Provides
@Singleton
@IoCoroutineScope
fun ioCoroutineScope(): CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
}

View file

@ -3,10 +3,8 @@ package com.github.damontecres.wholphin.preferences
import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import com.google.protobuf.InvalidProtocolBufferException
import timber.log.Timber
import java.io.InputStream
import java.io.OutputStream
import java.util.UUID
import javax.inject.Inject
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.seconds
@ -108,13 +106,3 @@ inline fun AppPreferences.updateInterfacePreferences(block: InterfacePreferences
update {
interfacePreferences = interfacePreferences.toBuilder().apply(block).build()
}
fun AppPreferences.rememberTab(
itemId: UUID,
index: Int,
): AppPreferences {
Timber.v("Updating $itemId tab to $index")
return updateInterfacePreferences {
putRememberedTabs(itemId.toString(), index)
}
}

View file

@ -32,7 +32,6 @@ import androidx.tv.material3.Text
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.GetItemsFilter
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.preferences.rememberTab
import com.github.damontecres.wholphin.ui.components.CollectionFolderGrid
import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.GenreCardGrid
@ -50,13 +49,8 @@ fun CollectionFolderMovie(
modifier: Modifier = Modifier,
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
) {
val uiPrefs = preferences.appPreferences.interfacePreferences
val rememberedTabIndex =
if (uiPrefs.rememberSelectedTab) {
uiPrefs.getRememberedTabsOrDefault(destination.itemId.toString(), 0)
} else {
0
}
remember { preferencesViewModel.getRememberedTab(preferences, destination.itemId, 0) }
val tabs = listOf("Recommended", "Library", "Genres")
var focusTabIndex by rememberSaveable { mutableIntStateOf(rememberedTabIndex) }
@ -66,13 +60,10 @@ fun CollectionFolderMovie(
val firstTabFocusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) { firstTabFocusRequester.tryRequestFocus() }
if (uiPrefs.rememberSelectedTab) {
LaunchedEffect(selectedTabIndex) {
preferencesViewModel.preferenceDataStore.updateData {
preferences.appPreferences.rememberTab(destination.itemId, selectedTabIndex)
}
}
LaunchedEffect(selectedTabIndex) {
preferencesViewModel.saveRememberedTab(preferences, destination.itemId, selectedTabIndex)
}
var showHeader by rememberSaveable { mutableStateOf(true) }
val onClickItem = { item: BaseItem ->

View file

@ -32,7 +32,6 @@ import androidx.tv.material3.Text
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.GetItemsFilter
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.preferences.rememberTab
import com.github.damontecres.wholphin.ui.components.CollectionFolderGrid
import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.GenreCardGrid
@ -50,13 +49,8 @@ fun CollectionFolderTv(
modifier: Modifier = Modifier,
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
) {
val uiPrefs = preferences.appPreferences.interfacePreferences
val rememberedTabIndex =
if (uiPrefs.rememberSelectedTab) {
uiPrefs.getRememberedTabsOrDefault(destination.itemId.toString(), 0)
} else {
0
}
remember { preferencesViewModel.getRememberedTab(preferences, destination.itemId, 0) }
val tabs = listOf("Recommended", "Library", "Genres")
var focusTabIndex by rememberSaveable { mutableIntStateOf(rememberedTabIndex) }
@ -66,13 +60,10 @@ fun CollectionFolderTv(
val firstTabFocusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) { firstTabFocusRequester.tryRequestFocus() }
if (uiPrefs.rememberSelectedTab) {
LaunchedEffect(selectedTabIndex) {
preferencesViewModel.preferenceDataStore.updateData {
preferences.appPreferences.rememberTab(destination.itemId, selectedTabIndex)
}
}
LaunchedEffect(selectedTabIndex) {
preferencesViewModel.saveRememberedTab(preferences, destination.itemId, selectedTabIndex)
}
val onClickItem = { item: BaseItem ->
preferencesViewModel.navigationManager.navigateTo(item.destination())
}

View file

@ -4,6 +4,7 @@ import androidx.datastore.core.DataStore
import androidx.lifecycle.ViewModel
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.ui.nav.NavigationManager
import com.github.damontecres.wholphin.util.RememberTabManager
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@ -13,4 +14,6 @@ class PreferencesViewModel
constructor(
val preferenceDataStore: DataStore<AppPreferences>,
val navigationManager: NavigationManager,
) : ViewModel()
val rememberTabManager: RememberTabManager,
) : ViewModel(),
RememberTabManager by rememberTabManager

View file

@ -0,0 +1,24 @@
package com.github.damontecres.wholphin.util
import com.github.damontecres.wholphin.preferences.UserPreferences
import java.util.UUID
interface RememberTabManager {
/**
* If enabled, get the remembered tab index for the given item
*/
fun getRememberedTab(
preferences: UserPreferences,
itemId: UUID,
defaultTab: Int,
): Int
/**
* If enabled, save the remembered tab index for the given item
*/
fun saveRememberedTab(
preferences: UserPreferences,
itemId: UUID,
tabIndex: Int,
)
}