mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
feat: add online/offline mode toggle to HomeScreen
Implements a toggle switch in the HomeScreen top bar (next to Menu) that allows users to switch between online mode (fetching from Jellyfin server) and offline mode (using local database only). The preference persists across app restarts via Proto DataStore. Key changes: - Added ActiveMediaRepository that delegates to online/offline repositories based on user preference - Extended MediaRepository interface with continueWatching, nextUp, and latestLibraryContent - Added isOfflineMode state to UserSession with reactive Flow - Added Cloud/CloudOff icon toggle button to HomeTopBar - Updated ViewModels to use MediaRepository interface for better abstraction
This commit is contained in:
@@ -3,7 +3,7 @@ package hu.bbara.purefin.app.content.episode
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import hu.bbara.purefin.data.InMemoryMediaRepository
|
import hu.bbara.purefin.data.MediaRepository
|
||||||
import hu.bbara.purefin.data.model.Episode
|
import hu.bbara.purefin.data.model.Episode
|
||||||
import hu.bbara.purefin.navigation.NavigationManager
|
import hu.bbara.purefin.navigation.NavigationManager
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -17,7 +17,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class EpisodeScreenViewModel @Inject constructor(
|
class EpisodeScreenViewModel @Inject constructor(
|
||||||
private val mediaRepository: InMemoryMediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val navigationManager: NavigationManager,
|
private val navigationManager: NavigationManager,
|
||||||
): ViewModel() {
|
): ViewModel() {
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package hu.bbara.purefin.app.content.series
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import hu.bbara.purefin.data.InMemoryMediaRepository
|
import hu.bbara.purefin.data.MediaRepository
|
||||||
import hu.bbara.purefin.data.model.Series
|
import hu.bbara.purefin.data.model.Series
|
||||||
import hu.bbara.purefin.navigation.EpisodeDto
|
import hu.bbara.purefin.navigation.EpisodeDto
|
||||||
import hu.bbara.purefin.navigation.NavigationManager
|
import hu.bbara.purefin.navigation.NavigationManager
|
||||||
@@ -21,7 +21,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SeriesViewModel @Inject constructor(
|
class SeriesViewModel @Inject constructor(
|
||||||
private val mediaRepository: InMemoryMediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val navigationManager: NavigationManager,
|
private val navigationManager: NavigationManager,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ fun HomePage(
|
|||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val libraries = viewModel.libraries.collectAsState().value
|
val libraries = viewModel.libraries.collectAsState().value
|
||||||
|
val isOfflineMode = viewModel.isOfflineMode.collectAsState().value
|
||||||
val libraryNavItems = libraries.map {
|
val libraryNavItems = libraries.map {
|
||||||
HomeNavItem(
|
HomeNavItem(
|
||||||
id = it.id,
|
id = it.id,
|
||||||
@@ -85,7 +86,9 @@ fun HomePage(
|
|||||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||||
topBar = {
|
topBar = {
|
||||||
HomeTopBar(
|
HomeTopBar(
|
||||||
onMenuClick = { coroutineScope.launch { drawerState.open() } }
|
onMenuClick = { coroutineScope.launch { drawerState.open() } },
|
||||||
|
isOfflineMode = isOfflineMode,
|
||||||
|
onToggleOfflineMode = viewModel::toggleOfflineMode
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import hu.bbara.purefin.app.home.ui.LibraryItem
|
|||||||
import hu.bbara.purefin.app.home.ui.NextUpItem
|
import hu.bbara.purefin.app.home.ui.NextUpItem
|
||||||
import hu.bbara.purefin.app.home.ui.PosterItem
|
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||||
import hu.bbara.purefin.client.JellyfinApiClient
|
import hu.bbara.purefin.client.JellyfinApiClient
|
||||||
import hu.bbara.purefin.data.InMemoryMediaRepository
|
import hu.bbara.purefin.data.MediaRepository
|
||||||
import hu.bbara.purefin.data.model.Media
|
import hu.bbara.purefin.data.model.Media
|
||||||
import hu.bbara.purefin.domain.usecase.RefreshHomeDataUseCase
|
import hu.bbara.purefin.domain.usecase.RefreshHomeDataUseCase
|
||||||
import hu.bbara.purefin.image.JellyfinImageHelper
|
import hu.bbara.purefin.image.JellyfinImageHelper
|
||||||
@@ -34,7 +34,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class HomePageViewModel @Inject constructor(
|
class HomePageViewModel @Inject constructor(
|
||||||
private val mediaRepository: InMemoryMediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val userSessionRepository: UserSessionRepository,
|
private val userSessionRepository: UserSessionRepository,
|
||||||
private val navigationManager: NavigationManager,
|
private val navigationManager: NavigationManager,
|
||||||
private val jellyfinApiClient: JellyfinApiClient,
|
private val jellyfinApiClient: JellyfinApiClient,
|
||||||
@@ -50,6 +50,12 @@ class HomePageViewModel @Inject constructor(
|
|||||||
private val _libraries = MutableStateFlow<List<LibraryItem>>(emptyList())
|
private val _libraries = MutableStateFlow<List<LibraryItem>>(emptyList())
|
||||||
val libraries = _libraries.asStateFlow()
|
val libraries = _libraries.asStateFlow()
|
||||||
|
|
||||||
|
val isOfflineMode = userSessionRepository.isOfflineMode.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.Eagerly,
|
||||||
|
initialValue = false
|
||||||
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
loadLibraries()
|
loadLibraries()
|
||||||
@@ -213,4 +219,10 @@ class HomePageViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleOfflineMode() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
userSessionRepository.setOfflineMode(!isOfflineMode.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Cloud
|
||||||
|
import androidx.compose.material.icons.outlined.CloudOff
|
||||||
import androidx.compose.material.icons.outlined.Menu
|
import androidx.compose.material.icons.outlined.Menu
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -20,6 +22,8 @@ import hu.bbara.purefin.common.ui.components.PurefinIconButton
|
|||||||
@Composable
|
@Composable
|
||||||
fun HomeTopBar(
|
fun HomeTopBar(
|
||||||
onMenuClick: () -> Unit,
|
onMenuClick: () -> Unit,
|
||||||
|
isOfflineMode: Boolean,
|
||||||
|
onToggleOfflineMode: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
val scheme = MaterialTheme.colorScheme
|
||||||
@@ -45,6 +49,13 @@ fun HomeTopBar(
|
|||||||
onClick = onMenuClick
|
onClick = onMenuClick
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
PurefinIconButton(
|
||||||
|
icon = if (isOfflineMode) Icons.Outlined.CloudOff else Icons.Outlined.Cloud,
|
||||||
|
contentDescription = if (isOfflineMode) "Switch to Online" else "Switch to Offline",
|
||||||
|
onClick = onToggleOfflineMode
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import hu.bbara.purefin.app.home.ui.PosterItem
|
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||||
import hu.bbara.purefin.client.JellyfinApiClient
|
import hu.bbara.purefin.client.JellyfinApiClient
|
||||||
import hu.bbara.purefin.data.InMemoryMediaRepository
|
import hu.bbara.purefin.data.MediaRepository
|
||||||
import hu.bbara.purefin.data.model.Media
|
import hu.bbara.purefin.data.model.Media
|
||||||
import hu.bbara.purefin.image.JellyfinImageHelper
|
import hu.bbara.purefin.image.JellyfinImageHelper
|
||||||
import hu.bbara.purefin.navigation.MovieDto
|
import hu.bbara.purefin.navigation.MovieDto
|
||||||
@@ -26,7 +26,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class LibraryViewModel @Inject constructor(
|
class LibraryViewModel @Inject constructor(
|
||||||
private val mediaRepository: InMemoryMediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val userSessionRepository: UserSessionRepository,
|
private val userSessionRepository: UserSessionRepository,
|
||||||
private val jellyfinApiClient: JellyfinApiClient,
|
private val jellyfinApiClient: JellyfinApiClient,
|
||||||
private val navigationManager: NavigationManager
|
private val navigationManager: NavigationManager
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package hu.bbara.purefin.data
|
||||||
|
|
||||||
|
import hu.bbara.purefin.data.local.room.OfflineRepository
|
||||||
|
import hu.bbara.purefin.data.local.room.OnlineRepository
|
||||||
|
import hu.bbara.purefin.data.model.Episode
|
||||||
|
import hu.bbara.purefin.data.model.Media
|
||||||
|
import hu.bbara.purefin.data.model.Movie
|
||||||
|
import hu.bbara.purefin.data.model.Series
|
||||||
|
import hu.bbara.purefin.session.UserSessionRepository
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import java.util.UUID
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active media repository that delegates to either online or offline repository
|
||||||
|
* based on user preference.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Singleton
|
||||||
|
class ActiveMediaRepository @Inject constructor(
|
||||||
|
@OnlineRepository private val onlineRepository: MediaRepository,
|
||||||
|
@OfflineRepository private val offlineRepository: MediaRepository,
|
||||||
|
private val userSessionRepository: UserSessionRepository
|
||||||
|
) : MediaRepository {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
|
// Switch between repositories based on offline mode preference
|
||||||
|
private val activeRepository: StateFlow<MediaRepository> =
|
||||||
|
userSessionRepository.isOfflineMode
|
||||||
|
.map { isOffline ->
|
||||||
|
if (isOffline) offlineRepository else onlineRepository
|
||||||
|
}
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, onlineRepository)
|
||||||
|
|
||||||
|
// Delegate all MediaRepository interface methods to the active repository
|
||||||
|
override val movies: StateFlow<Map<UUID, Movie>> =
|
||||||
|
activeRepository.flatMapLatest { it.movies }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
override val series: StateFlow<Map<UUID, Series>> =
|
||||||
|
activeRepository.flatMapLatest { it.series }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
override val episodes: StateFlow<Map<UUID, Episode>> =
|
||||||
|
activeRepository.flatMapLatest { it.episodes }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
override val state: StateFlow<MediaRepositoryState> =
|
||||||
|
activeRepository.flatMapLatest { it.state }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, MediaRepositoryState.Loading)
|
||||||
|
|
||||||
|
override val continueWatching: StateFlow<List<Media>> =
|
||||||
|
activeRepository.flatMapLatest { it.continueWatching }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyList())
|
||||||
|
|
||||||
|
override val nextUp: StateFlow<List<Media>> =
|
||||||
|
activeRepository.flatMapLatest { it.nextUp }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyList())
|
||||||
|
|
||||||
|
override val latestLibraryContent: StateFlow<Map<UUID, List<Media>>> =
|
||||||
|
activeRepository.flatMapLatest { it.latestLibraryContent }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
override fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> =
|
||||||
|
activeRepository.flatMapLatest { it.observeSeriesWithContent(seriesId) }
|
||||||
|
|
||||||
|
override suspend fun ensureReady() {
|
||||||
|
activeRepository.value.ensureReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long) {
|
||||||
|
activeRepository.value.updateWatchProgress(mediaId, positionMs, durationMs)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun refreshHomeData() {
|
||||||
|
activeRepository.value.refreshHomeData()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,13 +65,13 @@ class InMemoryMediaRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val _continueWatching: MutableStateFlow<List<Media>> = MutableStateFlow(emptyList())
|
private val _continueWatching: MutableStateFlow<List<Media>> = MutableStateFlow(emptyList())
|
||||||
val continueWatching: StateFlow<List<Media>> = _continueWatching.asStateFlow()
|
override val continueWatching: StateFlow<List<Media>> = _continueWatching.asStateFlow()
|
||||||
|
|
||||||
private val _nextUp: MutableStateFlow<List<Media>> = MutableStateFlow(emptyList())
|
private val _nextUp: MutableStateFlow<List<Media>> = MutableStateFlow(emptyList())
|
||||||
val nextUp: StateFlow<List<Media>> = _nextUp.asStateFlow()
|
override val nextUp: StateFlow<List<Media>> = _nextUp.asStateFlow()
|
||||||
|
|
||||||
private val _latestLibraryContent: MutableStateFlow<Map<UUID, List<Media>>> = MutableStateFlow(emptyMap())
|
private val _latestLibraryContent: MutableStateFlow<Map<UUID, List<Media>>> = MutableStateFlow(emptyMap())
|
||||||
val latestLibraryContent: StateFlow<Map<UUID, List<Media>>> = _latestLibraryContent.asStateFlow()
|
override val latestLibraryContent: StateFlow<Map<UUID, List<Media>>> = _latestLibraryContent.asStateFlow()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package hu.bbara.purefin.data
|
package hu.bbara.purefin.data
|
||||||
|
|
||||||
import hu.bbara.purefin.data.model.Episode
|
import hu.bbara.purefin.data.model.Episode
|
||||||
|
import hu.bbara.purefin.data.model.Media
|
||||||
import hu.bbara.purefin.data.model.Movie
|
import hu.bbara.purefin.data.model.Movie
|
||||||
import hu.bbara.purefin.data.model.Series
|
import hu.bbara.purefin.data.model.Series
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -14,6 +15,10 @@ interface MediaRepository {
|
|||||||
val episodes: StateFlow<Map<UUID, Episode>>
|
val episodes: StateFlow<Map<UUID, Episode>>
|
||||||
val state: StateFlow<MediaRepositoryState>
|
val state: StateFlow<MediaRepositoryState>
|
||||||
|
|
||||||
|
val continueWatching: StateFlow<List<Media>>
|
||||||
|
val nextUp: StateFlow<List<Media>>
|
||||||
|
val latestLibraryContent: StateFlow<Map<UUID, List<Media>>>
|
||||||
|
|
||||||
fun observeSeriesWithContent(seriesId: UUID): Flow<Series?>
|
fun observeSeriesWithContent(seriesId: UUID): Flow<Series?>
|
||||||
|
|
||||||
suspend fun ensureReady()
|
suspend fun ensureReady()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ abstract class MediaRepositoryModule {
|
|||||||
@OfflineRepository
|
@OfflineRepository
|
||||||
abstract fun bindOfflineMediaRepository(impl: OfflineMediaRepository): MediaRepository
|
abstract fun bindOfflineMediaRepository(impl: OfflineMediaRepository): MediaRepository
|
||||||
|
|
||||||
// Default binding for backward compatibility (uses online repository)
|
// Default binding delegates to online/offline based on user preference
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindDefaultMediaRepository(impl: InMemoryMediaRepository): MediaRepository
|
abstract fun bindDefaultMediaRepository(impl: ActiveMediaRepository): MediaRepository
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package hu.bbara.purefin.data
|
|||||||
import hu.bbara.purefin.data.local.room.OfflineDatabase
|
import hu.bbara.purefin.data.local.room.OfflineDatabase
|
||||||
import hu.bbara.purefin.data.local.room.OfflineRoomMediaLocalDataSource
|
import hu.bbara.purefin.data.local.room.OfflineRoomMediaLocalDataSource
|
||||||
import hu.bbara.purefin.data.model.Episode
|
import hu.bbara.purefin.data.model.Episode
|
||||||
|
import hu.bbara.purefin.data.model.Media
|
||||||
import hu.bbara.purefin.data.model.Movie
|
import hu.bbara.purefin.data.model.Movie
|
||||||
import hu.bbara.purefin.data.model.Series
|
import hu.bbara.purefin.data.model.Series
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -42,6 +43,11 @@ class OfflineMediaRepository @Inject constructor(
|
|||||||
override val episodes: StateFlow<Map<UUID, Episode>> = localDataSource.episodesFlow
|
override val episodes: StateFlow<Map<UUID, Episode>> = localDataSource.episodesFlow
|
||||||
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
// Offline mode doesn't support these server-side features
|
||||||
|
override val continueWatching: StateFlow<List<Media>> = MutableStateFlow(emptyList())
|
||||||
|
override val nextUp: StateFlow<List<Media>> = MutableStateFlow(emptyList())
|
||||||
|
override val latestLibraryContent: StateFlow<Map<UUID, List<Media>>> = MutableStateFlow(emptyMap())
|
||||||
|
|
||||||
override fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> {
|
override fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> {
|
||||||
return localDataSource.observeSeriesWithContent(seriesId)
|
return localDataSource.observeSeriesWithContent(seriesId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ data class UserSession(
|
|||||||
val url: String,
|
val url: String,
|
||||||
@Serializable(with = UUIDSerializer::class)
|
@Serializable(with = UUIDSerializer::class)
|
||||||
val userId: UUID?,
|
val userId: UUID?,
|
||||||
val loggedIn: Boolean
|
val loggedIn: Boolean,
|
||||||
|
val isOfflineMode: Boolean = false
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -49,4 +49,12 @@ class UserSessionRepository @Inject constructor(
|
|||||||
it.copy(loggedIn = isLoggedIn)
|
it.copy(loggedIn = isLoggedIn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isOfflineMode: Flow<Boolean> = session.map { it.isOfflineMode }.distinctUntilChanged()
|
||||||
|
|
||||||
|
suspend fun setOfflineMode(isOffline: Boolean) {
|
||||||
|
userSessionDataStore.updateData {
|
||||||
|
it.copy(isOfflineMode = isOffline)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.io.OutputStream
|
|||||||
|
|
||||||
object UserSessionSerializer : Serializer<UserSession> {
|
object UserSessionSerializer : Serializer<UserSession> {
|
||||||
override val defaultValue: UserSession
|
override val defaultValue: UserSession
|
||||||
get() = UserSession(accessToken = "", url = "", loggedIn = false, userId = null)
|
get() = UserSession(accessToken = "", url = "", loggedIn = false, userId = null, isOfflineMode = false)
|
||||||
|
|
||||||
override suspend fun readFrom(input: InputStream): UserSession {
|
override suspend fun readFrom(input: InputStream): UserSession {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user