local mode stored into local database

This commit is contained in:
m
2026-09-12 14:11:22 +02:00
parent e314f63760
commit 22858e38ce
4 changed files with 25 additions and 5 deletions
@@ -4,19 +4,22 @@ import com.vaultdrop.mobile.data.remote.ApiClient
import com.vaultdrop.mobile.data.remote.dto.LoginResponseDto import com.vaultdrop.mobile.data.remote.dto.LoginResponseDto
import com.vaultdrop.mobile.domain.ActiveUserStore import com.vaultdrop.mobile.domain.ActiveUserStore
import com.vaultdrop.mobile.domain.DeviceIdentity import com.vaultdrop.mobile.domain.DeviceIdentity
import com.vaultdrop.mobile.domain.LocalModeStore
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
/** /**
* Orchestration de la session (restauration/sauvegarde/purge) : relie le store * Orchestration de la session (restauration/sauvegarde/purge) : relie le store
* sécurisé, le miroir `active_user_id` et le token en mémoire lu par * sécurisé, le miroir `active_user_id` et le token en mémoire lu par
* `AuthInterceptor`. * `AuthInterceptor`. Le drapeau « mode local » est persisté à part
* ([LocalModeStore]) pour survivre aux redémarrages.
*/ */
@Singleton @Singleton
class SessionManager @Inject constructor( class SessionManager @Inject constructor(
private val secureTokenStore: SecureTokenStore, private val secureTokenStore: SecureTokenStore,
private val activeUserStore: ActiveUserStore, private val activeUserStore: ActiveUserStore,
private val tokenProvider: TokenProvider, private val tokenProvider: TokenProvider,
private val localModeStore: LocalModeStore,
) { ) {
/** Restaure la session persistée (si présente), sinon null. */ /** Restaure la session persistée (si présente), sinon null. */
@@ -30,6 +33,7 @@ class SessionManager @Inject constructor(
suspend fun save(token: String, user: com.vaultdrop.mobile.data.remote.dto.UserDto) { suspend fun save(token: String, user: com.vaultdrop.mobile.data.remote.dto.UserDto) {
secureTokenStore.save(token, user) secureTokenStore.save(token, user)
activeUserStore.set(user.id) activeUserStore.set(user.id)
localModeStore.clear()
tokenProvider.current = token tokenProvider.current = token
} }
@@ -38,6 +42,12 @@ class SessionManager @Inject constructor(
activeUserStore.clear() activeUserStore.clear()
tokenProvider.current = null tokenProvider.current = null
} }
suspend fun isLocalMode(): Boolean = localModeStore.get()
suspend fun setLocalMode() = localModeStore.set()
suspend fun clearLocalMode() = localModeStore.clear()
} }
data class AuthSession( data class AuthSession(
@@ -7,7 +7,8 @@ import androidx.room.PrimaryKey
/** /**
* Miroir de la table `user_preferences` JS (`key`/`value`/`updated_at`). * Miroir de la table `user_preferences` JS (`key`/`value`/`updated_at`).
* Clés connues : `device_user_id` (32-hex, généré une fois), `sync_mode`, * Clés connues : `device_user_id` (32-hex, généré une fois), `sync_mode`,
* `active_user_id` (miroir non-sensible du compte connecté). * `active_user_id` (miroir non-sensible du compte connecté), `local_mode`
* (app utilisée sans compte).
*/ */
@Entity(tableName = "user_preferences") @Entity(tableName = "user_preferences")
data class UserPreferenceEntity( data class UserPreferenceEntity(
@@ -4,6 +4,7 @@ package com.vaultdrop.mobile.domain
object PrefKeys { object PrefKeys {
const val DEVICE_USER_ID = "device_user_id" const val DEVICE_USER_ID = "device_user_id"
const val ACTIVE_USER_ID = "active_user_id" const val ACTIVE_USER_ID = "active_user_id"
const val LOCAL_MODE = "local_mode"
const val SYNC_MODE = "sync_mode" const val SYNC_MODE = "sync_mode"
const val THEME = "theme" const val THEME = "theme"
const val SERVER_URL = "server_url" const val SERVER_URL = "server_url"
@@ -37,8 +37,11 @@ class AuthViewModel @Inject constructor(
viewModelScope.launch { viewModelScope.launch {
val session = sessionManager.restore() val session = sessionManager.restore()
_authState.value = _authState.value = when {
if (session != null) AuthState.SignedIn(session.user) else AuthState.SignedOut session != null -> AuthState.SignedIn(session.user)
sessionManager.isLocalMode() -> AuthState.Local
else -> AuthState.SignedOut
}
authRepository.registerDevice() authRepository.registerDevice()
} }
} }
@@ -67,7 +70,10 @@ class AuthViewModel @Inject constructor(
} }
fun continueWithoutAccount() { fun continueWithoutAccount() {
_authState.value = AuthState.Local viewModelScope.launch {
sessionManager.setLocalMode()
_authState.value = AuthState.Local
}
} }
/** Purge la session et revient en mode local (sans repasser par le login). */ /** Purge la session et revient en mode local (sans repasser par le login). */
@@ -76,6 +82,7 @@ class AuthViewModel @Inject constructor(
Timber.d("auth: session purgée (mode local)") Timber.d("auth: session purgée (mode local)")
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
sessionManager.clear() sessionManager.clear()
sessionManager.setLocalMode()
} }
_authState.value = AuthState.Local _authState.value = AuthState.Local
} }
@@ -86,6 +93,7 @@ class AuthViewModel @Inject constructor(
Timber.d("auth: session purgée (signOut)") Timber.d("auth: session purgée (signOut)")
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
sessionManager.clear() sessionManager.clear()
sessionManager.clearLocalMode()
} }
_authState.value = AuthState.SignedOut _authState.value = AuthState.SignedOut
} }