fix(inbox): navigation between screens

This commit is contained in:
Diego Beraldin 2023-09-09 14:53:28 +02:00
parent 5bd81e529b
commit a2f6ea97a4
5 changed files with 73 additions and 29 deletions

View File

@ -13,6 +13,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -22,6 +23,8 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.CurrentScreen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.racconforlemmy.core.utils.onClick import com.github.diegoberaldin.racconforlemmy.core.utils.onClick
@ -31,12 +34,16 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Section
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.InboxTypeSheet import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.InboxTypeSheet
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxViewModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.mentions.InboxMentionsScreen import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.mentions.InboxMentionsScreen
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.messages.InboxMessagesScreen
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.replies.InboxRepliesScreen import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.replies.InboxRepliesScreen
import com.github.diegoberaldin.raccoonforlemmy.resources.MR import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository
import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString
import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.compose.stringResource
import dev.icerock.moko.resources.desc.desc import dev.icerock.moko.resources.desc.desc
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
class InboxScreen : Screen { class InboxScreen : Screen {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -133,19 +140,28 @@ class InboxScreen : Screen {
model.reduce(InboxMviModel.Intent.ChangeSection(section)) model.reduce(InboxMviModel.Intent.ChangeSection(section))
}, },
) )
val screen = when (uiState.section) { val screens = listOf(
InboxSection.REPLIES -> InboxRepliesScreen( InboxRepliesScreen().apply {
parentModel = model, parentModel = model
) },
InboxMentionsScreen().apply {
InboxSection.MENTIONS -> InboxMentionsScreen( parentModel = model
parentModel = model, },
) InboxMessagesScreen()
)
InboxSection.MESSAGES -> null Navigator(screens) {
} CurrentScreen()
if (screen != null) { val navigator = LocalNavigator.current
Navigator(screen) LaunchedEffect(model) {
model.uiState.map { it.section }.onEach { section ->
val index = when (section) {
InboxSection.REPLIES -> 0
InboxSection.MENTIONS -> 1
InboxSection.MESSAGES -> 2
}
navigator?.replace(screens[index])
}.launchIn(this)
}
} }
} }
} }

View File

@ -46,39 +46,42 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDet
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxMentionsViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxMentionsViewModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxMviModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxMviModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
class InboxMentionsScreen( class InboxMentionsScreen : Screen {
private val parentModel: InboxViewModel,
) : Screen { var parentModel: InboxViewModel? = null
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
override fun Content() { override fun Content() {
val model = rememberScreenModel { getInboxMentionsViewModel() } val model = rememberScreenModel { getInboxMentionsViewModel() }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val parentUiState by parentModel.uiState.collectAsState() val parentUiState by (parentModel?.uiState
?: MutableStateFlow(InboxMviModel.UiState())).collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigator = remember { getNavigationCoordinator().getRootNavigator() }
LaunchedEffect(parentModel) { LaunchedEffect(parentModel) {
parentModel.uiState.map { it.unreadOnly }.distinctUntilChanged().onEach { parentModel?.uiState?.map { it.unreadOnly }?.distinctUntilChanged()?.onEach {
model.reduce(InboxMentionsMviModel.Intent.ChangeUnreadOnly(unread = it)) model.reduce(InboxMentionsMviModel.Intent.ChangeUnreadOnly(unread = it))
}.launchIn(this) }?.launchIn(this)
if (uiState.unreadOnly != parentUiState.unreadOnly) { if (uiState.unreadOnly != parentUiState.unreadOnly) {
model.reduce(InboxMentionsMviModel.Intent.ChangeUnreadOnly(parentUiState.unreadOnly)) model.reduce(InboxMentionsMviModel.Intent.ChangeUnreadOnly(parentUiState.unreadOnly))
} }
parentModel.effects.onEach { parentModel?.effects?.onEach {
when (it) { when (it) {
InboxMviModel.Effect.Refresh -> { InboxMviModel.Effect.Refresh -> {
model.reduce(InboxMentionsMviModel.Intent.Refresh) model.reduce(InboxMentionsMviModel.Intent.Refresh)
} }
} }
}.launchIn(this) }?.launchIn(this)
} }
val pullRefreshState = rememberPullRefreshState(uiState.refreshing, { val pullRefreshState = rememberPullRefreshState(uiState.refreshing, {

View File

@ -0,0 +1,22 @@
package com.github.diegoberaldin.raccoonforlemmy.feature.inbox.messages
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import cafe.adriel.voyager.core.screen.Screen
class InboxMessagesScreen : Screen {
@Composable
override fun Content() {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "\uD83D\uDEA7 Work in progress! \uD83D\uDEA7",
style = MaterialTheme.typography.titleLarge,
)
}
}
}

View File

@ -46,39 +46,42 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDet
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxRepliesViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxRepliesViewModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxMviModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxMviModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
class InboxRepliesScreen( class InboxRepliesScreen : Screen {
private val parentModel: InboxViewModel,
) : Screen { var parentModel: InboxViewModel? = null
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
override fun Content() { override fun Content() {
val model = rememberScreenModel { getInboxRepliesViewModel() } val model = rememberScreenModel { getInboxRepliesViewModel() }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val parentUiState by parentModel.uiState.collectAsState() val parentUiState by (parentModel?.uiState
?: MutableStateFlow(InboxMviModel.UiState())).collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigator = remember { getNavigationCoordinator().getRootNavigator() }
LaunchedEffect(parentModel) { LaunchedEffect(parentModel) {
parentModel.uiState.map { it.unreadOnly }.distinctUntilChanged().onEach { parentModel?.uiState?.map { it.unreadOnly }?.distinctUntilChanged()?.onEach {
model.reduce(InboxRepliesMviModel.Intent.ChangeUnreadOnly(unread = it)) model.reduce(InboxRepliesMviModel.Intent.ChangeUnreadOnly(unread = it))
}.launchIn(this) }?.launchIn(this)
if (uiState.unreadOnly != parentUiState.unreadOnly) { if (uiState.unreadOnly != parentUiState.unreadOnly) {
model.reduce(InboxRepliesMviModel.Intent.ChangeUnreadOnly(parentUiState.unreadOnly)) model.reduce(InboxRepliesMviModel.Intent.ChangeUnreadOnly(parentUiState.unreadOnly))
} }
parentModel.effects.onEach { parentModel?.effects?.onEach {
when (it) { when (it) {
InboxMviModel.Effect.Refresh -> { InboxMviModel.Effect.Refresh -> {
model.reduce(InboxRepliesMviModel.Intent.Refresh) model.reduce(InboxRepliesMviModel.Intent.Refresh)
} }
} }
}.launchIn(this) }?.launchIn(this)
} }
val pullRefreshState = rememberPullRefreshState(uiState.refreshing, { val pullRefreshState = rememberPullRefreshState(uiState.refreshing, {