fix: MVI model state update (#879)

This commit is contained in:
Diego Beraldin 2024-05-20 22:54:34 +02:00 committed by GitHub
parent aeaff6be61
commit 58e33fccd8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 1040 additions and 881 deletions

View File

@ -3,6 +3,8 @@ package com.github.diegoberaldin.raccoonforlemmy.core.architecture
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
/** /**
* Basic implementation of the MVI model. * Basic implementation of the MVI model.
@ -20,13 +22,14 @@ abstract class DefaultMviModel<Intent, State, Effect>(
) : MviModel<Intent, State, Effect> { ) : MviModel<Intent, State, Effect> {
override val uiState = MutableStateFlow(initialState) override val uiState = MutableStateFlow(initialState)
override val effects = MutableSharedFlow<Effect>() override val effects = MutableSharedFlow<Effect>()
private val mutex = Mutex()
/** /**
* Emit an effect (event). * Emit an effect (event).
* *
* @param value Value * @param value Value
*/ */
suspend fun emitEffect(value: Effect) { protected suspend fun emitEffect(value: Effect) {
effects.emit(value) effects.emit(value)
} }
@ -35,9 +38,11 @@ abstract class DefaultMviModel<Intent, State, Effect>(
* *
* @param block Block * @param block Block
*/ */
inline fun updateState(block: (State) -> State) { protected suspend fun updateState(block: (State) -> State) {
mutex.withLock {
uiState.update { block(uiState.value) } uiState.update { block(uiState.value) }
} }
}
override fun reduce(intent: Intent) { override fun reduce(intent: Intent) {
// Noop // Noop

View File

@ -30,40 +30,4 @@ class DefaultNotificationCenterTest {
expectNoEvents() expectNoEvents()
} }
} }
@Test
fun givenMultipleSubscriptions_whenSendReplayableEvent_thenEventIsReceivedAndReplayed() =
runTest {
launch {
sut.send(NotificationCenterEvent.PostCreated)
}
sut.subscribe(NotificationCenterEvent.PostCreated::class).test {
val evt = awaitItem()
assertEquals(NotificationCenterEvent.PostCreated, evt)
}
sut.subscribe(NotificationCenterEvent.PostCreated::class).test {
val evt = awaitItem()
assertEquals(NotificationCenterEvent.PostCreated, evt)
}
}
@Test
fun givenMultipleSubscriptions_whenResetCache_thenEventIsNotReplayed() =
runTest {
launch {
sut.send(NotificationCenterEvent.PostCreated)
}
sut.subscribe(NotificationCenterEvent.PostCreated::class).test {
val evt = awaitItem()
assertEquals(NotificationCenterEvent.PostCreated, evt)
}
sut.resetCache()
sut.subscribe(NotificationCenterEvent.PostCreated::class).test {
expectNoEvents()
}
}
} }

View File

@ -2,7 +2,6 @@ package com.github.diegoberaldin.raccoonforlemmy.core.notifications
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
@ -11,49 +10,17 @@ import kotlinx.coroutines.launch
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.safeCast import kotlin.reflect.safeCast
private const val REPLAY_EVENT_COUNT = 5
object DefaultNotificationCenter : NotificationCenter { object DefaultNotificationCenter : NotificationCenter {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default) private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private val events = MutableSharedFlow<NotificationCenterEvent>() private val events = MutableSharedFlow<NotificationCenterEvent>()
private val replayedEvents =
MutableSharedFlow<NotificationCenterEvent>(
replay = REPLAY_EVENT_COUNT,
)
override fun send(event: NotificationCenterEvent) { override fun send(event: NotificationCenterEvent) {
scope.launch(Dispatchers.Main) { scope.launch(Dispatchers.Main) {
if (isReplayable(event::class)) {
replayedEvents.emit(event)
} else {
events.emit(event) events.emit(event)
} }
} }
}
override fun <T : NotificationCenterEvent> subscribe(clazz: KClass<T>): Flow<T> { override fun <T : NotificationCenterEvent> subscribe(clazz: KClass<T>): Flow<T> {
return if (isReplayable(clazz)) { return events.mapNotNull { clazz.safeCast(it) }
replayedEvents.mapNotNull { clazz.safeCast(it) }
} else {
events.mapNotNull { clazz.safeCast(it) }
}
}
@OptIn(ExperimentalCoroutinesApi::class)
override fun resetCache() {
replayedEvents.resetReplayCache()
}
}
private fun <T : NotificationCenterEvent> isReplayable(clazz: KClass<T>): Boolean {
return when (clazz) {
NotificationCenterEvent.MultiCommunityCreated::class -> true
NotificationCenterEvent.PostUpdated::class -> true
NotificationCenterEvent.PostCreated::class -> true
NotificationCenterEvent.PostDeleted::class -> true
NotificationCenterEvent.CommentCreated::class -> true
NotificationCenterEvent.UserBannedPost::class -> true
NotificationCenterEvent.UserBannedComment::class -> true
else -> false
} }
} }

View File

@ -12,6 +12,4 @@ interface NotificationCenter {
fun send(event: NotificationCenterEvent) fun send(event: NotificationCenterEvent)
fun <T : NotificationCenterEvent> subscribe(clazz: KClass<T>): Flow<T> fun <T : NotificationCenterEvent> subscribe(clazz: KClass<T>): Flow<T>
fun resetCache()
} }

View File

