fix(posts, search, inbox, settings): reset defaults after logout

This commit is contained in:
Diego Beraldin 2023-09-10 22:14:47 +02:00
parent cc8e26f33f
commit 1b8d8828e6
17 changed files with 133 additions and 23 deletions

View File

@ -15,6 +15,7 @@ interface NotificationCenter {
sealed interface Event { sealed interface Event {
data class PostUpdate(val post: PostModel) : Event data class PostUpdate(val post: PostModel) : Event
data class CommentUpdate(val comment: CommentModel) : Event data class CommentUpdate(val comment: CommentModel) : Event
object Logout : Event
} }
/** /**

View File

@ -17,7 +17,6 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toSortType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -84,21 +83,50 @@ class PostListViewModel(
it.copy(isLogged = isLogged) it.copy(isLogged = isLogged)
} }
}.launchIn(this) }.launchIn(this)
notificationCenter.events.filterIsInstance<NotificationCenter.Event.PostUpdate>() notificationCenter.events
.onEach { evt -> .onEach { evt ->
val newPost = evt.post when (evt) {
mvi.updateState { is NotificationCenter.Event.PostUpdate -> {
it.copy( val newPost = evt.post
posts = it.posts.map { p -> mvi.updateState {
if (p.id == newPost.id) { it.copy(
newPost posts = it.posts.map { p ->
} else { if (p.id == newPost.id) {
p newPost
} } else {
}, p
) }
},
)
}
}
else -> Unit
} }
}.launchIn(this) }.launchIn(this)
notificationCenter.events
.onEach { evt ->
when (evt) {
NotificationCenter.Event.Logout -> {
currentPage = 1
val listingType =
keyStore[KeyStoreKeys.DefaultListingType, 0].toListingType()
val sortType =
keyStore[KeyStoreKeys.DefaultPostSortType, 0].toSortType()
mvi.updateState {
it.copy(
listingType = listingType,
sortType = sortType,
posts = emptyList(),
isLogged = false,
)
}
}
else -> Unit
}
}.launchIn(this)
} }
if (mvi.uiState.value.posts.isEmpty()) { if (mvi.uiState.value.posts.isEmpty()) {

View File

@ -53,6 +53,7 @@ kotlin {
implementation(projects.coreAppearance) implementation(projects.coreAppearance)
implementation(projects.coreCommonui) implementation(projects.coreCommonui)
implementation(projects.coreUtils) implementation(projects.coreUtils)
implementation(projects.coreNotifications)
implementation(projects.domainLemmy.data) implementation(projects.domainLemmy.data)
implementation(projects.domainLemmy.repository) implementation(projects.domainLemmy.repository)

View File

@ -31,6 +31,7 @@ val inboxTabModule = module {
siteRepository = get(), siteRepository = get(),
hapticFeedback = get(), hapticFeedback = get(),
coordinator = get(), coordinator = get(),
notificationCenter = get(),
) )
} }
factory { factory {
@ -40,6 +41,7 @@ val inboxTabModule = module {
identityRepository = get(), identityRepository = get(),
hapticFeedback = get(), hapticFeedback = get(),
coordinator = get(), coordinator = get(),
notificationCenter = get(),
) )
} }
} }

View File

@ -4,6 +4,7 @@ import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.racconforlemmy.core.utils.HapticFeedback import com.github.diegoberaldin.racconforlemmy.core.utils.HapticFeedback
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
@ -23,6 +24,7 @@ class InboxMentionsViewModel(
private val userRepository: UserRepository, private val userRepository: UserRepository,
private val hapticFeedback: HapticFeedback, private val hapticFeedback: HapticFeedback,
private val coordinator: InboxCoordinator, private val coordinator: InboxCoordinator,
private val notificationCenter: NotificationCenter,
) : ScreenModel, ) : ScreenModel,
MviModel<InboxMentionsMviModel.Intent, InboxMentionsMviModel.UiState, InboxMentionsMviModel.Effect> by mvi { MviModel<InboxMentionsMviModel.Intent, InboxMentionsMviModel.UiState, InboxMentionsMviModel.Effect> by mvi {
@ -41,6 +43,15 @@ class InboxMentionsViewModel(
changeUnreadOnly(it) changeUnreadOnly(it)
} }
}.launchIn(this) }.launchIn(this)
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.Logout -> {
mvi.updateState { it.copy(mentions = emptyList()) }
}
else -> Unit
}
}.launchIn(this)
} }
} }

View File

@ -19,7 +19,7 @@ interface InboxRepliesMviModel :
val loading: Boolean = false, val loading: Boolean = false,
val canFetchMore: Boolean = true, val canFetchMore: Boolean = true,
val unreadOnly: Boolean = true, val unreadOnly: Boolean = true,
val mentions: List<PersonMentionModel> = emptyList(), val replies: List<PersonMentionModel> = emptyList(),
) )
sealed interface Effect sealed interface Effect

View File

@ -25,7 +25,6 @@ import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -45,10 +44,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCo
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxRepliesViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxRepliesViewModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxMviModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
class InboxRepliesScreen : Tab { class InboxRepliesScreen : Tab {
override val options: TabOptions override val options: TabOptions
@ -74,7 +69,7 @@ class InboxRepliesScreen : Tab {
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(Spacing.xs), verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) { ) {
items(uiState.mentions) { mention -> items(uiState.replies) { mention ->
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
backgroundColor = { backgroundColor = {

View File

@ -4,6 +4,7 @@ import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.racconforlemmy.core.utils.HapticFeedback import com.github.diegoberaldin.racconforlemmy.core.utils.HapticFeedback
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository
@ -26,6 +27,7 @@ class InboxRepliesViewModel(
private val siteRepository: SiteRepository, private val siteRepository: SiteRepository,
private val hapticFeedback: HapticFeedback, private val hapticFeedback: HapticFeedback,
private val coordinator: InboxCoordinator, private val coordinator: InboxCoordinator,
private val notificationCenter: NotificationCenter,
) : ScreenModel, ) : ScreenModel,
MviModel<InboxRepliesMviModel.Intent, InboxRepliesMviModel.UiState, InboxRepliesMviModel.Effect> by mvi { MviModel<InboxRepliesMviModel.Intent, InboxRepliesMviModel.UiState, InboxRepliesMviModel.Effect> by mvi {
@ -44,6 +46,15 @@ class InboxRepliesViewModel(
changeUnreadOnly(it) changeUnreadOnly(it)
} }
}.launchIn(this) }.launchIn(this)
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.Logout -> {
mvi.updateState { it.copy(replies = emptyList()) }
}
else -> Unit
}
}.launchIn(this)
} }
} }
@ -103,10 +114,10 @@ class InboxRepliesViewModel(
val newItems = if (refreshing) { val newItems = if (refreshing) {
itemList itemList
} else { } else {
it.mentions + itemList it.replies + itemList
} }
it.copy( it.copy(
mentions = newItems, replies = newItems,
loading = false, loading = false,
canFetchMore = canFetchMore, canFetchMore = canFetchMore,
refreshing = false, refreshing = false,

View File

@ -56,6 +56,8 @@ kotlin {
implementation(projects.coreUtils) implementation(projects.coreUtils)
implementation(projects.coreMd) implementation(projects.coreMd)
implementation(projects.coreCommonui) implementation(projects.coreCommonui)
implementation(projects.corePreferences)
implementation(projects.coreNotifications)
implementation(projects.domainIdentity) implementation(projects.domainIdentity)
implementation(projects.domainLemmy.data) implementation(projects.domainLemmy.data)
implementation(projects.domainLemmy.repository) implementation(projects.domainLemmy.repository)

View File

@ -3,6 +3,9 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.profile.content
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -10,6 +13,8 @@ import kotlinx.coroutines.flow.onEach
class ProfileContentViewModel( class ProfileContentViewModel(
private val mvi: DefaultMviModel<ProfileContentMviModel.Intent, ProfileContentMviModel.UiState, ProfileContentMviModel.Effect>, private val mvi: DefaultMviModel<ProfileContentMviModel.Intent, ProfileContentMviModel.UiState, ProfileContentMviModel.Effect>,
private val identityRepository: IdentityRepository, private val identityRepository: IdentityRepository,
private val keyStore: TemporaryKeyStore,
private val notificationCenter: NotificationCenter,
) : ScreenModel, ) : ScreenModel,
MviModel<ProfileContentMviModel.Intent, ProfileContentMviModel.UiState, ProfileContentMviModel.Effect> by mvi { MviModel<ProfileContentMviModel.Intent, ProfileContentMviModel.UiState, ProfileContentMviModel.Effect> by mvi {
@ -23,7 +28,15 @@ class ProfileContentViewModel(
override fun reduce(intent: ProfileContentMviModel.Intent) { override fun reduce(intent: ProfileContentMviModel.Intent) {
when (intent) { when (intent) {
ProfileContentMviModel.Intent.Logout -> identityRepository.clearToken() ProfileContentMviModel.Intent.Logout -> logout()
} }
} }
private fun logout() {
keyStore.save(KeyStoreKeys.DefaultListingType, 0)
keyStore.save(KeyStoreKeys.DefaultCommentSortType, 13)
keyStore.save(KeyStoreKeys.DefaultPostSortType, 0)
identityRepository.clearToken()
notificationCenter.send(NotificationCenter.Event.Logout)
}
} }

View File

@ -18,6 +18,8 @@ val profileTabModule = module {
ProfileContentViewModel( ProfileContentViewModel(
mvi = DefaultMviModel(ProfileContentMviModel.UiState()), mvi = DefaultMviModel(ProfileContentMviModel.UiState()),
identityRepository = get(), identityRepository = get(),
keyStore = get(),
notificationCenter = get(),
) )
} }
factory { factory {

View File

@ -53,6 +53,7 @@ kotlin {
implementation(projects.coreUtils) implementation(projects.coreUtils)
implementation(projects.corePreferences) implementation(projects.corePreferences)
implementation(projects.coreCommonui) implementation(projects.coreCommonui)
implementation(projects.coreNotifications)
implementation(projects.domainIdentity) implementation(projects.domainIdentity)
implementation(projects.domainLemmy.data) implementation(projects.domainLemmy.data)

View File

@ -3,6 +3,7 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.search.communitylist
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiConfigurationRepository import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiConfigurationRepository
@ -26,6 +27,7 @@ class CommunityListViewModel(
private val identityRepository: IdentityRepository, private val identityRepository: IdentityRepository,
private val communityRepository: CommunityRepository, private val communityRepository: CommunityRepository,
private val keyStore: TemporaryKeyStore, private val keyStore: TemporaryKeyStore,
private val notificationCenter: NotificationCenter,
) : ScreenModel, ) : ScreenModel,
MviModel<CommunityListMviModel.Intent, CommunityListMviModel.UiState, CommunityListMviModel.Effect> by mvi { MviModel<CommunityListMviModel.Intent, CommunityListMviModel.UiState, CommunityListMviModel.Effect> by mvi {
@ -45,6 +47,21 @@ class CommunityListViewModel(
it.copy(isLogged = isLogged) it.copy(isLogged = isLogged)
} }
}.launchIn(this) }.launchIn(this)
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.Logout -> {
currentPage = 1
mvi.updateState {
it.copy(
listingType = ListingType.Local,
communities = emptyList(),
)
}
}
else -> Unit
}
}.launchIn(this)
} }
if (mvi.uiState.value.communities.isEmpty()) { if (mvi.uiState.value.communities.isEmpty()) {

View File

@ -13,6 +13,7 @@ val searchTabModule = module {
identityRepository = get(), identityRepository = get(),
communityRepository = get(), communityRepository = get(),
keyStore = get(), keyStore = get(),
notificationCenter = get(),
) )
} }
} }

View File

@ -51,6 +51,7 @@ kotlin {
implementation(projects.coreArchitecture) implementation(projects.coreArchitecture)
implementation(projects.coreUtils) implementation(projects.coreUtils)
implementation(projects.coreCommonui) implementation(projects.coreCommonui)
implementation(projects.coreNotifications)
implementation(projects.resources) implementation(projects.resources)
implementation(projects.domainLemmy.data) implementation(projects.domainLemmy.data)
implementation(projects.domainIdentity) implementation(projects.domainIdentity)

View File

@ -9,6 +9,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository.Theme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ColorSchemeProvider import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ColorSchemeProvider
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
@ -30,6 +31,7 @@ class SettingsScreenViewModel(
private val languageRepository: LanguageRepository, private val languageRepository: LanguageRepository,
private val identityRepository: IdentityRepository, private val identityRepository: IdentityRepository,
private val keyStore: TemporaryKeyStore, private val keyStore: TemporaryKeyStore,
private val notificationCenter: NotificationCenter,
) : ScreenModel, ) : ScreenModel,
MviModel<SettingsScreenMviModel.Intent, SettingsScreenMviModel.UiState, SettingsScreenMviModel.Effect> by mvi { MviModel<SettingsScreenMviModel.Intent, SettingsScreenMviModel.UiState, SettingsScreenMviModel.Effect> by mvi {
@ -54,6 +56,27 @@ class SettingsScreenViewModel(
identityRepository.authToken.onEach { auth -> identityRepository.authToken.onEach { auth ->
mvi.updateState { it.copy(isLogged = !auth.isNullOrEmpty()) } mvi.updateState { it.copy(isLogged = !auth.isNullOrEmpty()) }
}.launchIn(this) }.launchIn(this)
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.Logout -> {
val listingType =
keyStore[KeyStoreKeys.DefaultListingType, 0].toListingType()
val postSortType =
keyStore[KeyStoreKeys.DefaultPostSortType, 0].toSortType()
val commentSortType =
keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType()
mvi.updateState {
it.copy(
defaultListingType = listingType,
defaultPostSortType = postSortType,
defaultCommentSortType = commentSortType,
)
}
}
else -> Unit
}
}.launchIn(this)
} }
val listingType = keyStore[KeyStoreKeys.DefaultListingType, 0].toListingType() val listingType = keyStore[KeyStoreKeys.DefaultListingType, 0].toListingType()

View File

@ -16,6 +16,7 @@ val settingsTabModule = module {
languageRepository = get(), languageRepository = get(),
identityRepository = get(), identityRepository = get(),
colorSchemeProvider = get(), colorSchemeProvider = get(),
notificationCenter = get(),
) )
} }
} }