Refactoring switching server or user (#205)

Now when initiating a user or server switch, you can't back out of it
and must select a user/server. This will be useful when PIN code are
implemented down the road.

The app will now disconnect the web socket when backgrounded.

Also lots of internal refactoring
This commit is contained in:
damontecres 2025-11-12 17:44:16 -05:00 committed by GitHub
parent 2e3e4e3f5f
commit 58395e9adf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 442 additions and 277 deletions

View file

@ -25,7 +25,7 @@ class ItemPlaybackRepository
itemId: UUID,
item: BaseItem,
): ChosenStreams? =
serverRepository.currentUser?.let { user ->
serverRepository.currentUser.value?.let { user ->
val itemPlayback = itemPlaybackDao.getItem(user = user, itemId = itemId)
if (itemPlayback != null) {
Timber.v("Got itemPlayback for %s", itemId)
@ -72,7 +72,7 @@ class ItemPlaybackRepository
sourceId: UUID,
): ItemPlayback? =
withContext(Dispatchers.IO) {
serverRepository.currentUser?.let { user ->
serverRepository.currentUser.value?.let { user ->
val itemPlayback =
ItemPlayback(
userId = user.rowId,
@ -89,7 +89,7 @@ class ItemPlaybackRepository
itemPlayback: ItemPlayback?,
trackIndex: Int,
type: MediaStreamType,
) = serverRepository.currentUser?.let { user ->
) = serverRepository.currentUser.value?.let { user ->
var toSave =
itemPlayback ?: ItemPlayback(
userId = user.rowId,
@ -113,7 +113,9 @@ class ItemPlaybackRepository
val toSave =
if (itemPlayback.userId < 0) {
val userRowId =
serverRepository.currentUser?.rowId?.takeIf { it >= 0 }
serverRepository.currentUser.value
?.rowId
?.takeIf { it >= 0 }
?: throw IllegalStateException("Trying to save an ItemPlayback without a user, but there is no current user")
itemPlayback.copy(userId = userRowId)
} else {

View file

@ -27,7 +27,7 @@ class NavDrawerItemRepository
val user = serverRepository.currentUser
val userViews =
api.userViewsApi
.getUserViews(userId = user?.id)
.getUserViews(userId = user.value?.id)
.content.items
val builtins = listOf(NavDrawerItem.Favorites)
@ -46,7 +46,7 @@ class NavDrawerItemRepository
}
suspend fun getFilteredNavDrawerItems(items: List<NavDrawerItem>): List<NavDrawerItem> {
val user = serverRepository.currentUser
val user = serverRepository.currentUser.value
val navDrawerPins =
user
?.let {

View file

@ -2,14 +2,15 @@ package com.github.damontecres.wholphin.data
import android.content.Context
import android.content.SharedPreferences
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.content.edit
import androidx.datastore.core.DataStore
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import com.github.damontecres.wholphin.data.model.JellyfinServer
import com.github.damontecres.wholphin.data.model.JellyfinUser
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.ui.setValueOnMain
import com.github.damontecres.wholphin.ui.toServerString
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
@ -41,12 +42,12 @@ class ServerRepository
) {
private val sharedPreferences = getServerSharedPreferences(context)
private var _currentServer by mutableStateOf<JellyfinServer?>(null)
val currentServer get() = _currentServer
private var _currentUser by mutableStateOf<JellyfinUser?>(null)
val currentUser get() = _currentUser
private var _currentUserDto by mutableStateOf<UserDto?>(null)
val currentUserDto get() = _currentUserDto
private var _current = MutableLiveData<CurrentUser?>(null)
val current: LiveData<CurrentUser?> = _current
val currentServer: LiveData<JellyfinServer?> get() = _current.map { it?.server }
val currentUser: LiveData<JellyfinUser?> get() = _current.map { it?.user }
val currentUserDto: LiveData<UserDto?> get() = _current.map { it?.userDto }
/**
* Adds a server to the app database and updated the [ApiClient] to the server's URL
@ -57,19 +58,8 @@ class ServerRepository
withContext(Dispatchers.IO) {
serverDao.addOrUpdateServer(server)
}
changeServer(server)
}
/**
* Updates the [ApiClient] to the server's URL
*
* The current user is removed
*/
fun changeServer(server: JellyfinServer) {
apiClient.update(baseUrl = server.url, accessToken = null)
_currentServer = server
_currentUser = null
_currentUserDto = null
_current.setValueOnMain(null)
}
/**
@ -109,9 +99,7 @@ class ServerRepository
}.build()
}
withContext(Dispatchers.Main) {
_currentUserDto = userDto
_currentServer = updatedServer
_currentUser = updatedUser
_current.value = CurrentUser(updatedServer, updatedUser, userDto)
}
sharedPreferences.edit(true) {
putString(SERVER_URL_KEY, updatedServer.url)
@ -127,6 +115,7 @@ class ServerRepository
userId: UUID?,
): Boolean {
if (serverId == null || userId == null) {
_current.setValueOnMain(null)
return false
}
val serverAndUsers =
@ -186,8 +175,9 @@ class ServerRepository
suspend fun removeUser(user: JellyfinUser) {
if (currentUser == user) {
_currentUser = null
_currentUserDto = null
withContext(Dispatchers.Main) {
_current.value = null
}
userPreferencesDataStore.updateData {
it
.toBuilder()
@ -204,9 +194,9 @@ class ServerRepository
suspend fun removeServer(server: JellyfinServer) {
if (currentServer == server) {
_currentServer = null
_currentUser = null
_currentUserDto = null
withContext(Dispatchers.Main) {
_current.value = null
}
userPreferencesDataStore.updateData {
it
.toBuilder()
@ -222,6 +212,18 @@ class ServerRepository
}
}
suspend fun switchServerOrUser() {
apiClient.update(baseUrl = null, accessToken = null)
userPreferencesDataStore.updateData {
it
.toBuilder()
.apply {
currentServerId = ""
currentUserId = ""
}.build()
}
}
companion object {
fun getServerSharedPreferences(context: Context): SharedPreferences =
context.getSharedPreferences(
@ -233,3 +235,9 @@ class ServerRepository
const val ACCESS_TOKEN_KEY = "current.accessToken"
}
}
data class CurrentUser(
val server: JellyfinServer,
val user: JellyfinUser,
val userDto: UserDto,
)

View file

@ -1,3 +1,5 @@
@file:UseSerializers(UUIDSerializer::class)
package com.github.damontecres.wholphin.data.model
import androidx.room.ColumnInfo
@ -8,9 +10,13 @@ import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room.Relation
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import org.jellyfin.sdk.model.serializer.UUIDSerializer
import java.util.UUID
@Entity(tableName = "servers")
@Serializable
data class JellyfinServer(
@PrimaryKey val id: UUID,
val name: String?,

View file

@ -145,7 +145,7 @@ class PlaylistCreator
name: String,
initialItems: List<UUID>,
): UUID? =
serverRepository.currentUser?.let { user ->
serverRepository.currentUser.value?.let { user ->
api.playlistsApi
.createPlaylist(
CreatePlaylistDto(