@ -60,20 +60,24 @@ class InboxViewModel(
override fun reduce(intent: InboxMviModel.Intent) { override fun reduce(intent: InboxMviModel.Intent) {
when (intent) { when (intent) {
is InboxMviModel.Intent.ChangeSection -> is InboxMviModel.Intent.ChangeSection ->
screenModelScope.launch {
updateState { updateState {
it.copy(section = intent.value) it.copy(section = intent.value)
} }
}
InboxMviModel.Intent.ReadAll -> markAllRead() InboxMviModel.Intent.ReadAll -> markAllRead()
} }
} }
private fun changeUnreadOnly(value: Boolean) { private fun changeUnreadOnly(value: Boolean) {
screenModelScope.launch {
updateState { updateState {
it.copy(unreadOnly = value) it.copy(unreadOnly = value)
} }
coordinator.setUnreadOnly(value) coordinator.setUnreadOnly(value)
} }
}
private fun markAllRead() { private fun markAllRead() {
screenModelScope.launch { screenModelScope.launch {

View File

@ -80,7 +80,6 @@ class AdvancedSettingsViewModel(
}.launchIn(this) }.launchIn(this)
updateAvailableLanguages() updateAvailableLanguages()
}
val settings = settingsRepository.currentSettings.value val settings = settingsRepository.currentSettings.value
updateState { updateState {
@ -109,6 +108,7 @@ class AdvancedSettingsViewModel(
) )
} }
} }
}
override fun reduce(intent: AdvancedSettingsMviModel.Intent) { override fun reduce(intent: AdvancedSettingsMviModel.Intent) {
when (intent) { when (intent) {
@ -153,64 +153,64 @@ class AdvancedSettingsViewModel(
} }
private fun changeEnableDoubleTapAction(value: Boolean) { private fun changeEnableDoubleTapAction(value: Boolean) {
updateState { it.copy(enableDoubleTapAction = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(enableDoubleTapAction = value) }
val settings = settingsRepository.currentSettings.value.copy(enableDoubleTapAction = value) val settings = settingsRepository.currentSettings.value.copy(enableDoubleTapAction = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeAutoLoadImages(value: Boolean) { private fun changeAutoLoadImages(value: Boolean) {
updateState { it.copy(autoLoadImages = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(autoLoadImages = value) }
val settings = settingsRepository.currentSettings.value.copy(autoLoadImages = value) val settings = settingsRepository.currentSettings.value.copy(autoLoadImages = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeAutoExpandComments(value: Boolean) { private fun changeAutoExpandComments(value: Boolean) {
updateState { it.copy(autoExpandComments = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(autoExpandComments = value) }
val settings = settingsRepository.currentSettings.value.copy(autoExpandComments = value) val settings = settingsRepository.currentSettings.value.copy(autoExpandComments = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeHideNavigationBarWhileScrolling(value: Boolean) { private fun changeHideNavigationBarWhileScrolling(value: Boolean) {
updateState { it.copy(hideNavigationBarWhileScrolling = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(hideNavigationBarWhileScrolling = value) }
val settings = settingsRepository.currentSettings.value.copy(hideNavigationBarWhileScrolling = value) val settings = settingsRepository.currentSettings.value.copy(hideNavigationBarWhileScrolling = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeMarkAsReadWhileScrolling(value: Boolean) { private fun changeMarkAsReadWhileScrolling(value: Boolean) {
updateState { it.copy(markAsReadWhileScrolling = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(markAsReadWhileScrolling = value) }
val settings = settingsRepository.currentSettings.value.copy(markAsReadWhileScrolling = value) val settings = settingsRepository.currentSettings.value.copy(markAsReadWhileScrolling = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeZombieModeInterval(value: Duration) { private fun changeZombieModeInterval(value: Duration) {
updateState { it.copy(zombieModeInterval = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(zombieModeInterval = value) }
val settings = settingsRepository.currentSettings.value.copy(zombieModeInterval = value) val settings = settingsRepository.currentSettings.value.copy(zombieModeInterval = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeZombieModeScrollAmount(value: Float) { private fun changeZombieModeScrollAmount(value: Float) {
updateState { it.copy(zombieModeScrollAmount = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(zombieModeScrollAmount = value) }
val settings = settingsRepository.currentSettings.value.copy(zombieModeScrollAmount = value) val settings = settingsRepository.currentSettings.value.copy(zombieModeScrollAmount = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeDefaultInboxUnreadOnly(value: Boolean) { private fun changeDefaultInboxUnreadOnly(value: Boolean) {
updateState { it.copy(defaultInboxUnreadOnly = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(defaultInboxUnreadOnly = value) }
val settings = settingsRepository.currentSettings.value.copy(defaultInboxType = value.toInboxDefaultType()) val settings = settingsRepository.currentSettings.value.copy(defaultInboxType = value.toInboxDefaultType())
saveSettings(settings) saveSettings(settings)
notificationCenter.send(NotificationCenterEvent.ResetInbox) notificationCenter.send(NotificationCenterEvent.ResetInbox)
@ -218,32 +218,32 @@ class AdvancedSettingsViewModel(
} }
private fun changeSearchPostTitleOnly(value: Boolean) { private fun changeSearchPostTitleOnly(value: Boolean) {
updateState { it.copy(searchPostTitleOnly = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchPostTitleOnly = value) }
val settings = settingsRepository.currentSettings.value.copy(searchPostTitleOnly = value) val settings = settingsRepository.currentSettings.value.copy(searchPostTitleOnly = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeExploreType(value: ListingType) { private fun changeExploreType(value: ListingType) {
updateState { it.copy(defaultExploreType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(defaultExploreType = value) }
val settings = settingsRepository.currentSettings.value.copy(defaultExploreType = value.toInt()) val settings = settingsRepository.currentSettings.value.copy(defaultExploreType = value.toInt())
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeEdgeToEdge(value: Boolean) { private fun changeEdgeToEdge(value: Boolean) {
updateState { it.copy(edgeToEdge = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(edgeToEdge = value) }
val settings = settingsRepository.currentSettings.value.copy(edgeToEdge = value) val settings = settingsRepository.currentSettings.value.copy(edgeToEdge = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeInfiniteScrollDisabled(value: Boolean) { private fun changeInfiniteScrollDisabled(value: Boolean) {
updateState { it.copy(infiniteScrollDisabled = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(infiniteScrollDisabled = value) }
val settings = settingsRepository.currentSettings.value.copy(infiniteScrollEnabled = !value) val settings = settingsRepository.currentSettings.value.copy(infiniteScrollEnabled = !value)
saveSettings(settings) saveSettings(settings)
} }
@ -255,16 +255,16 @@ class AdvancedSettingsViewModel(
UiBarTheme.Opaque -> true UiBarTheme.Opaque -> true
else -> false else -> false
} }
updateState { it.copy(opaqueSystemBars = opaque) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(opaqueSystemBars = opaque) }
val settings = settingsRepository.currentSettings.value.copy(opaqueSystemBars = opaque) val settings = settingsRepository.currentSettings.value.copy(opaqueSystemBars = opaque)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeImageSourcePath(value: Boolean) { private fun changeImageSourcePath(value: Boolean) {
updateState { it.copy(imageSourcePath = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(imageSourcePath = value) }
val settings = settingsRepository.currentSettings.value.copy(imageSourcePath = value) val settings = settingsRepository.currentSettings.value.copy(imageSourcePath = value)
saveSettings(settings) saveSettings(settings)
} }
@ -279,40 +279,40 @@ class AdvancedSettingsViewModel(
} }
private fun changeDefaultLanguageId(value: Long?) { private fun changeDefaultLanguageId(value: Long?) {
updateState { it.copy(defaultLanguageId = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(defaultLanguageId = value) }
val settings = settingsRepository.currentSettings.value.copy(defaultLanguageId = value) val settings = settingsRepository.currentSettings.value.copy(defaultLanguageId = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeInboxBackgroundCheckPeriod(value: Duration) { private fun changeInboxBackgroundCheckPeriod(value: Duration) {
updateState { it.copy(inboxBackgroundCheckPeriod = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(inboxBackgroundCheckPeriod = value) }
val settings = settingsRepository.currentSettings.value.copy(inboxBackgroundCheckPeriod = value) val settings = settingsRepository.currentSettings.value.copy(inboxBackgroundCheckPeriod = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeFadeReadPosts(value: Boolean) { private fun changeFadeReadPosts(value: Boolean) {
updateState { it.copy(fadeReadPosts = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(fadeReadPosts = value) }
val settings = settingsRepository.currentSettings.value.copy(fadeReadPosts = value) val settings = settingsRepository.currentSettings.value.copy(fadeReadPosts = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeShowUnreadPosts(value: Boolean) { private fun changeShowUnreadPosts(value: Boolean) {
updateState { it.copy(showUnreadComments = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(showUnreadComments = value) }
val settings = settingsRepository.currentSettings.value.copy(showUnreadComments = value) val settings = settingsRepository.currentSettings.value.copy(showUnreadComments = value)
saveSettings(settings) saveSettings(settings)
} }
} }
private fun changeEnableButtonsToScrollBetweenComments(value: Boolean) { private fun changeEnableButtonsToScrollBetweenComments(value: Boolean) {
updateState { it.copy(enableButtonsToScrollBetweenComments = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(enableButtonsToScrollBetweenComments = value) }
val settings = settingsRepository.currentSettings.value.copy(enableButtonsToScrollBetweenComments = value) val settings = settingsRepository.currentSettings.value.copy(enableButtonsToScrollBetweenComments = value)
saveSettings(settings) saveSettings(settings)
} }

View File

@ -96,7 +96,6 @@ class SettingsViewModel(
availableSortTypesForComments = availableSortTypesForComments, availableSortTypesForComments = availableSortTypesForComments,
) )
} }
}
val settings = settingsRepository.currentSettings.value val settings = settingsRepository.currentSettings.value
updateState { updateState {
@ -113,6 +112,7 @@ class SettingsViewModel(
) )
} }
} }
}
override fun reduce(intent: SettingsMviModel.Intent) { override fun reduce(intent: SettingsMviModel.Intent) {
when (intent) { when (intent) {
@ -148,8 +148,8 @@ class SettingsViewModel(
} }
private fun changeDefaultListingType(value: ListingType) { private fun changeDefaultListingType(value: ListingType) {
updateState { it.copy(defaultListingType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(defaultListingType = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
defaultListingType = value.toInt(), defaultListingType = value.toInt(),
@ -160,8 +160,8 @@ class SettingsViewModel(
} }
private fun changeDefaultPostSortType(value: SortType) { private fun changeDefaultPostSortType(value: SortType) {
updateState { it.copy(defaultPostSortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(defaultPostSortType = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
defaultPostSortType = value.toInt(), defaultPostSortType = value.toInt(),
@ -172,8 +172,8 @@ class SettingsViewModel(
} }
private fun changeDefaultCommentSortType(value: SortType) { private fun changeDefaultCommentSortType(value: SortType) {
updateState { it.copy(defaultCommentSortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(defaultCommentSortType = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
defaultCommentSortType = value.toInt(), defaultCommentSortType = value.toInt(),
@ -183,8 +183,8 @@ class SettingsViewModel(
} }
private fun changeIncludeNsfw(value: Boolean) { private fun changeIncludeNsfw(value: Boolean) {
updateState { it.copy(includeNsfw = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(includeNsfw = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
includeNsfw = value, includeNsfw = value,
@ -196,8 +196,8 @@ class SettingsViewModel(
} }
private fun changeBlurNsfw(value: Boolean) { private fun changeBlurNsfw(value: Boolean) {
updateState { it.copy(blurNsfw = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(blurNsfw = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
blurNsfw = value, blurNsfw = value,
@ -207,8 +207,8 @@ class SettingsViewModel(
} }
private fun changeUrlOpeningMode(value: UrlOpeningMode) { private fun changeUrlOpeningMode(value: UrlOpeningMode) {
updateState { it.copy(urlOpeningMode = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(urlOpeningMode = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
urlOpeningMode = value.toInt(), urlOpeningMode = value.toInt(),
@ -218,8 +218,8 @@ class SettingsViewModel(
} }
private fun changeEnableSwipeActions(value: Boolean) { private fun changeEnableSwipeActions(value: Boolean) {
updateState { it.copy(enableSwipeActions = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(enableSwipeActions = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
enableSwipeActions = value, enableSwipeActions = value,
@ -229,9 +229,11 @@ class SettingsViewModel(
} }
private fun changeCrashReportEnabled(value: Boolean) { private fun changeCrashReportEnabled(value: Boolean) {
screenModelScope.launch {
crashReportConfiguration.setEnabled(value) crashReportConfiguration.setEnabled(value)
updateState { it.copy(crashReportEnabled = value) } updateState { it.copy(crashReportEnabled = value) }
} }
}
private suspend fun saveSettings(settings: SettingsModel) { private suspend fun saveSettings(settings: SettingsModel) {
val accountId = accountRepository.getActive()?.id val accountId = accountRepository.getActive()?.id

View File

@ -46,8 +46,10 @@ class MainViewModel(
override fun reduce(intent: MainScreenMviModel.Intent) { override fun reduce(intent: MainScreenMviModel.Intent) {
when (intent) { when (intent) {
is MainScreenMviModel.Intent.SetBottomBarOffsetHeightPx -> { is MainScreenMviModel.Intent.SetBottomBarOffsetHeightPx -> {
screenModelScope.launch {
updateState { it.copy(bottomBarOffsetHeightPx = intent.value) } updateState { it.copy(bottomBarOffsetHeightPx = intent.value) }
} }
} }
} }
} }
}

View File

@ -1,13 +1,16 @@
package com.github.diegoberaldin.raccoonforlemmy.unit.about package com.github.diegoberaldin.raccoonforlemmy.unit.about
import cafe.adriel.voyager.core.model.screenModelScope
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.utils.debug.AppInfo import com.github.diegoberaldin.raccoonforlemmy.core.utils.debug.AppInfo
import kotlinx.coroutines.launch
class AboutDialogViewModel : AboutDialogMviModel, class AboutDialogViewModel : AboutDialogMviModel,
DefaultMviModel<AboutDialogMviModel.Intent, AboutDialogMviModel.UiState, AboutDialogMviModel.Effect>( DefaultMviModel<AboutDialogMviModel.Intent, AboutDialogMviModel.UiState, AboutDialogMviModel.Effect>(
initialState = AboutDialogMviModel.UiState(), initialState = AboutDialogMviModel.UiState(),
) { ) {
init { init {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
version = AppInfo.versionCode, version = AppInfo.versionCode,
@ -15,3 +18,4 @@ class AboutDialogViewModel : AboutDialogMviModel,
} }
} }
} }
}

View File

@ -55,6 +55,7 @@ class AccountSettingsViewModel(
override fun reduce(intent: AccountSettingsMviModel.Intent) { override fun reduce(intent: AccountSettingsMviModel.Intent) {
when (intent) { when (intent) {
is AccountSettingsMviModel.Intent.ChangeDisplayName -> { is AccountSettingsMviModel.Intent.ChangeDisplayName -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
displayName = intent.value, displayName = intent.value,
@ -62,8 +63,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeEmail -> { is AccountSettingsMviModel.Intent.ChangeEmail -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
email = intent.value, email = intent.value,
@ -71,8 +74,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeMatrixUserId -> { is AccountSettingsMviModel.Intent.ChangeMatrixUserId -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
matrixUserId = intent.value, matrixUserId = intent.value,
@ -80,8 +85,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeBio -> { is AccountSettingsMviModel.Intent.ChangeBio -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
bio = intent.value, bio = intent.value,
@ -89,8 +96,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeBot -> { is AccountSettingsMviModel.Intent.ChangeBot -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
bot = intent.value, bot = intent.value,
@ -98,8 +107,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeSendNotificationsToEmail -> { is AccountSettingsMviModel.Intent.ChangeSendNotificationsToEmail -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
sendNotificationsToEmail = intent.value, sendNotificationsToEmail = intent.value,
@ -107,8 +118,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeShowBotAccounts -> { is AccountSettingsMviModel.Intent.ChangeShowBotAccounts -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
showBotAccounts = intent.value, showBotAccounts = intent.value,
@ -116,8 +129,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeShowNsfw -> { is AccountSettingsMviModel.Intent.ChangeShowNsfw -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
showNsfw = intent.value, showNsfw = intent.value,
@ -125,8 +140,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeShowScores -> { is AccountSettingsMviModel.Intent.ChangeShowScores -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
showScores = intent.value, showScores = intent.value,
@ -134,8 +151,10 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.ChangeShowReadPosts -> { is AccountSettingsMviModel.Intent.ChangeShowReadPosts -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
showReadPosts = intent.value, showReadPosts = intent.value,
@ -143,6 +162,7 @@ class AccountSettingsViewModel(
) )
} }
} }
}
is AccountSettingsMviModel.Intent.AvatarSelected -> { is AccountSettingsMviModel.Intent.AvatarSelected -> {
loadImageAvatar(intent.value) loadImageAvatar(intent.value)
@ -240,8 +260,8 @@ class AccountSettingsViewModel(
showScores = currentState.showScores, showScores = currentState.showScores,
showReadPosts = currentState.showReadPosts, showReadPosts = currentState.showReadPosts,
) ?: return ) ?: return
updateState { it.copy(loading = true) }
screenModelScope.launch(Dispatchers.IO) { screenModelScope.launch(Dispatchers.IO) {
updateState { it.copy(loading = true) }
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
siteRepository.updateAccountSettings( siteRepository.updateAccountSettings(

View File

@ -22,31 +22,48 @@ class BanUserViewModel(
initialState = BanUserMviModel.UiState(), initialState = BanUserMviModel.UiState(),
) { ) {
init { init {
screenModelScope.launch {
updateState { updateState {
it.copy(targetBanValue = newValue) it.copy(targetBanValue = newValue)
} }
} }
}
override fun reduce(intent: BanUserMviModel.Intent) { override fun reduce(intent: BanUserMviModel.Intent) {
when (intent) { when (intent) {
BanUserMviModel.Intent.IncrementDays -> incrementDays() BanUserMviModel.Intent.IncrementDays -> incrementDays()
BanUserMviModel.Intent.DecrementDays -> decrementDays() BanUserMviModel.Intent.DecrementDays -> decrementDays()
is BanUserMviModel.Intent.ChangePermanent -> updateState { it.copy(permanent = intent.value) } is BanUserMviModel.Intent.ChangePermanent ->
is BanUserMviModel.Intent.ChangeRemoveData -> updateState { it.copy(removeData = intent.value) } screenModelScope.launch {
is BanUserMviModel.Intent.SetText -> updateState { it.copy(text = intent.value) } updateState { it.copy(permanent = intent.value) }
}
is BanUserMviModel.Intent.ChangeRemoveData ->
screenModelScope.launch {
updateState { it.copy(removeData = intent.value) }
}
is BanUserMviModel.Intent.SetText ->
screenModelScope.launch {
updateState { it.copy(text = intent.value) }
}
BanUserMviModel.Intent.Submit -> submit() BanUserMviModel.Intent.Submit -> submit()
} }
} }
private fun incrementDays() { private fun incrementDays() {
screenModelScope.launch {
val newValue = uiState.value.days + 1 val newValue = uiState.value.days + 1
updateState { it.copy(days = newValue) } updateState { it.copy(days = newValue) }
} }
}
private fun decrementDays() { private fun decrementDays() {
screenModelScope.launch {
val newValue = (uiState.value.days - 1).coerceAtLeast(1) val newValue = (uiState.value.days - 1).coerceAtLeast(1)
updateState { it.copy(days = newValue) } updateState { it.copy(days = newValue) }
} }
}
private fun submit() { private fun submit() {
val currentState = uiState.value val currentState = uiState.value
@ -57,8 +74,8 @@ class BanUserViewModel(
val removeData = currentState.removeData.takeIf { newValue } ?: false val removeData = currentState.removeData.takeIf { newValue } ?: false
val days = currentState.days.toLong().takeIf { newValue } val days = currentState.days.toLong().takeIf { newValue }
updateState { it.copy(loading = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(loading = true) }
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
val newUser = val newUser =

View File

@ -181,6 +181,7 @@ class InboxChatViewModel(
} }
private fun handleMessageUpdate(newMessage: PrivateMessageModel) { private fun handleMessageUpdate(newMessage: PrivateMessageModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
messages = messages =
@ -194,6 +195,7 @@ class InboxChatViewModel(
) )
} }
} }
}
private fun loadImageAndAppendUrlInBody(bytes: ByteArray) { private fun loadImageAndAppendUrlInBody(bytes: ByteArray) {
if (bytes.isEmpty()) { if (bytes.isEmpty()) {
@ -215,12 +217,14 @@ class InboxChatViewModel(
} }
private fun startEditingMessage(message: PrivateMessageModel) { private fun startEditingMessage(message: PrivateMessageModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
editedMessageId = message.id, editedMessageId = message.id,
) )
} }
} }
}
private fun submitNewMessage(text: String) { private fun submitNewMessage(text: String) {
val editedMessageId = uiState.value.editedMessageId val editedMessageId = uiState.value.editedMessageId
@ -268,8 +272,10 @@ class InboxChatViewModel(
} }
private fun handleLogout() { private fun handleLogout() {
screenModelScope.launch {
updateState { it.copy(messages = emptyList()) } updateState { it.copy(messages = emptyList()) }
} }
}
private fun deleteMessage(message: PrivateMessageModel) { private fun deleteMessage(message: PrivateMessageModel) {
screenModelScope.launch { screenModelScope.launch {

View File

@ -114,7 +114,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomS
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.ActionOnSwipe import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.ActionOnSwipe
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
@ -176,7 +175,6 @@ class CommunityDetailScreen(
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val fabNestedScrollConnection = remember { getFabNestedScrollConnection() } val fabNestedScrollConnection = remember { getFabNestedScrollConnection() }
val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState() val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState()
val notificationCenter = remember { getNotificationCenter() }
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
val upVoteColor by themeRepository.upVoteColor.collectAsState() val upVoteColor by themeRepository.upVoteColor.collectAsState()
@ -212,9 +210,6 @@ class CommunityDetailScreen(
WindowInsets.statusBars.getTop(this) WindowInsets.statusBars.getTop(this)
} }
LaunchedEffect(notificationCenter) {
notificationCenter.resetCache()
}
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { effect -> model.effects.onEach { effect ->
when (effect) { when (effect) {

View File

@ -265,17 +265,21 @@ class CommunityDetailViewModel(
} }
CommunityDetailMviModel.Intent.PauseZombieMode -> { CommunityDetailMviModel.Intent.PauseZombieMode -> {
screenModelScope.launch {
updateState { it.copy(zombieModeActive = false) } updateState { it.copy(zombieModeActive = false) }
zombieModeHelper.pause() zombieModeHelper.pause()
} }
}
is CommunityDetailMviModel.Intent.StartZombieMode -> { is CommunityDetailMviModel.Intent.StartZombieMode -> {
screenModelScope.launch {
updateState { it.copy(zombieModeActive = true) } updateState { it.copy(zombieModeActive = true) }
zombieModeHelper.start( zombieModeHelper.start(
initialValue = intent.index, initialValue = intent.index,
interval = settingsRepository.currentSettings.value.zombieModeInterval, interval = settingsRepository.currentSettings.value.zombieModeInterval,
) )
} }
}
is CommunityDetailMviModel.Intent.ModFeaturePost -> is CommunityDetailMviModel.Intent.ModFeaturePost ->
uiState.value.posts.firstOrNull { it.id == intent.id } uiState.value.posts.firstOrNull { it.id == intent.id }
@ -298,11 +302,13 @@ class CommunityDetailViewModel(
} }
is CommunityDetailMviModel.Intent.ChangeSearching -> { is CommunityDetailMviModel.Intent.ChangeSearching -> {
screenModelScope.launch {
updateState { it.copy(searching = intent.value) } updateState { it.copy(searching = intent.value) }
if (!intent.value) { if (!intent.value) {
updateSearchText("") updateSearchText("")
} }
} }
}
is CommunityDetailMviModel.Intent.SetSearch -> updateSearchText(intent.value) is CommunityDetailMviModel.Intent.SetSearch -> updateSearchText(intent.value)
is CommunityDetailMviModel.Intent.Copy -> is CommunityDetailMviModel.Intent.Copy ->
@ -375,8 +381,8 @@ class CommunityDetailViewModel(
if (uiState.value.sortType == value) { if (uiState.value.sortType == value) {
return return
} }
updateState { it.copy(sortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(sortType = value) }
emitEffect(CommunityDetailMviModel.Effect.BackToTop) emitEffect(CommunityDetailMviModel.Effect.BackToTop)
delay(50) delay(50)
refresh() refresh()
@ -562,6 +568,7 @@ class CommunityDetailViewModel(
} }
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
posts = posts =
@ -575,14 +582,17 @@ class CommunityDetailViewModel(
) )
} }
} }
}
private fun handlePostDelete(id: Long) { private fun handlePostDelete(id: Long) {
screenModelScope.launch {
updateState { it.copy(posts = it.posts.filter { post -> post.id != id }) } updateState { it.copy(posts = it.posts.filter { post -> post.id != id }) }
} }
}
private fun blockCommunity() { private fun blockCommunity() {
updateState { it.copy(asyncInProgress = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(asyncInProgress = true) }
try { try {
val auth = identityRepository.authToken.value val auth = identityRepository.authToken.value
communityRepository.block(communityId, true, auth).getOrThrow() communityRepository.block(communityId, true, auth).getOrThrow()
@ -596,8 +606,8 @@ class CommunityDetailViewModel(
} }
private fun blockInstance() { private fun blockInstance() {
updateState { it.copy(asyncInProgress = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(asyncInProgress = true) }
try { try {
val community = uiState.value.community val community = uiState.value.community
val instanceId = community.instanceId val instanceId = community.instanceId
@ -613,6 +623,7 @@ class CommunityDetailViewModel(
} }
private fun clearRead() { private fun clearRead() {
screenModelScope.launch {
hideReadPosts = true hideReadPosts = true
updateState { updateState {
val newPosts = it.posts.filter { e -> !e.read } val newPosts = it.posts.filter { e -> !e.read }
@ -621,8 +632,10 @@ class CommunityDetailViewModel(
) )
} }
} }
}
private fun hide(post: PostModel) { private fun hide(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
val newPosts = it.posts.filter { e -> e.id != post.id } val newPosts = it.posts.filter { e -> e.id != post.id }
it.copy( it.copy(
@ -631,6 +644,7 @@ class CommunityDetailViewModel(
} }
markAsRead(post) markAsRead(post)
} }
}
private fun feature(post: PostModel) { private fun feature(post: PostModel) {
screenModelScope.launch { screenModelScope.launch {
@ -698,8 +712,8 @@ class CommunityDetailViewModel(
} }
private fun updateSearchText(value: String) { private fun updateSearchText(value: String) {
updateState { it.copy(searchText = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchText = value) }
searchEventChannel.send(Unit) searchEventChannel.send(Unit)
} }
} }

View File

@ -137,8 +137,8 @@ class ConfigureContentViewViewModel(
} }
private fun changeVoteFormat(value: VoteFormat) { private fun changeVoteFormat(value: VoteFormat) {
updateState { it.copy(voteFormat = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(voteFormat = value) }
val settings = val settings =
settingsRepository.currentSettings.value.let { settingsRepository.currentSettings.value.let {
if (value == VoteFormat.Hidden) { if (value == VoteFormat.Hidden) {
@ -155,8 +155,8 @@ class ConfigureContentViewViewModel(
} }
private fun changeFullHeightImages(value: Boolean) { private fun changeFullHeightImages(value: Boolean) {
updateState { it.copy(fullHeightImages = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(fullHeightImages = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
fullHeightImages = value, fullHeightImages = value,
@ -166,8 +166,8 @@ class ConfigureContentViewViewModel(
} }
private fun changeFullWidthImages(value: Boolean) { private fun changeFullWidthImages(value: Boolean) {
updateState { it.copy(fullWidthImages = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(fullWidthImages = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
fullWidthImages = value, fullWidthImages = value,
@ -177,8 +177,8 @@ class ConfigureContentViewViewModel(
} }
private fun changePreferUserNicknames(value: Boolean) { private fun changePreferUserNicknames(value: Boolean) {
updateState { it.copy(preferUserNicknames = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(preferUserNicknames = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
preferUserNicknames = value, preferUserNicknames = value,
@ -188,8 +188,8 @@ class ConfigureContentViewViewModel(
} }
private fun changePostBodyMaxLines(value: Int?) { private fun changePostBodyMaxLines(value: Int?) {
updateState { it.copy(postBodyMaxLines = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(postBodyMaxLines = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
postBodyMaxLines = value, postBodyMaxLines = value,
@ -232,8 +232,8 @@ class ConfigureContentViewViewModel(
} }
private fun changeCommentBarThickness(value: Int) { private fun changeCommentBarThickness(value: Int) {
updateState { it.copy(commentBarThickness = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(commentBarThickness = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
commentBarThickness = value, commentBarThickness = value,
@ -243,8 +243,8 @@ class ConfigureContentViewViewModel(
} }
private fun changeCommentIndentAmount(value: Int) { private fun changeCommentIndentAmount(value: Int) {
updateState { it.copy(commentIndentAmount = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(commentIndentAmount = value) }
val settings = val settings =
settingsRepository.currentSettings.value.copy( settingsRepository.currentSettings.value.copy(
commentIndentAmount = value, commentIndentAmount = value,

View File

@ -51,9 +51,10 @@ class ConfigureSwipeActionsViewModel(
) )
} }
}.launchIn(this) }.launchIn(this)
}
refresh() refresh()
} }
}
override fun reduce(intent: ConfigureSwipeActionsMviModel.Intent) { override fun reduce(intent: ConfigureSwipeActionsMviModel.Intent) {
when (intent) { when (intent) {
@ -81,7 +82,7 @@ class ConfigureSwipeActionsViewModel(
} }
} }
private fun refresh() { private suspend fun refresh() {
val settings = settingsRepository.currentSettings.value val settings = settingsRepository.currentSettings.value
updateState { updateState {
it.copy( it.copy(
@ -515,6 +516,7 @@ class ConfigureSwipeActionsViewModel(
this -= currentState.actionsOnSwipeToEndInbox.toSet() this -= currentState.actionsOnSwipeToEndInbox.toSet()
} }
} }
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
availableOptionsPosts = actionsPosts.toList(), availableOptionsPosts = actionsPosts.toList(),
@ -524,3 +526,4 @@ class ConfigureSwipeActionsViewModel(
} }
} }
} }
}

View File

@ -107,20 +107,26 @@ class CreateCommentViewModel(
override fun reduce(intent: CreateCommentMviModel.Intent) { override fun reduce(intent: CreateCommentMviModel.Intent) {
when (intent) { when (intent) {
is CreateCommentMviModel.Intent.ChangeSection -> { is CreateCommentMviModel.Intent.ChangeSection -> {
screenModelScope.launch {
updateState { it.copy(section = intent.value) } updateState { it.copy(section = intent.value) }
} }
}
is CreateCommentMviModel.Intent.ImageSelected -> { is CreateCommentMviModel.Intent.ImageSelected -> {
loadImageAndAppendUrlInBody(intent.value) loadImageAndAppendUrlInBody(intent.value)
} }
is CreateCommentMviModel.Intent.ChangeLanguage -> { is CreateCommentMviModel.Intent.ChangeLanguage -> {
screenModelScope.launch {
updateState { it.copy(currentLanguageId = intent.value) } updateState { it.copy(currentLanguageId = intent.value) }
} }
}
is CreateCommentMviModel.Intent.ChangeTextValue -> { is CreateCommentMviModel.Intent.ChangeTextValue -> {
screenModelScope.launch {
updateState { it.copy(textValue = intent.value) } updateState { it.copy(textValue = intent.value) }
} }
}
is CreateCommentMviModel.Intent.Send -> submit() is CreateCommentMviModel.Intent.Send -> submit()
is CreateCommentMviModel.Intent.SaveDraft -> saveDraft() is CreateCommentMviModel.Intent.SaveDraft -> saveDraft()
@ -133,29 +139,33 @@ class CreateCommentViewModel(
return return
} }
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
textError = null, textError = null,
) )
} }
}
val text = currentState.textValue.text.trim() val text = currentState.textValue.text.trim()
val languageId = currentState.currentLanguageId val languageId = currentState.currentLanguageId
var valid = true var valid = true
if (text.isEmpty()) { if (text.isEmpty()) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
textError = ValidationError.MissingField, textError = ValidationError.MissingField,
) )
} }
}
valid = false valid = false
} }
if (!valid) { if (!valid) {
return return
} }
updateState { it.copy(loading = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(loading = true) }
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
if (postId != null) { if (postId != null) {

View File

@ -97,22 +97,28 @@ class CreatePostViewModel(
} }
is CreatePostMviModel.Intent.SetTitle -> { is CreatePostMviModel.Intent.SetTitle -> {
screenModelScope.launch {
updateState { updateState {
it.copy(title = intent.value) it.copy(title = intent.value)
} }
} }
}
is CreatePostMviModel.Intent.ChangeNsfw -> { is CreatePostMviModel.Intent.ChangeNsfw -> {
screenModelScope.launch {
updateState { updateState {
it.copy(nsfw = intent.value) it.copy(nsfw = intent.value)
} }
} }
}
is CreatePostMviModel.Intent.SetUrl -> { is CreatePostMviModel.Intent.SetUrl -> {
screenModelScope.launch {
updateState { updateState {
it.copy(url = intent.value) it.copy(url = intent.value)
} }
} }
}
is CreatePostMviModel.Intent.ImageSelected -> { is CreatePostMviModel.Intent.ImageSelected -> {
loadImageAndObtainUrl(intent.value) loadImageAndObtainUrl(intent.value)
@ -123,19 +129,24 @@ class CreatePostViewModel(
} }
is CreatePostMviModel.Intent.ChangeSection -> is CreatePostMviModel.Intent.ChangeSection ->
screenModelScope.launch {
updateState { updateState {
it.copy(section = intent.value) it.copy(section = intent.value)
} }
}
is CreatePostMviModel.Intent.ChangeLanguage -> is CreatePostMviModel.Intent.ChangeLanguage ->
screenModelScope.launch {
updateState { updateState {
it.copy(currentLanguageId = intent.value) it.copy(currentLanguageId = intent.value)
} }
}
is CreatePostMviModel.Intent.ChangeBodyValue -> is CreatePostMviModel.Intent.ChangeBodyValue ->
screenModelScope.launch {
updateState { updateState {
it.copy(bodyValue = intent.value) it.copy(bodyValue = intent.value)
} }
}
CreatePostMviModel.Intent.Send -> submit() CreatePostMviModel.Intent.Send -> submit()
@ -214,6 +225,7 @@ class CreatePostViewModel(
return return
} }
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
titleError = null, titleError = null,
@ -221,6 +233,7 @@ class CreatePostViewModel(
bodyError = null, bodyError = null,
) )
} }
}
val communityId = currentState.communityId val communityId = currentState.communityId
val title = currentState.title.trim() val title = currentState.title.trim()
@ -230,21 +243,27 @@ class CreatePostViewModel(
val languageId = currentState.currentLanguageId val languageId = currentState.currentLanguageId
var valid = true var valid = true
if (title.isEmpty()) { if (title.isEmpty()) {
screenModelScope.launch {
updateState { updateState {
it.copy(titleError = ValidationError.MissingField) it.copy(titleError = ValidationError.MissingField)
} }
}
valid = false valid = false
} }
if (!url.isNullOrEmpty() && !url.isValidUrl()) { if (!url.isNullOrEmpty() && !url.isValidUrl()) {
screenModelScope.launch {
updateState { updateState {
it.copy(urlError = ValidationError.InvalidField) it.copy(urlError = ValidationError.InvalidField)
} }
}
valid = false valid = false
} }
if (communityId == null) { if (communityId == null) {
screenModelScope.launch {
updateState { updateState {
it.copy(communityError = ValidationError.MissingField) it.copy(communityError = ValidationError.MissingField)
} }
}
valid = false valid = false
} }
@ -252,8 +271,8 @@ class CreatePostViewModel(
return return
} }
updateState { it.copy(loading = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(loading = true) }
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
when { when {

View File

@ -44,9 +44,11 @@ class DraftsViewModel(
override fun reduce(intent: DraftsMviModel.Intent) { override fun reduce(intent: DraftsMviModel.Intent) {
when (intent) { when (intent) {
is DraftsMviModel.Intent.ChangeSection -> is DraftsMviModel.Intent.ChangeSection ->
screenModelScope.launch {
updateState { updateState {
it.copy(section = intent.section) it.copy(section = intent.section)
} }
}
is DraftsMviModel.Intent.Delete -> deleteDraft(intent.model) is DraftsMviModel.Intent.Delete -> deleteDraft(intent.model)
DraftsMviModel.Intent.Refresh -> refresh() DraftsMviModel.Intent.Refresh -> refresh()
@ -54,6 +56,7 @@ class DraftsViewModel(
} }
private fun refresh(initial: Boolean = false) { private fun refresh(initial: Boolean = false) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
refreshing = !initial, refreshing = !initial,
@ -61,7 +64,6 @@ class DraftsViewModel(
loading = false, loading = false,
) )
} }
screenModelScope.launch {
val currentState = uiState.value val currentState = uiState.value
updateState { it.copy(loading = true) } updateState { it.copy(loading = true) }
val refreshing = currentState.refreshing val refreshing = currentState.refreshing

View File

@ -123,8 +123,8 @@ class ModalDrawerViewModel(
} }
is ModalDrawerMviModel.Intent.SetSearch -> { is ModalDrawerMviModel.Intent.SetSearch -> {
updateState { it.copy(searchText = intent.value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchText = intent.value) }
searchEventChannel.send(Unit) searchEventChannel.send(Unit)
} }
} }

View File

@ -32,6 +32,7 @@ class EditCommunityViewModel(
is EditCommunityMviModel.Intent.BannerSelected -> loadImageBanner(intent.value) is EditCommunityMviModel.Intent.BannerSelected -> loadImageBanner(intent.value)
is EditCommunityMviModel.Intent.ChangeDescription -> { is EditCommunityMviModel.Intent.ChangeDescription -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
description = intent.value, description = intent.value,
@ -39,8 +40,10 @@ class EditCommunityViewModel(
) )
} }
} }
}
is EditCommunityMviModel.Intent.ChangeTitle -> { is EditCommunityMviModel.Intent.ChangeTitle -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
title = intent.value, title = intent.value,
@ -48,8 +51,10 @@ class EditCommunityViewModel(
) )
} }
} }
}
is EditCommunityMviModel.Intent.ChangeNsfw -> { is EditCommunityMviModel.Intent.ChangeNsfw -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
nsfw = intent.value, nsfw = intent.value,
@ -57,8 +62,10 @@ class EditCommunityViewModel(
) )
} }
} }
}
is EditCommunityMviModel.Intent.ChangePostingRestrictedToMods -> { is EditCommunityMviModel.Intent.ChangePostingRestrictedToMods -> {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
postingRestrictedToMods = intent.value, postingRestrictedToMods = intent.value,
@ -66,6 +73,7 @@ class EditCommunityViewModel(
) )
} }
} }
}
EditCommunityMviModel.Intent.Submit -> submit() EditCommunityMviModel.Intent.Submit -> submit()
} }
@ -138,8 +146,8 @@ class EditCommunityViewModel(
private fun submit() { private fun submit() {
val community = originalCommunity?.copy() ?: return val community = originalCommunity?.copy() ?: return
val currentState = uiState.value val currentState = uiState.value
updateState { it.copy(loading = true) }
screenModelScope.launch(Dispatchers.IO) { screenModelScope.launch(Dispatchers.IO) {
updateState { it.copy(loading = true) }
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
val newValue = val newValue =

View File

@ -65,12 +65,12 @@ class ExploreViewModel(
} }
init { init {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
instance = apiConfigRepository.instance.value, instance = apiConfigRepository.instance.value,
) )
} }
screenModelScope.launch {
identityRepository.isLogged.onEach { isLogged -> identityRepository.isLogged.onEach { isLogged ->
updateState { updateState {
it.copy(isLogged = isLogged ?: false) it.copy(isLogged = isLogged ?: false)
@ -143,6 +143,7 @@ class ExploreViewModel(
} }
private fun onFirstLoad() { private fun onFirstLoad() {
screenModelScope.launch {
val settings = settingsRepository.currentSettings.value val settings = settingsRepository.currentSettings.value
val listingType = if (isOnOtherInstance) ListingType.Local else settings.defaultExploreType.toListingType() val listingType = if (isOnOtherInstance) ListingType.Local else settings.defaultExploreType.toListingType()
val sortType = settings.defaultPostSortType.toSortType() val sortType = settings.defaultPostSortType.toSortType()
@ -152,7 +153,6 @@ class ExploreViewModel(
sortType = sortType, sortType = sortType,
) )
} }
screenModelScope.launch {
val auth = identityRepository.authToken.value val auth = identityRepository.authToken.value
val downVoteEnabled = siteRepository.isDownVoteEnabled(auth) val downVoteEnabled = siteRepository.isDownVoteEnabled(auth)
updateState { it.copy(downVoteEnabled = downVoteEnabled) } updateState { it.copy(downVoteEnabled = downVoteEnabled) }
@ -265,31 +265,31 @@ class ExploreViewModel(
} }
private fun setSearch(value: String) { private fun setSearch(value: String) {
updateState { it.copy(searchText = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchText = value) }
searchEventChannel.send(Unit) searchEventChannel.send(Unit)
} }
} }
private fun changeListingType(value: ListingType) { private fun changeListingType(value: ListingType) {
updateState { it.copy(listingType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(listingType = value) }
emitEffect(ExploreMviModel.Effect.BackToTop) emitEffect(ExploreMviModel.Effect.BackToTop)
refresh() refresh()
} }
} }
private fun changeSortType(value: SortType) { private fun changeSortType(value: SortType) {
updateState { it.copy(sortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(sortType = value) }
emitEffect(ExploreMviModel.Effect.BackToTop) emitEffect(ExploreMviModel.Effect.BackToTop)
refresh() refresh()
} }
} }
private fun changeResultType(value: SearchResultType) { private fun changeResultType(value: SearchResultType) {
updateState { it.copy(resultType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(resultType = value) }
emitEffect(ExploreMviModel.Effect.BackToTop) emitEffect(ExploreMviModel.Effect.BackToTop)
refresh() refresh()
} }
@ -434,6 +434,7 @@ class ExploreViewModel(
} }
private fun handleLogout() { private fun handleLogout() {
screenModelScope.launch {
currentPage = 1 currentPage = 1
updateState { updateState {
it.copy( it.copy(
@ -443,8 +444,10 @@ class ExploreViewModel(
} }
onFirstLoad() onFirstLoad()
} }
}
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
results = results =
@ -458,8 +461,10 @@ class ExploreViewModel(
) )
} }
} }
}
private fun handleCommentUpdate(comment: CommentModel) { private fun handleCommentUpdate(comment: CommentModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
results = results =
@ -473,8 +478,10 @@ class ExploreViewModel(
) )
} }
} }
}
private fun toggleUpVote(post: PostModel) { private fun toggleUpVote(post: PostModel) {
screenModelScope.launch {
val newVote = post.myVote <= 0 val newVote = post.myVote <= 0
val newPost = val newPost =
postRepository.asUpVoted( postRepository.asUpVoted(
@ -494,7 +501,6 @@ class ExploreViewModel(
}, },
) )
} }
screenModelScope.launch {
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
postRepository.upVote( postRepository.upVote(
@ -522,6 +528,7 @@ class ExploreViewModel(
} }
private fun toggleDownVote(post: PostModel) { private fun toggleDownVote(post: PostModel) {
screenModelScope.launch {
val newValue = post.myVote >= 0 val newValue = post.myVote >= 0
val newPost = val newPost =
postRepository.asDownVoted( postRepository.asDownVoted(
@ -541,7 +548,6 @@ class ExploreViewModel(
}, },
) )
} }
screenModelScope.launch {
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
postRepository.downVote( postRepository.downVote(
@ -569,6 +575,7 @@ class ExploreViewModel(
} }
private fun toggleSave(post: PostModel) { private fun toggleSave(post: PostModel) {
screenModelScope.launch {
val newValue = !post.saved val newValue = !post.saved
val newPost = val newPost =
postRepository.asSaved( postRepository.asSaved(
@ -588,7 +595,6 @@ class ExploreViewModel(
}, },
) )
} }
screenModelScope.launch {
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
postRepository.save( postRepository.save(
@ -616,6 +622,7 @@ class ExploreViewModel(
} }
private fun toggleUpVoteComment(comment: CommentModel) { private fun toggleUpVoteComment(comment: CommentModel) {
screenModelScope.launch {
val newValue = comment.myVote <= 0 val newValue = comment.myVote <= 0
val newComment = val newComment =
commentRepository.asUpVoted( commentRepository.asUpVoted(
@ -635,7 +642,6 @@ class ExploreViewModel(
}, },
) )
} }
screenModelScope.launch {
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
commentRepository.upVote( commentRepository.upVote(
@ -663,6 +669,7 @@ class ExploreViewModel(
} }
private fun toggleDownVoteComment(comment: CommentModel) { private fun toggleDownVoteComment(comment: CommentModel) {
screenModelScope.launch {
val newValue = comment.myVote >= 0 val newValue = comment.myVote >= 0
val newComment = commentRepository.asDownVoted(comment, newValue) val newComment = commentRepository.asDownVoted(comment, newValue)
updateState { updateState {
@ -678,7 +685,6 @@ class ExploreViewModel(
}, },
) )
} }
screenModelScope.launch {
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
commentRepository.downVote( commentRepository.downVote(
@ -706,6 +712,7 @@ class ExploreViewModel(
} }
private fun toggleSaveComment(comment: CommentModel) { private fun toggleSaveComment(comment: CommentModel) {
screenModelScope.launch {
val newValue = !comment.saved val newValue = !comment.saved
val newComment = val newComment =
commentRepository.asSaved( commentRepository.asSaved(
@ -725,7 +732,6 @@ class ExploreViewModel(
}, },
) )
} }
screenModelScope.launch {
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
commentRepository.save( commentRepository.save(
@ -787,6 +793,7 @@ class ExploreViewModel(
} }
private fun handleCommunityUpdate(community: CommunityModel) { private fun handleCommunityUpdate(community: CommunityModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
results = results =
@ -802,6 +809,7 @@ class ExploreViewModel(
} }
} }
} }
}
internal fun getItemKey(result: SearchResult): String = internal fun getItemKey(result: SearchResult): String =
when (result) { when (result) {

View File

@ -47,10 +47,10 @@ class FilteredContentsViewModel(
initialState = FilteredContentsMviModel.State(), initialState = FilteredContentsMviModel.State(),
) { ) {
init { init {
screenModelScope.launch {
updateState { updateState {
it.copy(contentsType = contentsType.toFilteredContentsType()) it.copy(contentsType = contentsType.toFilteredContentsType())
} }
screenModelScope.launch {
updateState { updateState {
it.copy(isAdmin = identityRepository.cachedUser?.admin == true) it.copy(isAdmin = identityRepository.cachedUser?.admin == true)
} }
@ -238,10 +238,10 @@ class FilteredContentsViewModel(
} }
private fun changeSection(section: FilteredContentsSection) { private fun changeSection(section: FilteredContentsSection) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(section = section)
section = section, }
)
} }
} }
@ -408,6 +408,7 @@ class FilteredContentsViewModel(
} }
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
posts = posts =
@ -421,6 +422,7 @@ class FilteredContentsViewModel(
) )
} }
} }
}
private fun toggleUpVoteComment(comment: CommentModel) { private fun toggleUpVoteComment(comment: CommentModel) {
val newValue = comment.myVote <= 0 val newValue = comment.myVote <= 0
@ -503,6 +505,7 @@ class FilteredContentsViewModel(
} }
private fun handleCommentUpdate(comment: CommentModel) { private fun handleCommentUpdate(comment: CommentModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
comments = comments =
@ -516,10 +519,11 @@ class FilteredContentsViewModel(
) )
} }
} }
}
private fun changeLiked(value: Boolean) { private fun changeLiked(value: Boolean) {
updateState { it.copy(liked = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(liked = value) }
refresh(initial = true) refresh(initial = true)
emitEffect(FilteredContentsMviModel.Effect.BackToTop) emitEffect(FilteredContentsMviModel.Effect.BackToTop)
} }

View File

@ -55,21 +55,23 @@ class InstanceInfoViewModel(
) )
} }
} }
}
if (uiState.value.initial) { if (uiState.value.initial) {
refresh(initial = true) refresh(initial = true)
} }
} }
}
override fun reduce(intent: InstanceInfoMviModel.Intent) { override fun reduce(intent: InstanceInfoMviModel.Intent) {
when (intent) { when (intent) {
InstanceInfoMviModel.Intent.LoadNextPage -> loadNextPage() InstanceInfoMviModel.Intent.LoadNextPage -> loadNextPage()
InstanceInfoMviModel.Intent.Refresh -> refresh() InstanceInfoMviModel.Intent.Refresh ->
screenModelScope.launch {
refresh()
}
} }
} }
private fun refresh(initial: Boolean = false) { private suspend fun refresh(initial: Boolean = false) {
currentPage = 1 currentPage = 1
updateState { updateState {
it.copy( it.copy(
@ -85,7 +87,9 @@ class InstanceInfoViewModel(
private fun loadNextPage() { private fun loadNextPage() {
val currentState = uiState.value val currentState = uiState.value
if (!currentState.canFetchMore || currentState.loading) { if (!currentState.canFetchMore || currentState.loading) {
screenModelScope.launch {
updateState { it.copy(refreshing = false) } updateState { it.copy(refreshing = false) }
}
return return
} }
@ -133,8 +137,8 @@ class InstanceInfoViewModel(
} }
private fun changeSortType(value: SortType) { private fun changeSortType(value: SortType) {
updateState { it.copy(sortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(sortType = value) }
emitEffect(InstanceInfoMviModel.Effect.BackToTop) emitEffect(InstanceInfoMviModel.Effect.BackToTop)
refresh() refresh()
} }

View File

@ -1,18 +1,22 @@
package com.github.diegoberaldin.raccoonforlemmy.unit.licences package com.github.diegoberaldin.raccoonforlemmy.unit.licences
import cafe.adriel.voyager.core.model.screenModelScope
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.unit.licences.models.LicenceItem import com.github.diegoberaldin.raccoonforlemmy.unit.licences.models.LicenceItem
import com.github.diegoberaldin.raccoonforlemmy.unit.licences.models.LicenceItemType import com.github.diegoberaldin.raccoonforlemmy.unit.licences.models.LicenceItemType
import kotlinx.coroutines.launch
class LicencesViewModel : LicencesMviModel, class LicencesViewModel : LicencesMviModel,
DefaultMviModel<LicencesMviModel.Intent, LicencesMviModel.State, LicencesMviModel.Effect>( DefaultMviModel<LicencesMviModel.Intent, LicencesMviModel.State, LicencesMviModel.Effect>(
initialState = LicencesMviModel.State(), initialState = LicencesMviModel.State(),
) { ) {
init { init {
screenModelScope.launch {
populate() populate()
} }
}
private fun populate() { private suspend fun populate() {
updateState { updateState {
it.copy( it.copy(
items = items =

View File

@ -29,10 +29,12 @@ class LoginViewModel(
) { ) {
init { init {
val instance = apiConfigurationRepository.instance.value val instance = apiConfigurationRepository.instance.value
screenModelScope.launch {
updateState { updateState {
it.copy(instanceName = instance) it.copy(instanceName = instance)
} }
} }
}
override fun reduce(intent: LoginMviModel.Intent) { override fun reduce(intent: LoginMviModel.Intent) {
when (intent) { when (intent) {
@ -45,20 +47,28 @@ class LoginViewModel(
} }
private fun setInstanceName(value: String) { private fun setInstanceName(value: String) {
screenModelScope.launch {
updateState { it.copy(instanceName = value) } updateState { it.copy(instanceName = value) }
} }
}
private fun setUsername(value: String) { private fun setUsername(value: String) {
screenModelScope.launch {
updateState { it.copy(username = value.trim()) } updateState { it.copy(username = value.trim()) }
} }
}
private fun setPassword(value: String) { private fun setPassword(value: String) {
screenModelScope.launch {
updateState { it.copy(password = value) } updateState { it.copy(password = value) }
} }
}
private fun setTotp2faToken(value: String) { private fun setTotp2faToken(value: String) {
screenModelScope.launch {
updateState { it.copy(totp2faToken = value) } updateState { it.copy(totp2faToken = value) }
} }
}
private fun submit() { private fun submit() {
val currentState = uiState.value val currentState = uiState.value
@ -70,6 +80,7 @@ class LoginViewModel(
val username = currentState.username val username = currentState.username
val password = currentState.password val password = currentState.password
val totp2faToken = currentState.totp2faToken val totp2faToken = currentState.totp2faToken
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
instanceNameError = null, instanceNameError = null,
@ -77,27 +88,34 @@ class LoginViewModel(
passwordError = null, passwordError = null,
) )
} }
}
val valid = val valid =
when { when {
instance.isEmpty() -> { instance.isEmpty() -> {
screenModelScope.launch {
updateState { updateState {
it.copy(instanceNameError = ValidationError.MissingField) it.copy(instanceNameError = ValidationError.MissingField)
} }
}
false false
} }
username.isEmpty() -> { username.isEmpty() -> {
screenModelScope.launch {
updateState { updateState {
it.copy(usernameError = ValidationError.MissingField) it.copy(usernameError = ValidationError.MissingField)
} }
}
false false
} }
password.isEmpty() -> { password.isEmpty() -> {
screenModelScope.launch {
updateState { updateState {
it.copy(passwordError = ValidationError.MissingField) it.copy(passwordError = ValidationError.MissingField)
} }
}
false false
} }

View File

@ -41,8 +41,10 @@ class ManageBanViewModel(
override fun reduce(intent: ManageBanMviModel.Intent) { override fun reduce(intent: ManageBanMviModel.Intent) {
when (intent) { when (intent) {
is ManageBanMviModel.Intent.ChangeSection -> { is ManageBanMviModel.Intent.ChangeSection -> {
screenModelScope.launch {
updateState { it.copy(section = intent.section) } updateState { it.copy(section = intent.section) }
} }
}
ManageBanMviModel.Intent.Refresh -> { ManageBanMviModel.Intent.Refresh -> {
screenModelScope.launch { screenModelScope.launch {

View File

@ -99,8 +99,8 @@ class ManageSubscriptionsViewModel(
if (uiState.value.refreshing) { if (uiState.value.refreshing) {
return return
} }
updateState { it.copy(refreshing = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(refreshing = true) }
val auth = identityRepository.authToken.value val auth = identityRepository.authToken.value
val accountId = accountRepository.getActive()?.id ?: 0L val accountId = accountRepository.getActive()?.id ?: 0L
val favoriteCommunityIds = val favoriteCommunityIds =
@ -169,6 +169,7 @@ class ManageSubscriptionsViewModel(
} }
private fun handleMultiCommunityCreated(community: MultiCommunityModel) { private fun handleMultiCommunityCreated(community: MultiCommunityModel) {
screenModelScope.launch {
val oldCommunities = uiState.value.multiCommunities val oldCommunities = uiState.value.multiCommunities
val newCommunities = val newCommunities =
if (oldCommunities.any { it.id == community.id }) { if (oldCommunities.any { it.id == community.id }) {
@ -184,6 +185,7 @@ class ManageSubscriptionsViewModel(
}.sortedBy { it.name } }.sortedBy { it.name }
updateState { it.copy(multiCommunities = newCommunities) } updateState { it.copy(multiCommunities = newCommunities) }
} }
}
private fun toggleFavorite(community: CommunityModel) { private fun toggleFavorite(community: CommunityModel) {
val communityId = community.id val communityId = community.id
@ -205,6 +207,7 @@ class ManageSubscriptionsViewModel(
} }
private fun handleCommunityUpdate(community: CommunityModel) { private fun handleCommunityUpdate(community: CommunityModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
communities = communities =
@ -218,10 +221,11 @@ class ManageSubscriptionsViewModel(
) )
} }
} }
}
private fun updateSearchText(value: String) { private fun updateSearchText(value: String) {
updateState { it.copy(searchText = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchText = value) }
searchEventChannel.send(Unit) searchEventChannel.send(Unit)
} }
} }

View File

@ -126,8 +126,8 @@ class InboxMentionsViewModel(
} }
private fun changeUnreadOnly(value: Boolean) { private fun changeUnreadOnly(value: Boolean) {
updateState { it.copy(unreadOnly = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(unreadOnly = value) }
refresh(initial = true) refresh(initial = true)
emitEffect(InboxMentionsMviModel.Effect.BackToTop) emitEffect(InboxMentionsMviModel.Effect.BackToTop)
} }
@ -174,6 +174,7 @@ class InboxMentionsViewModel(
} }
private fun handleItemUpdate(item: PersonMentionModel) { private fun handleItemUpdate(item: PersonMentionModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
mentions = mentions =
@ -187,6 +188,7 @@ class InboxMentionsViewModel(
) )
} }
} }
}
private fun markAsRead( private fun markAsRead(
read: Boolean, read: Boolean,
@ -287,8 +289,8 @@ class InboxMentionsViewModel(
} }
private fun handleLogout() { private fun handleLogout() {
updateState { it.copy(mentions = emptyList()) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(mentions = emptyList()) }
refresh(initial = true) refresh(initial = true)
} }
} }

View File

@ -100,8 +100,8 @@ class InboxMessagesViewModel(
if (uiState.value.currentUserId == 0L) { if (uiState.value.currentUserId == 0L) {
return return
} }
updateState { it.copy(unreadOnly = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(unreadOnly = value) }
refresh(initial = true) refresh(initial = true)
emitEffect(InboxMessagesMviModel.Effect.BackToTop) emitEffect(InboxMessagesMviModel.Effect.BackToTop)
} }
@ -168,8 +168,8 @@ class InboxMessagesViewModel(
} }
private fun handleLogout() { private fun handleLogout() {
updateState { it.copy(chats = emptyList()) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(chats = emptyList()) }
refresh(initial = true) refresh(initial = true)
} }
} }

View File

@ -22,16 +22,20 @@ class ModerateWithReasonViewModel(
initialState = ModerateWithReasonMviModel.UiState(), initialState = ModerateWithReasonMviModel.UiState(),
) { ) {
init { init {
screenModelScope.launch {
updateState { it.copy(action = actionId.toModerateWithReasonAction()) } updateState { it.copy(action = actionId.toModerateWithReasonAction()) }
} }
}
override fun reduce(intent: ModerateWithReasonMviModel.Intent) { override fun reduce(intent: ModerateWithReasonMviModel.Intent) {
when (intent) { when (intent) {
is ModerateWithReasonMviModel.Intent.SetText -> { is ModerateWithReasonMviModel.Intent.SetText -> {
screenModelScope.launch {
updateState { updateState {
it.copy(text = intent.value) it.copy(text = intent.value)
} }
} }
}
ModerateWithReasonMviModel.Intent.Submit -> submit() ModerateWithReasonMviModel.Intent.Submit -> submit()
} }
@ -43,8 +47,8 @@ class ModerateWithReasonViewModel(
} }
val text = uiState.value.text val text = uiState.value.text
updateState { it.copy(loading = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(loading = true) }
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
try { try {
when (uiState.value.action) { when (uiState.value.action) {

View File

@ -53,6 +53,7 @@ class ModlogViewModel(
} }
private fun refresh(initial: Boolean = false) { private fun refresh(initial: Boolean = false) {
screenModelScope.launch {
currentPage = 1 currentPage = 1
updateState { updateState {
it.copy( it.copy(
@ -62,7 +63,6 @@ class ModlogViewModel(
loading = false, loading = false,
) )
} }
screenModelScope.launch {
loadNextPage() loadNextPage()
} }
} }
@ -70,7 +70,9 @@ class ModlogViewModel(
private fun loadNextPage() { private fun loadNextPage() {
val currentState = uiState.value val currentState = uiState.value
if (!currentState.canFetchMore || currentState.loading) { if (!currentState.canFetchMore || currentState.loading) {
screenModelScope.launch {
updateState { it.copy(refreshing = false) } updateState { it.copy(refreshing = false) }
}
return return
} }

View File

@ -247,8 +247,8 @@ class MultiCommunityViewModel(
if (uiState.value.sortType == value) { if (uiState.value.sortType == value) {
return return
} }
updateState { it.copy(sortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(sortType = value) }
emitEffect(MultiCommunityMviModel.Effect.BackToTop) emitEffect(MultiCommunityMviModel.Effect.BackToTop)
delay(50) delay(50)
refresh() refresh()
@ -349,6 +349,7 @@ class MultiCommunityViewModel(
} }
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
posts = posts =
@ -362,16 +363,20 @@ class MultiCommunityViewModel(
) )
} }
} }
}
private fun clearRead() { private fun clearRead() {
screenModelScope.launch {
hideReadPosts = true hideReadPosts = true
updateState { updateState {
val newPosts = it.posts.filter { e -> !e.read } val newPosts = it.posts.filter { e -> !e.read }
it.copy(posts = newPosts) it.copy(posts = newPosts)
} }
} }
}
private fun hide(post: PostModel) { private fun hide(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
val newPosts = it.posts.filter { e -> e.id != post.id } val newPosts = it.posts.filter { e -> e.id != post.id }
it.copy( it.copy(
@ -381,3 +386,4 @@ class MultiCommunityViewModel(
markAsRead(post) markAsRead(post)
} }
} }
}

View File

@ -62,7 +62,10 @@ class MultiCommunityEditorViewModel(
override fun reduce(intent: MultiCommunityEditorMviModel.Intent) { override fun reduce(intent: MultiCommunityEditorMviModel.Intent) {
when (intent) { when (intent) {
is MultiCommunityEditorMviModel.Intent.SelectImage -> selectImage(intent.index) is MultiCommunityEditorMviModel.Intent.SelectImage -> selectImage(intent.index)
is MultiCommunityEditorMviModel.Intent.SetName -> updateState { it.copy(name = intent.value) } is MultiCommunityEditorMviModel.Intent.SetName ->
screenModelScope.launch {
updateState { it.copy(name = intent.value) }
}
is MultiCommunityEditorMviModel.Intent.ToggleCommunity -> toggleCommunity(intent.id) is MultiCommunityEditorMviModel.Intent.ToggleCommunity -> toggleCommunity(intent.id)
is MultiCommunityEditorMviModel.Intent.SetSearch -> setSearch(intent.value) is MultiCommunityEditorMviModel.Intent.SetSearch -> setSearch(intent.value)
MultiCommunityEditorMviModel.Intent.Submit -> submit() MultiCommunityEditorMviModel.Intent.Submit -> submit()
@ -94,8 +97,8 @@ class MultiCommunityEditorViewModel(
} }
private fun setSearch(value: String) { private fun setSearch(value: String) {
updateState { it.copy(searchText = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchText = value) }
searchEventChannel.send(Unit) searchEventChannel.send(Unit)
} }
} }
@ -112,6 +115,7 @@ class MultiCommunityEditorViewModel(
} }
private fun selectImage(index: Int?) { private fun selectImage(index: Int?) {
screenModelScope.launch {
val image = val image =
if (index == null) { if (index == null) {
null null
@ -120,6 +124,7 @@ class MultiCommunityEditorViewModel(
} }
updateState { it.copy(icon = image) } updateState { it.copy(icon = image) }
} }
}
private fun toggleCommunity(communityId: Long) { private fun toggleCommunity(communityId: Long) {
val newCommunities = val newCommunities =
@ -138,6 +143,7 @@ class MultiCommunityEditorViewModel(
} }
communities = newCommunities communities = newCommunities
val filtered = filterCommunities() val filtered = filterCommunities()
screenModelScope.launch {
updateState { state -> updateState { state ->
state.copy( state.copy(
communities = filtered, communities = filtered,
@ -145,14 +151,19 @@ class MultiCommunityEditorViewModel(
) )
} }
} }
}
private fun submit() { private fun submit() {
screenModelScope.launch {
updateState { it.copy(nameError = null) } updateState { it.copy(nameError = null) }
}
val currentState = uiState.value val currentState = uiState.value
var valid = true var valid = true
val name = currentState.name val name = currentState.name
if (name.isEmpty()) { if (name.isEmpty()) {
screenModelScope.launch {
updateState { it.copy(nameError = ValidationError.MissingField) } updateState { it.copy(nameError = ValidationError.MissingField) }
}
valid = false valid = false
} }
if (!valid) { if (!valid) {

View File

@ -53,8 +53,9 @@ class ProfileLoggedViewModel(
initialState = ProfileLoggedMviModel.UiState(), initialState = ProfileLoggedMviModel.UiState(),
) { ) {
init { init {
updateState { it.copy(instance = apiConfigurationRepository.instance.value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(instance = apiConfigurationRepository.instance.value) }
themeRepository.postLayout.onEach { layout -> themeRepository.postLayout.onEach { layout ->
updateState { it.copy(postLayout = layout) } updateState { it.copy(postLayout = layout) }
}.launchIn(this) }.launchIn(this)
@ -253,10 +254,12 @@ class ProfileLoggedViewModel(
} }
private fun changeSection(section: ProfileLoggedSection) { private fun changeSection(section: ProfileLoggedSection) {
screenModelScope.launch {
updateState { updateState {
it.copy(section = section) it.copy(section = section)
} }
} }
}
private suspend fun loadNextPage() { private suspend fun loadNextPage() {
val currentState = uiState.value val currentState = uiState.value
@ -444,6 +447,7 @@ class ProfileLoggedViewModel(
} }
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
posts = posts =
@ -457,8 +461,10 @@ class ProfileLoggedViewModel(
) )
} }
} }
}
private fun handleCommentUpdate(comment: CommentModel) { private fun handleCommentUpdate(comment: CommentModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
comments = comments =
@ -472,9 +478,16 @@ class ProfileLoggedViewModel(
) )
} }
} }
}
private fun handlePostDelete(id: Long) { private fun handlePostDelete(id: Long) {
updateState { it.copy(posts = it.posts.filter { post -> post.id != id }) } screenModelScope.launch {
updateState {
it.copy(
posts = it.posts.filter { post -> post.id != id },
)
}
}
} }
private fun deletePost(id: Long) { private fun deletePost(id: Long) {

View File

@ -126,7 +126,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomS
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.ActionOnSwipe import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.ActionOnSwipe
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
@ -191,7 +190,6 @@ class PostDetailScreen(
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val fabNestedScrollConnection = remember { getFabNestedScrollConnection() } val fabNestedScrollConnection = remember { getFabNestedScrollConnection() }
val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState() val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState()
val notificationCenter = remember { getNotificationCenter() }
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
val upVoteColor by themeRepository.upVoteColor.collectAsState() val upVoteColor by themeRepository.upVoteColor.collectAsState()
val downVoteColor by themeRepository.downVoteColor.collectAsState() val downVoteColor by themeRepository.downVoteColor.collectAsState()
@ -257,9 +255,6 @@ class PostDetailScreen(
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.resetCache()
}
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { effect -> model.effects.onEach { effect ->
when (effect) { when (effect) {

View File

@ -74,6 +74,7 @@ class PostDetailViewModel(
} }
init { init {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
instance = instance =
@ -81,7 +82,6 @@ class PostDetailViewModel(
?: apiConfigurationRepository.instance.value, ?: apiConfigurationRepository.instance.value,
) )
} }
screenModelScope.launch {
if (uiState.value.post.id == 0L) { if (uiState.value.post.id == 0L) {
val post = itemCache.getPost(postId) ?: PostModel() val post = itemCache.getPost(postId) ?: PostModel()
val downVoteEnabled = siteRepository.isDownVoteEnabled(identityRepository.authToken.value) val downVoteEnabled = siteRepository.isDownVoteEnabled(identityRepository.authToken.value)
@ -371,11 +371,13 @@ class PostDetailViewModel(
} }
is PostDetailMviModel.Intent.ChangeSearching -> { is PostDetailMviModel.Intent.ChangeSearching -> {
screenModelScope.launch {
updateState { it.copy(searching = intent.value) } updateState { it.copy(searching = intent.value) }
if (!intent.value) { if (!intent.value) {
updateSearchText("") updateSearchText("")
} }
} }
}
is PostDetailMviModel.Intent.SetSearch -> updateSearchText(intent.value) is PostDetailMviModel.Intent.SetSearch -> updateSearchText(intent.value)
PostDetailMviModel.Intent.NavigatePrevious -> navigateToPreviousPost() PostDetailMviModel.Intent.NavigatePrevious -> navigateToPreviousPost()
@ -472,8 +474,8 @@ class PostDetailViewModel(
if (uiState.value.sortType == value) { if (uiState.value.sortType == value) {
return return
} }
updateState { it.copy(sortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(sortType = value) }
emitEffect(PostDetailMviModel.Effect.BackToTop) emitEffect(PostDetailMviModel.Effect.BackToTop)
delay(50) delay(50)
refresh() refresh()
@ -481,10 +483,12 @@ class PostDetailViewModel(
} }
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy(post = post) it.copy(post = post)
} }
} }
}
private fun loadMoreComments( private fun loadMoreComments(
parentId: Long, parentId: Long,
@ -546,8 +550,8 @@ class PostDetailViewModel(
post = post, post = post,
voted = newValue, voted = newValue,
) )
updateState { it.copy(post = newPost) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(post = newPost) }
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
postRepository.upVote( postRepository.upVote(
@ -572,10 +576,10 @@ class PostDetailViewModel(
post = post, post = post,
downVoted = newValue, downVoted = newValue,
) )
screenModelScope.launch {
updateState { updateState {
it.copy(post = newPost) it.copy(post = newPost)
} }
screenModelScope.launch {
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
postRepository.downVote( postRepository.downVote(
@ -600,8 +604,8 @@ class PostDetailViewModel(
post = post, post = post,
saved = newValue, saved = newValue,
) )
updateState { it.copy(post = newPost) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(post = newPost) }
try { try {
val auth = identityRepository.authToken.value.orEmpty() val auth = identityRepository.authToken.value.orEmpty()
postRepository.save( postRepository.save(
@ -620,6 +624,7 @@ class PostDetailViewModel(
} }
private fun handleCommentUpdate(comment: CommentModel) { private fun handleCommentUpdate(comment: CommentModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
comments = comments =
@ -633,6 +638,7 @@ class PostDetailViewModel(
) )
} }
} }
}
private fun toggleUpVoteComment(comment: CommentModel) { private fun toggleUpVoteComment(comment: CommentModel) {
val newValue = comment.myVote <= 0 val newValue = comment.myVote <= 0
@ -718,8 +724,10 @@ class PostDetailViewModel(
} }
private fun handleCommentDelete(id: Long) { private fun handleCommentDelete(id: Long) {
screenModelScope.launch {
updateState { it.copy(comments = it.comments.filter { comment -> comment.id != id }) } updateState { it.copy(comments = it.comments.filter { comment -> comment.id != id }) }
} }
}
private fun deletePost() { private fun deletePost() {
screenModelScope.launch { screenModelScope.launch {
@ -833,16 +841,16 @@ class PostDetailViewModel(
} }
private fun updateSearchText(value: String) { private fun updateSearchText(value: String) {
updateState { it.copy(searchText = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchText = value) }
searchEventChannel.send(Unit) searchEventChannel.send(Unit)
} }
} }
private fun navigateToPreviousPost() { private fun navigateToPreviousPost() {
val currentId = uiState.value.post.id val currentId = uiState.value.post.id
updateState { it.copy(loading = true, initial = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(loading = true, initial = true) }
postNavigationManager.getPrevious(currentId)?.also { newPost -> postNavigationManager.getPrevious(currentId)?.also { newPost ->
loadNewPost(newPost) loadNewPost(newPost)
} }
@ -851,8 +859,8 @@ class PostDetailViewModel(
private fun navigateToNextPost() { private fun navigateToNextPost() {
val currentId = uiState.value.post.id val currentId = uiState.value.post.id
updateState { it.copy(loading = true, initial = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(loading = true, initial = true) }
postNavigationManager.getNext(currentId)?.also { newPost -> postNavigationManager.getNext(currentId)?.also { newPost ->
loadNewPost(newPost) loadNewPost(newPost)
} }

View File

@ -156,6 +156,7 @@ class PostListViewModel(
} }
private fun onFirstLoad() { private fun onFirstLoad() {
screenModelScope.launch {
val settings = settingsRepository.currentSettings.value val settings = settingsRepository.currentSettings.value
updateState { updateState {
it.copy( it.copy(
@ -163,7 +164,6 @@ class PostListViewModel(
sortType = settings.defaultPostSortType.toSortType(), sortType = settings.defaultPostSortType.toSortType(),
) )
} }
screenModelScope.launch {
refreshUser() refreshUser()
refresh(initial = true) refresh(initial = true)
emitEffect(PostListMviModel.Effect.BackToTop) emitEffect(PostListMviModel.Effect.BackToTop)
@ -251,17 +251,21 @@ class PostListViewModel(
} }
PostListMviModel.Intent.PauseZombieMode -> { PostListMviModel.Intent.PauseZombieMode -> {
screenModelScope.launch {
updateState { it.copy(zombieModeActive = false) } updateState { it.copy(zombieModeActive = false) }
zombieModeHelper.pause() zombieModeHelper.pause()
} }
}
is PostListMviModel.Intent.StartZombieMode -> { is PostListMviModel.Intent.StartZombieMode -> {
screenModelScope.launch {
updateState { it.copy(zombieModeActive = true) } updateState { it.copy(zombieModeActive = true) }
zombieModeHelper.start( zombieModeHelper.start(
initialValue = intent.index, initialValue = intent.index,
interval = settingsRepository.currentSettings.value.zombieModeInterval, interval = settingsRepository.currentSettings.value.zombieModeInterval,
) )
} }
}
is PostListMviModel.Intent.Copy -> is PostListMviModel.Intent.Copy ->
screenModelScope.launch { screenModelScope.launch {
@ -339,8 +343,8 @@ class PostListViewModel(
if (uiState.value.sortType == value) { if (uiState.value.sortType == value) {
return return
} }
updateState { it.copy(sortType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(sortType = value) }
emitEffect(PostListMviModel.Effect.BackToTop) emitEffect(PostListMviModel.Effect.BackToTop)
delay(50) delay(50)
refresh() refresh()
@ -351,8 +355,8 @@ class PostListViewModel(
if (uiState.value.listingType == value) { if (uiState.value.listingType == value) {
return return
} }
updateState { it.copy(listingType = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(listingType = value) }
emitEffect(PostListMviModel.Effect.BackToTop) emitEffect(PostListMviModel.Effect.BackToTop)
delay(50) delay(50)
refresh() refresh()
@ -453,6 +457,7 @@ class PostListViewModel(
} }
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
posts = posts =
@ -466,8 +471,10 @@ class PostListViewModel(
) )
} }
} }
}
private fun handleLogout() { private fun handleLogout() {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
posts = emptyList(), posts = emptyList(),
@ -476,6 +483,7 @@ class PostListViewModel(
} }
onFirstLoad() onFirstLoad()
} }
}
private fun handlePostDelete(id: Long) { private fun handlePostDelete(id: Long) {
screenModelScope.launch { screenModelScope.launch {
@ -486,14 +494,17 @@ class PostListViewModel(
} }
private fun clearRead() { private fun clearRead() {
screenModelScope.launch {
hideReadPosts = true hideReadPosts = true
updateState { updateState {
val newPosts = it.posts.filter { e -> !e.read } val newPosts = it.posts.filter { e -> !e.read }
it.copy(posts = newPosts) it.copy(posts = newPosts)
} }
} }
}
private fun hide(post: PostModel) { private fun hide(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
val newPosts = it.posts.filter { e -> e.id != post.id } val newPosts = it.posts.filter { e -> e.id != post.id }
it.copy( it.copy(
@ -502,6 +513,7 @@ class PostListViewModel(
} }
markAsRead(post) markAsRead(post)
} }
}
private fun blockUser(userId: Long) { private fun blockUser(userId: Long) {
screenModelScope.launch { screenModelScope.launch {

View File

@ -123,8 +123,8 @@ class InboxRepliesViewModel(
} }
private fun changeUnreadOnly(value: Boolean) { private fun changeUnreadOnly(value: Boolean) {
updateState { it.copy(unreadOnly = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(unreadOnly = value) }
refresh(initial = true) refresh(initial = true)
emitEffect(InboxRepliesMviModel.Effect.BackToTop) emitEffect(InboxRepliesMviModel.Effect.BackToTop)
} }
@ -171,6 +171,7 @@ class InboxRepliesViewModel(
} }
private fun handleItemUpdate(item: PersonMentionModel) { private fun handleItemUpdate(item: PersonMentionModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
replies = replies =
@ -184,6 +185,7 @@ class InboxRepliesViewModel(
) )
} }
} }
}
private fun markAsRead( private fun markAsRead(
read: Boolean, read: Boolean,
@ -282,8 +284,8 @@ class InboxRepliesViewModel(
} }
private fun handleLogout() { private fun handleLogout() {
updateState { it.copy(replies = emptyList()) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(replies = emptyList()) }
refresh(initial = true) refresh(initial = true)
} }
} }

View File

@ -90,18 +90,20 @@ class ReportListViewModel(
} }
private fun changeSection(section: ReportListSection) { private fun changeSection(section: ReportListSection) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
section = section, section = section,
) )
} }
} }
}
private fun changeUnresolvedOnly(value: Boolean) { private fun changeUnresolvedOnly(value: Boolean) {
screenModelScope.launch {
updateState { updateState {
it.copy(unresolvedOnly = value) it.copy(unresolvedOnly = value)
} }
screenModelScope.launch {
emitEffect(ReportListMviModel.Effect.BackToTop) emitEffect(ReportListMviModel.Effect.BackToTop)
delay(50) delay(50)
refresh(initial = true) refresh(initial = true)
@ -255,6 +257,7 @@ class ReportListViewModel(
} }
private fun handleReportUpdate(report: PostReportModel) { private fun handleReportUpdate(report: PostReportModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
postReports = postReports =
@ -268,8 +271,10 @@ class ReportListViewModel(
) )
} }
} }
}
private fun handleReportUpdate(report: CommentReportModel) { private fun handleReportUpdate(report: CommentReportModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
commentReports = commentReports =
@ -283,16 +288,20 @@ class ReportListViewModel(
) )
} }
} }
}
private fun handleReporDelete(report: PostReportModel) { private fun handleReporDelete(report: PostReportModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
postReports = it.postReports.filter { r -> r.id != report.id }, postReports = it.postReports.filter { r -> r.id != report.id },
) )
} }
} }
}
private fun handleReporDelete(report: CommentReportModel) { private fun handleReporDelete(report: CommentReportModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
commentReports = it.commentReports.filter { r -> r.id != report.id }, commentReports = it.commentReports.filter { r -> r.id != report.id },
@ -300,3 +309,4 @@ class ReportListViewModel(
} }
} }
} }
}

View File

@ -58,8 +58,8 @@ class SelectCommunityViewModel(
} }
private fun setSearch(value: String) { private fun setSearch(value: String) {
updateState { it.copy(searchText = value) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(searchText = value) }
searchEventChannel.send(Unit) searchEventChannel.send(Unit)
} }
} }

View File

@ -51,8 +51,10 @@ class SelectInstanceViewModel(
} }
is SelectInstanceMviModel.Intent.ChangeInstanceName -> { is SelectInstanceMviModel.Intent.ChangeInstanceName -> {
screenModelScope.launch {
updateState { it.copy(changeInstanceName = intent.value) } updateState { it.copy(changeInstanceName = intent.value) }
} }
}
is SelectInstanceMviModel.Intent.SubmitChangeInstanceDialog -> submitChangeInstance() is SelectInstanceMviModel.Intent.SubmitChangeInstanceDialog -> submitChangeInstance()
is SelectInstanceMviModel.Intent.DeleteInstance -> deleteInstance(intent.value) is SelectInstanceMviModel.Intent.DeleteInstance -> deleteInstance(intent.value)
@ -69,11 +71,15 @@ class SelectInstanceViewModel(
} }
private fun submitChangeInstance() { private fun submitChangeInstance() {
screenModelScope.launch {
updateState { it.copy(changeInstanceNameError = null) } updateState { it.copy(changeInstanceNameError = null) }
}
var valid = true var valid = true
val instanceName = uiState.value.changeInstanceName val instanceName = uiState.value.changeInstanceName
if (instanceName.isEmpty()) { if (instanceName.isEmpty()) {
screenModelScope.launch {
updateState { it.copy(changeInstanceNameError = ValidationError.MissingField) } updateState { it.copy(changeInstanceNameError = ValidationError.MissingField) }
}
valid = false valid = false
} }
if (!valid) { if (!valid) {

View File

@ -98,7 +98,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomS
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel import com.github.diegoberaldin.raccoonforlemmy.core.navigation.getScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.ActionOnSwipe import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.ActionOnSwipe
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
@ -152,7 +151,6 @@ class UserDetailScreen(
val otherInstanceName = remember { otherInstance } val otherInstanceName = remember { otherInstance }
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val notificationCenter = remember { getNotificationCenter() }
val fabNestedScrollConnection = remember { getFabNestedScrollConnection() } val fabNestedScrollConnection = remember { getFabNestedScrollConnection() }
val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState() val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState()
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
@ -171,9 +169,6 @@ class UserDetailScreen(
val detailOpener = remember { getDetailOpener() } val detailOpener = remember { getDetailOpener() }
val clipboardManager = LocalClipboardManager.current val clipboardManager = LocalClipboardManager.current
LaunchedEffect(notificationCenter) {
notificationCenter.resetCache()
}
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { effect -> model.effects.onEach { effect ->
when (effect) { when (effect) {

View File

@ -63,6 +63,7 @@ class UserDetailViewModel(
initialState = UserDetailMviModel.UiState(), initialState = UserDetailMviModel.UiState(),
) { ) {
init { init {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
instance = instance =
@ -70,7 +71,7 @@ class UserDetailViewModel(
?: apiConfigurationRepository.instance.value, ?: apiConfigurationRepository.instance.value,
) )
} }
screenModelScope.launch {
if (uiState.value.user.id == 0L) { if (uiState.value.user.id == 0L) {
val user = itemCache.getUser(userId) ?: UserModel() val user = itemCache.getUser(userId) ?: UserModel()
updateState { updateState {
@ -238,8 +239,8 @@ class UserDetailViewModel(
if (uiState.value.sortType == value) { if (uiState.value.sortType == value) {
return return
} }
updateState { it.copy(sortType = value) }
screenModelScope.launch(Dispatchers.Main) { screenModelScope.launch(Dispatchers.Main) {
updateState { it.copy(sortType = value) }
emitEffect(UserDetailMviModel.Effect.BackToTop) emitEffect(UserDetailMviModel.Effect.BackToTop)
delay(50) delay(50)
refresh() refresh()
@ -247,10 +248,12 @@ class UserDetailViewModel(
} }
private fun changeSection(section: UserDetailSection) { private fun changeSection(section: UserDetailSection) {
screenModelScope.launch {
updateState { updateState {
it.copy(section = section) it.copy(section = section)
} }
} }
}
private fun updateAvailableSortTypes() { private fun updateAvailableSortTypes() {
screenModelScope.launch { screenModelScope.launch {
@ -495,6 +498,7 @@ class UserDetailViewModel(
} }
private fun handlePostUpdate(post: PostModel) { private fun handlePostUpdate(post: PostModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
posts = posts =
@ -508,8 +512,10 @@ class UserDetailViewModel(
) )
} }
} }
}
private fun handleCommentUpdate(comment: CommentModel) { private fun handleCommentUpdate(comment: CommentModel) {
screenModelScope.launch {
updateState { updateState {
it.copy( it.copy(
comments = comments =
@ -523,10 +529,11 @@ class UserDetailViewModel(
) )
} }
} }
}
private fun blockUser() { private fun blockUser() {
updateState { it.copy(asyncInProgress = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(asyncInProgress = true) }
try { try {
val auth = identityRepository.authToken.value val auth = identityRepository.authToken.value
userRepository.block(userId, true, auth).getOrThrow() userRepository.block(userId, true, auth).getOrThrow()
@ -540,8 +547,8 @@ class UserDetailViewModel(
} }
private fun blockInstance() { private fun blockInstance() {
updateState { it.copy(asyncInProgress = true) }
screenModelScope.launch { screenModelScope.launch {
updateState { it.copy(asyncInProgress = true) }
try { try {
val user = uiState.value.user val user = uiState.value.user
val instanceId = user.instanceId val instanceId = user.instanceId

View File

@ -125,8 +125,10 @@ class ZoomableImageViewModel(
private fun changeContentScale(contentScale: ContentScale) { private fun changeContentScale(contentScale: ContentScale) {
imagePreloadManager.remove(url) imagePreloadManager.remove(url)
screenModelScope.launch {
updateState { updateState {
it.copy(contentScale = contentScale) it.copy(contentScale = contentScale)
} }
} }
} }
}