mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-08-09 08:27:54 +00:00
feat: Implement ProfileStorage for managing user profiles and enhance ProfileRepository functionality
This commit is contained in:
parent
bbdf14d949
commit
69b9f5fabb
6 changed files with 118 additions and 1 deletions
|
|
@ -8,6 +8,7 @@ import com.nuvio.app.features.addons.AddonStorage
|
|||
import com.nuvio.app.features.library.LibraryStorage
|
||||
import com.nuvio.app.features.home.HomeCatalogSettingsStorage
|
||||
import com.nuvio.app.features.player.PlayerSettingsStorage
|
||||
import com.nuvio.app.features.profiles.ProfileStorage
|
||||
import com.nuvio.app.features.watched.WatchedStorage
|
||||
import com.nuvio.app.features.watchprogress.ContinueWatchingPreferencesStorage
|
||||
import com.nuvio.app.features.watchprogress.WatchProgressStorage
|
||||
|
|
@ -21,6 +22,7 @@ class MainActivity : ComponentActivity() {
|
|||
WatchedStorage.initialize(applicationContext)
|
||||
HomeCatalogSettingsStorage.initialize(applicationContext)
|
||||
PlayerSettingsStorage.initialize(applicationContext)
|
||||
ProfileStorage.initialize(applicationContext)
|
||||
ContinueWatchingPreferencesStorage.initialize(applicationContext)
|
||||
WatchProgressStorage.initialize(applicationContext)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.nuvio.app.features.profiles
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
|
||||
actual object ProfileStorage {
|
||||
private const val preferencesName = "nuvio_profile_cache"
|
||||
private const val payloadKey = "profile_payload"
|
||||
|
||||
private var preferences: SharedPreferences? = null
|
||||
|
||||
fun initialize(context: Context) {
|
||||
preferences = context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
actual fun loadPayload(): String? =
|
||||
preferences?.getString(payloadKey, null)
|
||||
|
||||
actual fun savePayload(payload: String) {
|
||||
preferences
|
||||
?.edit()
|
||||
?.putString(payloadKey, payload)
|
||||
?.apply()
|
||||
}
|
||||
}
|
||||
|
|
@ -156,8 +156,13 @@ fun App() {
|
|||
LaunchedEffect(authState) {
|
||||
when (authState) {
|
||||
is AuthState.Loading -> gateScreen = AppGateScreen.Loading.name
|
||||
is AuthState.Unauthenticated -> gateScreen = AppGateScreen.Auth.name
|
||||
is AuthState.Unauthenticated -> {
|
||||
ProfileRepository.clearInMemory()
|
||||
gateScreen = AppGateScreen.Auth.name
|
||||
}
|
||||
is AuthState.Authenticated -> {
|
||||
val authenticatedState = authState as AuthState.Authenticated
|
||||
ProfileRepository.ensureLoaded(authenticatedState.userId)
|
||||
if (gateScreen == AppGateScreen.Loading.name || gateScreen == AppGateScreen.Auth.name) {
|
||||
gateScreen = AppGateScreen.ProfileSelection.name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.nuvio.app.features.profiles
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.nuvio.app.core.auth.AuthRepository
|
||||
import com.nuvio.app.core.auth.AuthState
|
||||
import com.nuvio.app.core.network.SupabaseProvider
|
||||
import io.github.jan.supabase.postgrest.postgrest
|
||||
import io.github.jan.supabase.postgrest.rpc
|
||||
|
|
@ -11,11 +13,21 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import kotlinx.serialization.json.put
|
||||
|
||||
@Serializable
|
||||
private data class StoredProfilePayload(
|
||||
val userId: String,
|
||||
val activeProfileIndex: Int = 1,
|
||||
val profiles: List<NuvioProfile> = emptyList(),
|
||||
)
|
||||
|
||||
object ProfileRepository {
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||
private val log = Logger.withTag("ProfileRepository")
|
||||
|
|
@ -25,9 +37,47 @@ object ProfileRepository {
|
|||
val state: StateFlow<ProfileState> = _state.asStateFlow()
|
||||
|
||||
private var activeProfileIndex: Int = 1
|
||||
private var loadedCacheForUserId: String? = null
|
||||
|
||||
val activeProfileId: Int get() = activeProfileIndex
|
||||
|
||||
fun ensureLoaded(userId: String) {
|
||||
if (loadedCacheForUserId == userId && _state.value.isLoaded) return
|
||||
|
||||
loadedCacheForUserId = userId
|
||||
val payload = ProfileStorage.loadPayload().orEmpty().trim()
|
||||
if (payload.isEmpty()) {
|
||||
_state.value = ProfileState()
|
||||
activeProfileIndex = 1
|
||||
return
|
||||
}
|
||||
|
||||
val stored = runCatching {
|
||||
json.decodeFromString<StoredProfilePayload>(payload)
|
||||
}.getOrNull() ?: return
|
||||
|
||||
if (stored.userId != userId) {
|
||||
_state.value = ProfileState()
|
||||
activeProfileIndex = 1
|
||||
return
|
||||
}
|
||||
|
||||
val profiles = stored.profiles.sortedBy { it.profileIndex }
|
||||
activeProfileIndex = stored.activeProfileIndex
|
||||
_state.value = ProfileState(
|
||||
profiles = profiles,
|
||||
activeProfile = profiles.find { it.profileIndex == activeProfileIndex } ?: profiles.firstOrNull(),
|
||||
isLoaded = profiles.isNotEmpty(),
|
||||
)
|
||||
_state.value.activeProfile?.let { activeProfileIndex = it.profileIndex }
|
||||
}
|
||||
|
||||
fun clearInMemory() {
|
||||
loadedCacheForUserId = null
|
||||
activeProfileIndex = 1
|
||||
_state.value = ProfileState()
|
||||
}
|
||||
|
||||
suspend fun pullProfiles() {
|
||||
runCatching {
|
||||
val result = SupabaseProvider.client.postgrest.rpc("sync_pull_profiles")
|
||||
|
|
@ -41,6 +91,7 @@ object ProfileRepository {
|
|||
if (_state.value.activeProfile != null) {
|
||||
activeProfileIndex = _state.value.activeProfile!!.profileIndex
|
||||
}
|
||||
persist()
|
||||
}.onFailure { e ->
|
||||
log.e(e) { "Failed to pull profiles" }
|
||||
if (!_state.value.isLoaded) {
|
||||
|
|
@ -54,6 +105,7 @@ object ProfileRepository {
|
|||
_state.value = _state.value.copy(
|
||||
activeProfile = _state.value.profiles.find { it.profileIndex == profileIndex },
|
||||
)
|
||||
persist()
|
||||
}
|
||||
|
||||
suspend fun pushProfiles(profiles: List<ProfilePushPayload>) {
|
||||
|
|
@ -201,6 +253,19 @@ object ProfileRepository {
|
|||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun persist() {
|
||||
val authState = AuthRepository.state.value as? AuthState.Authenticated ?: return
|
||||
ProfileStorage.savePayload(
|
||||
json.encodeToString(
|
||||
StoredProfilePayload(
|
||||
userId = authState.userId,
|
||||
activeProfileIndex = activeProfileIndex,
|
||||
profiles = _state.value.profiles,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package com.nuvio.app.features.profiles
|
||||
|
||||
internal expect object ProfileStorage {
|
||||
fun loadPayload(): String?
|
||||
fun savePayload(payload: String)
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.nuvio.app.features.profiles
|
||||
|
||||
import platform.Foundation.NSUserDefaults
|
||||
|
||||
actual object ProfileStorage {
|
||||
private const val payloadKey = "profile_payload"
|
||||
|
||||
actual fun loadPayload(): String? =
|
||||
NSUserDefaults.standardUserDefaults.stringForKey(payloadKey)
|
||||
|
||||
actual fun savePayload(payload: String) {
|
||||
NSUserDefaults.standardUserDefaults.setObject(payload, forKey = payloadKey)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue