chore: screen model and navigator optimizations (#103)

This commit is contained in:
Diego Beraldin 2023-11-05 13:58:46 +01:00 committed by GitHub
parent a4a8722b02
commit e007426b37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 1227 additions and 951 deletions

View File

@ -1,11 +1,13 @@
package com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository package com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@Stable
interface ThemeRepository { interface ThemeRepository {
val uiTheme: StateFlow<UiTheme> val uiTheme: StateFlow<UiTheme>

View File

@ -1,9 +1,11 @@
package com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme package com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme
import androidx.compose.material3.ColorScheme import androidx.compose.material3.ColorScheme
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
@Stable
interface ColorSchemeProvider { interface ColorSchemeProvider {
val supportsDynamicColors: Boolean val supportsDynamicColors: Boolean

View File

@ -1,9 +1,11 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.chat package com.github.diegoberaldin.raccoonforlemmy.core.commonui.chat
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel
@Stable
interface InboxChatMviModel : interface InboxChatMviModel :
MviModel<InboxChatMviModel.Intent, InboxChatMviModel.UiState, InboxChatMviModel.SideEffect>, MviModel<InboxChatMviModel.Intent, InboxChatMviModel.UiState, InboxChatMviModel.SideEffect>,
ScreenModel { ScreenModel {

View File

@ -67,7 +67,7 @@ class InboxChatScreen(
val model = rememberScreenModel { getInboxChatViewModel(otherUserId) } val model = rememberScreenModel { getInboxChatViewModel(otherUserId) }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
DisposableEffect(key) { DisposableEffect(key) {
@ -112,7 +112,7 @@ class InboxChatScreen(
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,

View File

@ -31,9 +31,11 @@ class InboxChatViewModel(
private var currentPage: Int = 1 private var currentPage: Int = 1
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
handleLogout() handleLogout()
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout
)
} }
fun finalize() { fun finalize() {

View File

@ -1,9 +1,11 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo package com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
@Stable
interface CommunityInfoMviModel : interface CommunityInfoMviModel :
MviModel<CommunityInfoMviModel.Intent, CommunityInfoMviModel.UiState, CommunityInfoMviModel.Effect>, MviModel<CommunityInfoMviModel.Intent, CommunityInfoMviModel.UiState, CommunityInfoMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail package com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
@ -7,6 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
@Stable
interface CommunityDetailMviModel : interface CommunityDetailMviModel :
MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect>, MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect>,
ScreenModel { ScreenModel {
@ -15,16 +17,16 @@ interface CommunityDetailMviModel :
data object Refresh : Intent data object Refresh : Intent
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class ChangeSort(val value: SortType) : Intent data class ChangeSort(val value: SortType) : Intent
data class UpVotePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class DownVotePost(val index: Int, val feedback: Boolean = false) : Intent data class DownVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class SavePost(val id: Int, val feedback: Boolean = false) : Intent
data object HapticIndication : Intent data object HapticIndication : Intent
data object Subscribe : Intent data object Subscribe : Intent
data object Unsubscribe : Intent data object Unsubscribe : Intent
data class DeletePost(val id: Int) : Intent data class DeletePost(val id: Int) : Intent
data class SharePost(val index: Int) : Intent data class SharePost(val id: Int) : Intent
data class MarkAsRead(val index: Int) : Intent data class MarkAsRead(val id: Int) : Intent
data class Hide(val index: Int) : Intent data class Hide(val id: Int) : Intent
data object Block : Intent data object Block : Intent
data object BlockInstance : Intent data object BlockInstance : Intent
data object ClearRead : Intent data object ClearRead : Intent

View File

@ -13,7 +13,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -60,7 +60,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
@ -88,6 +87,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateRepor
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs
@ -123,14 +123,13 @@ class CommunityDetailScreen(
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val genericError = stringResource(MR.strings.message_generic_error) val genericError = stringResource(MR.strings.message_generic_error)
val successMessage = stringResource(MR.strings.message_operation_successful) val successMessage = stringResource(MR.strings.message_operation_successful)
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val isOnOtherInstance = otherInstance.isNotEmpty() val isOnOtherInstance = otherInstance.isNotEmpty()
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
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 notificationCenter = remember { getNotificationCenter() }
val navigationCoordinator = remember { getNavigationCoordinator() }
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()
@ -138,6 +137,8 @@ class CommunityDetailScreen(
val defaultDownVoteColor = MaterialTheme.colorScheme.tertiary val defaultDownVoteColor = MaterialTheme.colorScheme.tertiary
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
var rawContent by remember { mutableStateOf<Any?>(null) } var rawContent by remember { mutableStateOf<Any?>(null) }
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
DisposableEffect(key) { DisposableEffect(key) {
drawerCoordinator.setGesturesEnabled(false) drawerCoordinator.setGesturesEnabled(false)
@ -146,7 +147,38 @@ class CommunityDetailScreen(
drawerCoordinator.setGesturesEnabled(true) drawerCoordinator.setGesturesEnabled(true)
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
CommunityDetailMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
model.reduce(CommunityDetailMviModel.Intent.Refresh)
}, key, NotificationCenterContractKeys.PostCreated
)
notificationCenter.addObserver(
{
model.reduce(CommunityDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.PostCreated
)
notificationCenter.addObserver(
{
model.reduce(CommunityDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
}
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { model.effects.onEach {
when (it) { when (it) {
@ -170,8 +202,6 @@ class CommunityDetailScreen(
val stateCommunity = uiState.community val stateCommunity = uiState.community
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection)
.background(MaterialTheme.colorScheme.background) .background(MaterialTheme.colorScheme.background)
.padding(Spacing.xs), .padding(Spacing.xs),
topBar = { topBar = {
@ -216,16 +246,7 @@ class CommunityDetailScreen(
val sheet = SortBottomSheet( val sheet = SortBottomSheet(
expandTop = true, expandTop = true,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
CommunityDetailMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
), ),
imageVector = uiState.sortType.toIcon(), imageVector = uiState.sortType.toIcon(),
@ -234,6 +255,7 @@ class CommunityDetailScreen(
) )
}, },
navigationIcon = { navigationIcon = {
val navigator = navigationCoordinator.getRootNavigator()
if (navigator?.canPop == true) { if (navigator?.canPop == true) {
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
@ -264,7 +286,7 @@ class CommunityDetailScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ExpandLess, icon = Icons.Default.ExpandLess,
text = stringResource(MR.strings.action_back_to_top), text = stringResource(MR.strings.action_back_to_top),
onSelected = { onSelected = rememberCallback {
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
topAppBarState.heightOffset = 0f topAppBarState.heightOffset = 0f
@ -275,7 +297,7 @@ class CommunityDetailScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ClearAll, icon = Icons.Default.ClearAll,
text = stringResource(MR.strings.action_clear_read), text = stringResource(MR.strings.action_clear_read),
onSelected = { onSelected = rememberCallback {
model.reduce(CommunityDetailMviModel.Intent.ClearRead) model.reduce(CommunityDetailMviModel.Intent.ClearRead)
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
@ -286,14 +308,11 @@ class CommunityDetailScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.Create, icon = Icons.Default.Create,
text = stringResource(MR.strings.action_create_post), text = stringResource(MR.strings.action_create_post),
onSelected = { onSelected = rememberCallback {
val screen = CreatePostScreen( val screen = CreatePostScreen(
communityId = stateCommunity.id, communityId = stateCommunity.id,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(screen)
model.reduce(CommunityDetailMviModel.Intent.Refresh)
}, key, NotificationCenterContractKeys.PostCreated)
bottomSheetNavigator.show(screen)
}, },
) )
} }
@ -312,6 +331,14 @@ class CommunityDetailScreen(
Box( Box(
modifier = Modifier modifier = Modifier
.padding(padding) .padding(padding)
.let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.nestedScroll(fabNestedScrollConnection)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
@ -328,7 +355,8 @@ class CommunityDetailScreen(
stringResource(MR.strings.community_detail_block_instance), stringResource(MR.strings.community_detail_block_instance),
), ),
onOpenImage = rememberCallbackArgs { url -> onOpenImage = rememberCallbackArgs { url ->
navigator?.push(ZoomableImageScreen(url)) navigationCoordinator.getRootNavigator()
?.push(ZoomableImageScreen(url))
}, },
onOptionSelected = rememberCallbackArgs { optionIdx -> onOptionSelected = rememberCallbackArgs { optionIdx ->
when (optionIdx) { when (optionIdx) {
@ -336,7 +364,7 @@ class CommunityDetailScreen(
2 -> model.reduce(CommunityDetailMviModel.Intent.Block) 2 -> model.reduce(CommunityDetailMviModel.Intent.Block)
1 -> { 1 -> {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
InstanceInfoScreen( InstanceInfoScreen(
url = stateCommunity.instanceUrl, url = stateCommunity.instanceUrl,
), ),
@ -344,7 +372,7 @@ class CommunityDetailScreen(
} }
else -> { else -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()?.show(
CommunityInfoScreen(stateCommunity), CommunityInfoScreen(stateCommunity),
) )
} }
@ -367,7 +395,7 @@ class CommunityDetailScreen(
} }
} }
} }
itemsIndexed(uiState.posts) { idx, post -> items(uiState.posts) { post ->
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled && !isOnOtherInstance, enabled = uiState.swipeActionsEnabled && !isOnOtherInstance,
@ -398,12 +426,12 @@ class CommunityDetailScreen(
}, },
onDismissToStart = rememberCallback(model) { onDismissToStart = rememberCallback(model) {
model.reduce( model.reduce(
CommunityDetailMviModel.Intent.UpVotePost(idx), CommunityDetailMviModel.Intent.UpVotePost(post.id),
) )
}, },
onDismissToEnd = rememberCallback(model) { onDismissToEnd = rememberCallback(model) {
model.reduce( model.reduce(
CommunityDetailMviModel.Intent.DownVotePost(idx), CommunityDetailMviModel.Intent.DownVotePost(post.id),
) )
}, },
content = { content = {
@ -420,10 +448,10 @@ class CommunityDetailScreen(
onClick = rememberCallback(model) { onClick = rememberCallback(model) {
model.reduce( model.reduce(
CommunityDetailMviModel.Intent.MarkAsRead( CommunityDetailMviModel.Intent.MarkAsRead(
idx post.id
) )
) )
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen( PostDetailScreen(
post = post, post = post,
otherInstance = otherInstance, otherInstance = otherInstance,
@ -431,7 +459,7 @@ class CommunityDetailScreen(
) )
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator = rememberCallbackArgs { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen( UserDetailScreen(
user = user, user = user,
otherInstance = otherInstance, otherInstance = otherInstance,
@ -442,7 +470,7 @@ class CommunityDetailScreen(
if (!isOnOtherInstance) { if (!isOnOtherInstance) {
model.reduce( model.reduce(
CommunityDetailMviModel.Intent.UpVotePost( CommunityDetailMviModel.Intent.UpVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -452,7 +480,7 @@ class CommunityDetailScreen(
if (!isOnOtherInstance) { if (!isOnOtherInstance) {
model.reduce( model.reduce(
CommunityDetailMviModel.Intent.DownVotePost( CommunityDetailMviModel.Intent.DownVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -462,7 +490,7 @@ class CommunityDetailScreen(
if (!isOnOtherInstance) { if (!isOnOtherInstance) {
model.reduce( model.reduce(
CommunityDetailMviModel.Intent.SavePost( CommunityDetailMviModel.Intent.SavePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -473,23 +501,17 @@ class CommunityDetailScreen(
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = post, originalPost = post,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(screen)
model.reduce(CommunityDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
} }
}, },
onImageClick = rememberCallbackArgs(model) { url -> onImageClick = rememberCallbackArgs(model) { url ->
model.reduce( model.reduce(
CommunityDetailMviModel.Intent.MarkAsRead( CommunityDetailMviModel.Intent.MarkAsRead(
idx post.id
) )
) )
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url), ZoomableImageScreen(url),
) )
}, },
@ -512,14 +534,8 @@ class CommunityDetailScreen(
) )
4 -> { 4 -> {
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(
model.reduce(CommunityDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.PostCreated
)
bottomSheetNavigator.show(
CreatePostScreen( CreatePostScreen(
editedPost = post, editedPost = post,
) )
@ -527,7 +543,8 @@ class CommunityDetailScreen(
} }
3 -> { 3 -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()
?.show(
CreateReportScreen( CreateReportScreen(
postId = post.id postId = post.id
) )
@ -540,12 +557,12 @@ class CommunityDetailScreen(
1 -> model.reduce( 1 -> model.reduce(
CommunityDetailMviModel.Intent.Hide( CommunityDetailMviModel.Intent.Hide(
idx post.id
) )
) )
else -> model.reduce( else -> model.reduce(
CommunityDetailMviModel.Intent.SharePost(idx) CommunityDetailMviModel.Intent.SharePost(post.id)
) )
} }
}) })

View File

@ -33,8 +33,8 @@ class CommunityDetailViewModel(
private val settingsRepository: SettingsRepository, private val settingsRepository: SettingsRepository,
private val shareHelper: ShareHelper, private val shareHelper: ShareHelper,
private val hapticFeedback: HapticFeedback, private val hapticFeedback: HapticFeedback,
) : MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect> by mvi, ) : CommunityDetailMviModel,
CommunityDetailMviModel { MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect> by mvi {
private var currentPage: Int = 1 private var currentPage: Int = 1
private var pageCursor: String? = null private var pageCursor: String? = null
@ -85,17 +85,17 @@ class CommunityDetailViewModel(
CommunityDetailMviModel.Intent.Refresh -> refresh() CommunityDetailMviModel.Intent.Refresh -> refresh()
is CommunityDetailMviModel.Intent.DownVotePost -> toggleDownVotePost( is CommunityDetailMviModel.Intent.DownVotePost -> toggleDownVotePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is CommunityDetailMviModel.Intent.SavePost -> toggleSavePost( is CommunityDetailMviModel.Intent.SavePost -> toggleSavePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is CommunityDetailMviModel.Intent.UpVotePost -> toggleUpVotePost( is CommunityDetailMviModel.Intent.UpVotePost -> toggleUpVotePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
@ -105,17 +105,17 @@ class CommunityDetailViewModel(
CommunityDetailMviModel.Intent.Unsubscribe -> unsubscribe() CommunityDetailMviModel.Intent.Unsubscribe -> unsubscribe()
is CommunityDetailMviModel.Intent.DeletePost -> handlePostDelete(intent.id) is CommunityDetailMviModel.Intent.DeletePost -> handlePostDelete(intent.id)
is CommunityDetailMviModel.Intent.SharePost -> share( is CommunityDetailMviModel.Intent.SharePost -> share(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
) )
CommunityDetailMviModel.Intent.Block -> blockCommunity() CommunityDetailMviModel.Intent.Block -> blockCommunity()
CommunityDetailMviModel.Intent.BlockInstance -> blockInstance() CommunityDetailMviModel.Intent.BlockInstance -> blockInstance()
is CommunityDetailMviModel.Intent.MarkAsRead -> { is CommunityDetailMviModel.Intent.MarkAsRead -> {
markAsRead(uiState.value.posts[intent.index]) markAsRead(uiState.value.posts.first { it.id == intent.id })
} }
CommunityDetailMviModel.Intent.ClearRead -> clearRead() CommunityDetailMviModel.Intent.ClearRead -> clearRead()
is CommunityDetailMviModel.Intent.Hide -> hide(post = uiState.value.posts[intent.index]) is CommunityDetailMviModel.Intent.Hide -> hide(post = uiState.value.posts.first { it.id == intent.id })
} }
} }

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.components package com.github.diegoberaldin.raccoonforlemmy.core.commonui.components
import androidx.compose.runtime.Stable
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.NestedScrollSource
@ -13,6 +14,7 @@ import kotlinx.coroutines.flow.stateIn
private const val THRESHOLD = 5f private const val THRESHOLD = 5f
@Stable
interface FabNestedScrollConnection : NestedScrollConnection { interface FabNestedScrollConnection : NestedScrollConnection {
val isFabVisible: StateFlow<Boolean> val isFabVisible: StateFlow<Boolean>
} }

View File

@ -17,7 +17,7 @@ fun PostCardBody(
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
) { ) {
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val settingsRepository = remember { getSettingsRepository() } val settingsRepository = remember { getSettingsRepository() }
if (text.isNotEmpty()) { if (text.isNotEmpty()) {
@ -31,11 +31,11 @@ fun PostCardBody(
url = url, url = url,
openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser, openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser,
uriHandler = uriHandler, uriHandler = uriHandler,
navigator = navigator navigator = navigationCoordinator.getRootNavigator()
) )
}, },
onOpenImage = { url -> onOpenImage = { url ->
navigator?.push(ZoomableImageScreen(url)) navigationCoordinator.getRootNavigator()?.push(ZoomableImageScreen(url))
}, },
onClick = onClick, onClick = onClick,
) )

View File

@ -17,7 +17,7 @@ fun PostCardTitle(
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
) { ) {
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val settingsRepository = remember { getSettingsRepository() } val settingsRepository = remember { getSettingsRepository() }
CustomMarkdown( CustomMarkdown(
@ -29,11 +29,11 @@ fun PostCardTitle(
url = url, url = url,
openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser, openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser,
uriHandler = uriHandler, uriHandler = uriHandler,
navigator = navigator navigator = navigationCoordinator.getRootNavigator(),
) )
}, },
onOpenImage = { url -> onOpenImage = { url ->
navigator?.push(ZoomableImageScreen(url)) navigationCoordinator.getRootNavigator()?.push(ZoomableImageScreen(url))
}, },
onClick = onClick, onClick = onClick,
) )

View File

@ -30,7 +30,7 @@ fun PostLinkBanner(
url: String, url: String,
) { ) {
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val settingsRepository = remember { getSettingsRepository() } val settingsRepository = remember { getSettingsRepository() }
if (url.isNotEmpty()) { if (url.isNotEmpty()) {
@ -44,7 +44,7 @@ fun PostLinkBanner(
if (settingsRepository.currentSettings.value.openUrlsInExternalBrowser) { if (settingsRepository.currentSettings.value.openUrlsInExternalBrowser) {
uriHandler.openUri(url) uriHandler.openUri(url)
} else { } else {
navigator?.push(WebViewScreen(url)) navigationCoordinator.getRootNavigator()?.push(WebViewScreen(url))
} }
}, },
).padding( ).padding(

View File

@ -1,11 +1,13 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostSection import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostSection
import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.StringDesc
@Stable
interface CreateCommentMviModel : interface CreateCommentMviModel :
MviModel<CreateCommentMviModel.Intent, CreateCommentMviModel.UiState, CreateCommentMviModel.Effect>, MviModel<CreateCommentMviModel.Intent, CreateCommentMviModel.UiState, CreateCommentMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -45,7 +45,6 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
@ -57,6 +56,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Section
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.TextFormattingBar import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.TextFormattingBar
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostSection import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostSection
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreateCommentViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.RawContentDialog import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.RawContentDialog
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
@ -88,7 +88,7 @@ class CreateCommentScreen(
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val genericError = stringResource(MR.strings.message_generic_error) val genericError = stringResource(MR.strings.message_generic_error)
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val galleryHelper = remember { getGalleryHelper() } val galleryHelper = remember { getGalleryHelper() }
var openImagePicker by remember { mutableStateOf(false) } var openImagePicker by remember { mutableStateOf(false) }
@ -109,7 +109,7 @@ class CreateCommentScreen(
CreateCommentMviModel.Effect.Success -> { CreateCommentMviModel.Effect.Success -> {
notificationCenter.getObserver(NotificationCenterContractKeys.CommentCreated) notificationCenter.getObserver(NotificationCenterContractKeys.CommentCreated)
?.also { o -> o.invoke(Unit) } ?.also { o -> o.invoke(Unit) }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} }
is CreateCommentMviModel.Effect.AddImageToText -> { is CreateCommentMviModel.Effect.AddImageToText -> {

View File

@ -1,10 +1,12 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.StringDesc
@Stable
interface CreatePostMviModel : interface CreatePostMviModel :
MviModel<CreatePostMviModel.Intent, CreatePostMviModel.UiState, CreatePostMviModel.Effect>, MviModel<CreatePostMviModel.Intent, CreatePostMviModel.UiState, CreatePostMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -51,7 +51,6 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
@ -60,6 +59,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Progres
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.TextFormattingBar import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.TextFormattingBar
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreatePostViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreatePostViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.getGalleryHelper import com.github.diegoberaldin.raccoonforlemmy.core.utils.getGalleryHelper
@ -89,7 +89,6 @@ class CreatePostScreen(
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val genericError = stringResource(MR.strings.message_generic_error) val genericError = stringResource(MR.strings.message_generic_error)
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val galleryHelper = remember { getGalleryHelper() } val galleryHelper = remember { getGalleryHelper() }
var bodyTextFieldValue by remember { var bodyTextFieldValue by remember {
@ -98,6 +97,7 @@ class CreatePostScreen(
val bodyFocusRequester = remember { FocusRequester() } val bodyFocusRequester = remember { FocusRequester() }
val urlFocusRequester = remember { FocusRequester() } val urlFocusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
val navigationCoordinator = remember { getNavigationCoordinator() }
LaunchedEffect(model) { LaunchedEffect(model) {
model.reduce(CreatePostMviModel.Intent.SetTitle(editedPost?.title.orEmpty())) model.reduce(CreatePostMviModel.Intent.SetTitle(editedPost?.title.orEmpty()))
@ -112,7 +112,7 @@ class CreatePostScreen(
CreatePostMviModel.Effect.Success -> { CreatePostMviModel.Effect.Success -> {
notificationCenter.getObserver(NotificationCenterContractKeys.PostCreated) notificationCenter.getObserver(NotificationCenterContractKeys.PostCreated)
?.also { o -> o.invoke(Unit) } ?.also { o -> o.invoke(Unit) }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} }
is CreatePostMviModel.Effect.AddImageToBody -> { is CreatePostMviModel.Effect.AddImageToBody -> {

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.drawer package com.github.diegoberaldin.raccoonforlemmy.core.commonui.drawer
import androidx.compose.runtime.Stable
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
@ -13,6 +14,7 @@ sealed interface DrawerEvent {
data object OpenBookmarks : DrawerEvent data object OpenBookmarks : DrawerEvent
} }
@Stable
interface DrawerCoordinator { interface DrawerCoordinator {
val gesturesEnabled: StateFlow<Boolean> val gesturesEnabled: StateFlow<Boolean>

View File

@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
@ -179,7 +179,7 @@ object ModalDrawerContent : Tab {
} }
} }
itemsIndexed(uiState.multiCommunities) { _, community -> items(uiState.multiCommunities) { community ->
MultiCommunityItem( MultiCommunityItem(
modifier = Modifier.fillMaxWidth().onClick( modifier = Modifier.fillMaxWidth().onClick(
rememberCallback { rememberCallback {
@ -196,7 +196,7 @@ object ModalDrawerContent : Tab {
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
) )
} }
itemsIndexed(uiState.communities) { _, community -> items(uiState.communities) { community ->
CommunityItem( CommunityItem(
modifier = Modifier.fillMaxWidth().onClick( modifier = Modifier.fillMaxWidth().onClick(
rememberCallback { rememberCallback {

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.drawer package com.github.diegoberaldin.raccoonforlemmy.core.commonui.drawer
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
@ -7,6 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.StringDesc
@Stable
interface ModalDrawerMviModel : interface ModalDrawerMviModel :
MviModel<ModalDrawerMviModel.Intent, ModalDrawerMviModel.UiState, ModalDrawerMviModel.Effect>, MviModel<ModalDrawerMviModel.Intent, ModalDrawerMviModel.UiState, ModalDrawerMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -1,8 +1,10 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.image package com.github.diegoberaldin.raccoonforlemmy.core.commonui.image
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
@Stable
interface ZoomableImageMviModel : interface ZoomableImageMviModel :
MviModel<ZoomableImageMviModel.Intent, ZoomableImageMviModel.UiState, ZoomableImageMviModel.Effect>, MviModel<ZoomableImageMviModel.Intent, ZoomableImageMviModel.UiState, ZoomableImageMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -55,7 +55,7 @@ class ZoomableImageScreen(
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val successMessage = stringResource(MR.strings.message_operation_successful) val successMessage = stringResource(MR.strings.message_operation_successful)
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
LaunchedEffect(model) { LaunchedEffect(model) {
@ -82,7 +82,7 @@ class ZoomableImageScreen(
Icon( Icon(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,

View File

@ -1,9 +1,11 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo package com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
@Stable
interface InstanceInfoMviModel : interface InstanceInfoMviModel :
MviModel<InstanceInfoMviModel.Intent, InstanceInfoMviModel.UiState, InstanceInfoMviModel.Effect>, MviModel<InstanceInfoMviModel.Intent, InstanceInfoMviModel.UiState, InstanceInfoMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -43,6 +43,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Communi
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ScaledContent import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ScaledContent
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getInstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getInstanceInfoViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.resources.MR import com.github.diegoberaldin.raccoonforlemmy.resources.MR
@ -61,9 +62,11 @@ class InstanceInfoScreen(
val model = rememberScreenModel { getInstanceInfoViewModel(url) } val model = rememberScreenModel { getInstanceInfoViewModel(url) }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val instanceName = url.replace("https://", "") val instanceName = url.replace("https://", "")
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
Scaffold( Scaffold(
modifier = Modifier.background(MaterialTheme.colorScheme.background) modifier = Modifier.background(MaterialTheme.colorScheme.background)
@ -75,7 +78,7 @@ class InstanceInfoScreen(
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,
@ -101,7 +104,13 @@ class InstanceInfoScreen(
) )
Box( Box(
modifier = Modifier modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection) .let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.padding(paddingValues) .padding(paddingValues)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
@ -143,7 +152,7 @@ class InstanceInfoScreen(
CommunityItem( CommunityItem(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen( CommunityDetailScreen(
community = it, community = it,
otherInstance = instanceName, otherInstance = instanceName,

View File

@ -28,9 +28,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
@ -43,7 +43,7 @@ class ColorBottomSheet : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
var customPickerDialogOpened by remember { mutableStateOf(false) } var customPickerDialogOpened by remember { mutableStateOf(false) }
val settingsRepository = remember { getSettingsRepository() } val settingsRepository = remember { getSettingsRepository() }
@ -101,7 +101,7 @@ class ColorBottomSheet : Screen {
?.also { ?.also {
it.invoke(value.first ?: Unit) it.invoke(value.first ?: Unit)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} else { } else {
customPickerDialogOpened = true customPickerDialogOpened = true
} }
@ -149,7 +149,7 @@ class ColorBottomSheet : Screen {
?.also { ?.also {
it.invoke(color) it.invoke(color)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} }
) )
} }

View File

@ -14,11 +14,11 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -39,7 +39,7 @@ class FontFamilyBottomSheet(
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier = Modifier
@ -80,7 +80,7 @@ class FontFamilyBottomSheet(
?.also { ?.also {
it.invoke(value) it.invoke(value)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -14,12 +14,12 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.FontScale import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.FontScale
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.scaleFactor import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.scaleFactor
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -41,7 +41,7 @@ class FontScaleBottomSheet(
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier = Modifier
@ -82,7 +82,7 @@ class FontScaleBottomSheet(
?.also { ?.also {
it.invoke(value.scaleFactor) it.invoke(value.scaleFactor)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -14,9 +14,9 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -27,7 +27,7 @@ import dev.icerock.moko.resources.compose.stringResource
class InboxTypeSheet : Screen { class InboxTypeSheet : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
@ -66,7 +66,7 @@ class InboxTypeSheet : Screen {
?.also { ?.also {
it.invoke(true) it.invoke(true)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {
@ -88,7 +88,7 @@ class InboxTypeSheet : Screen {
?.also { ?.also {
it.invoke(false) it.invoke(false)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -14,9 +14,9 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -29,7 +29,7 @@ class LanguageBottomSheet : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier = Modifier
@ -80,7 +80,7 @@ class LanguageBottomSheet : Screen {
?.also { ?.also {
it.invoke(value) it.invoke(value)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -17,9 +17,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -35,8 +35,9 @@ class ListingTypeBottomSheet(
) : Screen { ) : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier = Modifier
.padding( .padding(
@ -81,7 +82,7 @@ class ListingTypeBottomSheet(
NotificationCenterContractKeys.ChangeFeedType NotificationCenterContractKeys.ChangeFeedType
) )
?.invoke(value) ?.invoke(value)
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -14,11 +14,11 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -30,8 +30,9 @@ class PostLayoutBottomSheet : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier.padding( modifier = Modifier.padding(
top = Spacing.s, top = Spacing.s,
@ -71,7 +72,7 @@ class PostLayoutBottomSheet : Screen {
?.also { ?.also {
it.invoke(value) it.invoke(value)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -43,7 +43,7 @@ fun RawContentDialog(
onDismiss: (() -> Unit)? = null, onDismiss: (() -> Unit)? = null,
) { ) {
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val settingsRepository = remember { getSettingsRepository() } val settingsRepository = remember { getSettingsRepository() }
val clipboardManager = LocalClipboardManager.current val clipboardManager = LocalClipboardManager.current
val onSearchLambda = { val onSearchLambda = {
@ -53,7 +53,7 @@ fun RawContentDialog(
url = url, url = url,
openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser, openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser,
uriHandler = uriHandler, uriHandler = uriHandler,
navigator = navigator navigator = navigationCoordinator.getRootNavigator()
) )
} }

View File

@ -24,10 +24,10 @@ import androidx.compose.ui.graphics.ColorFilter
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator 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.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -83,7 +83,7 @@ internal class SortBottomSheetMain(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
@ -118,7 +118,7 @@ internal class SortBottomSheetMain(
?.also { ?.also {
it.invoke(value) it.invoke(value)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} }
}, },
), ),
@ -163,7 +163,7 @@ internal class SortBottomSheetTop(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column { Column {
@ -205,7 +205,7 @@ internal class SortBottomSheetTop(
?.also { ?.also {
it.invoke(value) it.invoke(value)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -17,12 +17,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toIcon import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toIcon
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
@ -34,7 +34,7 @@ class ThemeBottomSheet : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier = Modifier
@ -80,7 +80,7 @@ class ThemeBottomSheet : Screen {
?.also { ?.also {
it.invoke(value) it.invoke(value)
} }
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
}, },
), ),
) { ) {

View File

@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.Tab
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@ -17,6 +18,7 @@ internal class DefaultNavigationCoordinator : NavigationCoordinator {
private var connection: NestedScrollConnection? = null private var connection: NestedScrollConnection? = null
private var navigator: Navigator? = null private var navigator: Navigator? = null
private var bottomNavigator: BottomSheetNavigator? = null
private var currentTab: Tab? = null private var currentTab: Tab? = null
private val scope = CoroutineScope(SupervisorJob()) private val scope = CoroutineScope(SupervisorJob())
private var canGoBackCallback: (() -> Boolean)? = null private var canGoBackCallback: (() -> Boolean)? = null
@ -60,4 +62,12 @@ internal class DefaultNavigationCoordinator : NavigationCoordinator {
override fun setInboxUnread(count: Int) { override fun setInboxUnread(count: Int) {
inboxUnread.value = count inboxUnread.value = count
} }
override fun setBottomNavigator(value: BottomSheetNavigator?) {
bottomNavigator = value
}
override fun getBottomNavigator(): BottomSheetNavigator? {
return bottomNavigator
}
} }

View File

@ -1,11 +1,14 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation package com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation
import androidx.compose.runtime.Stable
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.Tab
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@Stable
interface NavigationCoordinator { interface NavigationCoordinator {
val onDoubleTabSelection: Flow<Tab> val onDoubleTabSelection: Flow<Tab>
@ -29,4 +32,8 @@ interface NavigationCoordinator {
fun getBottomBarScrollConnection(): NestedScrollConnection? fun getBottomBarScrollConnection(): NestedScrollConnection?
fun setInboxUnread(count: Int) fun setInboxUnread(count: Int)
fun setBottomNavigator(value: BottomSheetNavigator?)
fun getBottomNavigator(): BottomSheetNavigator?
} }

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail package com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
@ -7,6 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
@Stable
interface PostDetailMviModel : interface PostDetailMviModel :
MviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect>, MviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -22,7 +22,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -71,7 +71,6 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
@ -97,6 +96,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateRepor
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs
@ -136,21 +136,12 @@ class PostDetailScreen(
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val isOnOtherInstance = otherInstance.isNotEmpty() val isOnOtherInstance = otherInstance.isNotEmpty()
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
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 notificationCenter = remember { getNotificationCenter() }
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
DisposableEffect(key) {
drawerCoordinator.setGesturesEnabled(false)
onDispose {
notificationCenter.removeObserver(key)
drawerCoordinator.setGesturesEnabled(true)
}
}
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()
@ -159,12 +150,91 @@ class PostDetailScreen(
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
var rawContent by remember { mutableStateOf<Any?>(null) } var rawContent by remember { mutableStateOf<Any?>(null) }
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
DisposableEffect(key) {
drawerCoordinator.setGesturesEnabled(false)
onDispose {
notificationCenter.removeObserver(key)
drawerCoordinator.setGesturesEnabled(true)
}
}
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
PostDetailMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
}, key, NotificationCenterContractKeys.CommentCreated
)
notificationCenter.addObserver(
{
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
}, key, NotificationCenterContractKeys.CommentCreated
)
notificationCenter.addObserver(
{
model.reduce(PostDetailMviModel.Intent.RefreshPost)
}, key, NotificationCenterContractKeys.PostCreated
)
notificationCenter.addObserver(
{
model.reduce(
PostDetailMviModel.Intent.Refresh
)
model.reduce(
PostDetailMviModel.Intent.RefreshPost
)
},
key,
NotificationCenterContractKeys.CommentCreated
)
notificationCenter.addObserver(
{
model.reduce(
PostDetailMviModel.Intent.Refresh
)
model.reduce(
PostDetailMviModel.Intent.RefreshPost
)
},
key,
NotificationCenterContractKeys.CommentCreated
)
notificationCenter.addObserver(
{
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
},
key,
NotificationCenterContractKeys.CommentCreated
)
notificationCenter.addObserver(
{
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
},
key,
NotificationCenterContractKeys.CommentCreated
)
}
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { evt -> model.effects.onEach { evt ->
when (evt) { when (evt) {
PostDetailMviModel.Effect.Close -> { PostDetailMviModel.Effect.Close -> {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
} }
is PostDetailMviModel.Effect.ScrollToComment -> { is PostDetailMviModel.Effect.ScrollToComment -> {
@ -183,8 +253,6 @@ class PostDetailScreen(
val statePost = uiState.post val statePost = uiState.post
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection)
.background(MaterialTheme.colorScheme.background) .background(MaterialTheme.colorScheme.background)
.padding(Spacing.xs), .padding(Spacing.xs),
topBar = { topBar = {
@ -211,16 +279,7 @@ class PostDetailScreen(
SortType.Controversial, SortType.Controversial,
), ),
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
PostDetailMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
), ),
imageVector = uiState.sortType.toIcon(), imageVector = uiState.sortType.toIcon(),
@ -229,6 +288,7 @@ class PostDetailScreen(
) )
}, },
navigationIcon = { navigationIcon = {
val navigator = navigationCoordinator.getRootNavigator()
if (navigator?.canPop == true) { if (navigator?.canPop == true) {
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
@ -258,7 +318,7 @@ class PostDetailScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ExpandLess, icon = Icons.Default.ExpandLess,
text = stringResource(MR.strings.action_back_to_top), text = stringResource(MR.strings.action_back_to_top),
onSelected = { onSelected = rememberCallback {
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
topAppBarState.heightOffset = 0f topAppBarState.heightOffset = 0f
@ -270,15 +330,11 @@ class PostDetailScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.Reply, icon = Icons.Default.Reply,
text = stringResource(MR.strings.action_reply), text = stringResource(MR.strings.action_reply),
onSelected = { onSelected = rememberCallback {
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = statePost, originalPost = statePost,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(screen)
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
}, key, NotificationCenterContractKeys.CommentCreated)
bottomSheetNavigator.show(screen)
}, },
) )
} }
@ -295,6 +351,14 @@ class PostDetailScreen(
) )
Box( Box(
modifier = Modifier.padding(padding) modifier = Modifier.padding(padding)
.let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.nestedScroll(fabNestedScrollConnection)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
@ -310,12 +374,12 @@ class PostDetailScreen(
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
blurNsfw = false, blurNsfw = false,
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community = community) CommunityDetailScreen(community = community)
) )
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator = rememberCallbackArgs { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(user = user) UserDetailScreen(user = user)
) )
}, },
@ -350,11 +414,7 @@ class PostDetailScreen(
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = statePost, originalPost = statePost,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(screen)
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
}, key, NotificationCenterContractKeys.CommentCreated)
bottomSheetNavigator.show(screen)
} }
}, },
options = buildList { options = buildList {
@ -371,12 +431,7 @@ class PostDetailScreen(
4 -> model.reduce(PostDetailMviModel.Intent.DeletePost) 4 -> model.reduce(PostDetailMviModel.Intent.DeletePost)
3 -> { 3 -> {
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()?.show(
{
model.reduce(PostDetailMviModel.Intent.RefreshPost)
}, key, NotificationCenterContractKeys.PostCreated
)
bottomSheetNavigator.show(
CreatePostScreen( CreatePostScreen(
editedPost = statePost, editedPost = statePost,
) )
@ -384,7 +439,9 @@ class PostDetailScreen(
} }
2 -> { 2 -> {
bottomSheetNavigator.show(CreateReportScreen(postId = statePost.id)) navigationCoordinator.getBottomNavigator()?.show(
CreateReportScreen(postId = statePost.id)
)
} }
1 -> { 1 -> {
@ -395,7 +452,7 @@ class PostDetailScreen(
} }
}, },
onImageClick = rememberCallbackArgs { url -> onImageClick = rememberCallbackArgs { url ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url), ZoomableImageScreen(url),
) )
}, },
@ -441,7 +498,8 @@ class PostDetailScreen(
id = crossPost.id, id = crossPost.id,
community = community, community = community,
) )
navigator?.push( navigationCoordinator.getRootNavigator()
?.push(
PostDetailScreen( PostDetailScreen(
post = post, post = post,
) )
@ -465,7 +523,7 @@ class PostDetailScreen(
) )
} }
} }
itemsIndexed(uiState.comments, key = { _, c -> c.id }) { _, comment -> items(uiState.comments, key = { c -> c.id }) { comment ->
val commentId = comment.id val commentId = comment.id
AnimatedVisibility( AnimatedVisibility(
visible = comment.visible, visible = comment.visible,
@ -586,25 +644,17 @@ class PostDetailScreen(
originalPost = statePost, originalPost = statePost,
originalComment = comment, originalComment = comment,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(
model.reduce( screen
PostDetailMviModel.Intent.Refresh
) )
model.reduce(
PostDetailMviModel.Intent.RefreshPost
)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
} }
}, },
onOpenCreator = rememberCallbackArgs { onOpenCreator = rememberCallbackArgs {
val user = comment.creator val user = comment.creator
if (user != null) { if (user != null) {
navigator?.push( navigationCoordinator.getRootNavigator()
?.push(
UserDetailScreen( UserDetailScreen(
user = user, user = user,
otherInstance = otherInstance, otherInstance = otherInstance,
@ -615,7 +665,8 @@ class PostDetailScreen(
onOpenCommunity = rememberCallbackArgs { onOpenCommunity = rememberCallbackArgs {
val community = comment.community val community = comment.community
if (community != null) { if (community != null) {
navigator?.push( navigationCoordinator.getRootNavigator()
?.push(
CommunityDetailScreen( CommunityDetailScreen(
community = community, community = community,
otherInstance = otherInstance, otherInstance = otherInstance,
@ -642,19 +693,8 @@ class PostDetailScreen(
) )
2 -> { 2 -> {
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(
model.reduce(
PostDetailMviModel.Intent.Refresh
)
model.reduce(
PostDetailMviModel.Intent.RefreshPost
)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(
CreateCommentScreen( CreateCommentScreen(
editedComment = comment, editedComment = comment,
) )
@ -662,7 +702,8 @@ class PostDetailScreen(
} }
1 -> { 1 -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()
?.show(
CreateReportScreen( CreateReportScreen(
commentId = comment.id commentId = comment.id
) )
@ -723,21 +764,15 @@ class PostDetailScreen(
originalPost = statePost, originalPost = statePost,
originalComment = comment, originalComment = comment,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(screen)
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
} }
}, },
onOpenCreator = rememberCallbackArgs { onOpenCreator = rememberCallbackArgs {
val user = comment.creator val user = comment.creator
if (user != null) { if (user != null) {
navigator?.push( navigationCoordinator.getRootNavigator()
?.push(
UserDetailScreen( UserDetailScreen(
user = user, user = user,
otherInstance = otherInstance, otherInstance = otherInstance,
@ -762,15 +797,8 @@ class PostDetailScreen(
) )
2 -> { 2 -> {
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(
model.reduce(PostDetailMviModel.Intent.Refresh)
model.reduce(PostDetailMviModel.Intent.RefreshPost)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(
CreateCommentScreen( CreateCommentScreen(
editedComment = comment, editedComment = comment,
) )
@ -778,7 +806,8 @@ class PostDetailScreen(
} }
1 -> { 1 -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()
?.show(
CreateReportScreen( CreateReportScreen(
commentId = comment.id commentId = comment.id
) )

View File

@ -37,19 +37,21 @@ class PostDetailViewModel(
private val shareHelper: ShareHelper, private val shareHelper: ShareHelper,
private val notificationCenter: NotificationCenter, private val notificationCenter: NotificationCenter,
private val hapticFeedback: HapticFeedback, private val hapticFeedback: HapticFeedback,
) : MviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect> by mvi, ) : PostDetailMviModel,
PostDetailMviModel { MviModel<PostDetailMviModel.Intent, PostDetailMviModel.UiState, PostDetailMviModel.Effect> by mvi {
private var currentPage: Int = 1 private var currentPage: Int = 1
private var highlightCommentPath: String? = null private var highlightCommentPath: String? = null
private var commentWasHighlighted = false private var commentWasHighlighted = false
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
(it as? PostModel)?.also { post -> (it as? PostModel)?.also { post ->
handlePostUpdate(post) handlePostUpdate(post)
} }
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated
)
} }
fun finalize() { fun finalize() {

View File

@ -1,9 +1,11 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.report package com.github.diegoberaldin.raccoonforlemmy.core.commonui.report
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import dev.icerock.moko.resources.desc.StringDesc import dev.icerock.moko.resources.desc.StringDesc
@Stable
interface CreateReportMviModel : interface CreateReportMviModel :
MviModel<CreateReportMviModel.Intent, CreateReportMviModel.UiState, CreateReportMviModel.Effect>, MviModel<CreateReportMviModel.Intent, CreateReportMviModel.UiState, CreateReportMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -34,13 +34,12 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreateReportViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreateReportViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.resources.MR import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.localized import dev.icerock.moko.resources.compose.localized
import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.compose.stringResource
@ -64,8 +63,7 @@ class CreateReportScreen(
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val genericError = stringResource(MR.strings.message_generic_error) val genericError = stringResource(MR.strings.message_generic_error)
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() }
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { model.effects.onEach {
@ -75,7 +73,7 @@ class CreateReportScreen(
} }
CreateReportMviModel.Effect.Success -> { CreateReportMviModel.Effect.Success -> {
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} }
} }
}.launchIn(this) }.launchIn(this)

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems package com.github.diegoberaldin.raccoonforlemmy.core.commonui.saveditems
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
@ -8,6 +9,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
@Stable
interface SavedItemsMviModel : interface SavedItemsMviModel :
MviModel<SavedItemsMviModel.Intent, SavedItemsMviModel.UiState, SavedItemsMviModel.Effect>, MviModel<SavedItemsMviModel.Intent, SavedItemsMviModel.UiState, SavedItemsMviModel.Effect>,
ScreenModel { ScreenModel {
@ -17,13 +19,13 @@ interface SavedItemsMviModel :
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class ChangeSort(val value: SortType) : Intent data class ChangeSort(val value: SortType) : Intent
data class ChangeSection(val section: SavedItemsSection) : Intent data class ChangeSection(val section: SavedItemsSection) : Intent
data class UpVotePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class DownVotePost(val index: Int, val feedback: Boolean = false) : Intent data class DownVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class SavePost(val id: Int, val feedback: Boolean = false) : Intent
data class SharePost(val index: Int) : Intent data class SharePost(val id: Int) : Intent
data class UpVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class UpVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class DownVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class DownVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class SaveComment(val index: Int, val feedback: Boolean = false) : Intent data class SaveComment(val id: Int, val feedback: Boolean = false) : Intent
} }
data class UiState( data class UiState(

View File

@ -13,7 +13,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -33,6 +33,7 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
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
@ -47,7 +48,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
@ -70,6 +70,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateRepor
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
@ -88,8 +89,7 @@ class SavedItemsScreen : Screen {
val model = rememberScreenModel { getSavedItemsViewModel() } val model = rememberScreenModel { getSavedItemsViewModel() }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigatorCoordinator = remember { getNavigationCoordinator() }
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
@ -99,18 +99,31 @@ class SavedItemsScreen : Screen {
val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState() val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState()
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
var rawContent by remember { mutableStateOf<Any?>(null) } var rawContent by remember { mutableStateOf<Any?>(null) }
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
DisposableEffect(key) { DisposableEffect(key) {
notificationCenter.removeObserver(key)
drawerCoordinator.setGesturesEnabled(false) drawerCoordinator.setGesturesEnabled(false)
onDispose { onDispose {
drawerCoordinator.setGesturesEnabled(true) drawerCoordinator.setGesturesEnabled(true)
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
SavedItemsMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
}
Scaffold( Scaffold(
modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection),
topBar = { topBar = {
TopAppBar( TopAppBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
@ -131,16 +144,7 @@ class SavedItemsScreen : Screen {
SortType.Old, SortType.Old,
), ),
) )
notificationCenter.addObserver({ navigatorCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
SavedItemsMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
), ),
imageVector = uiState.sortType.toIcon(), imageVector = uiState.sortType.toIcon(),
@ -152,7 +156,7 @@ class SavedItemsScreen : Screen {
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigatorCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,
@ -177,7 +181,7 @@ class SavedItemsScreen : Screen {
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ExpandLess, icon = Icons.Default.ExpandLess,
text = stringResource(MR.strings.action_back_to_top), text = stringResource(MR.strings.action_back_to_top),
onSelected = { onSelected = rememberCallback {
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
topAppBarState.heightOffset = 0f topAppBarState.heightOffset = 0f
@ -191,7 +195,15 @@ class SavedItemsScreen : Screen {
}, },
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier.padding(paddingValues), modifier = Modifier.padding(paddingValues)
.let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.nestedScroll(fabNestedScrollConnection),
verticalArrangement = Arrangement.spacedBy(Spacing.s), verticalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
SectionSelector( SectionSelector(
@ -227,7 +239,7 @@ class SavedItemsScreen : Screen {
modifier = Modifier.padding(horizontal = Spacing.xxxs), modifier = Modifier.padding(horizontal = Spacing.xxxs),
) { ) {
if (uiState.section == SavedItemsSection.Posts) { if (uiState.section == SavedItemsSection.Posts) {
itemsIndexed(uiState.posts) { idx, post -> items(uiState.posts) { post ->
PostCard( PostCard(
post = post, post = post,
postLayout = uiState.postLayout, postLayout = uiState.postLayout,
@ -236,24 +248,25 @@ class SavedItemsScreen : Screen {
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
blurNsfw = uiState.blurNsfw, blurNsfw = uiState.blurNsfw,
onClick = { onClick = {
navigator?.push( navigatorCoordinator.getRootNavigator()?.push(
PostDetailScreen(post), PostDetailScreen(post),
) )
}, },
onOpenCommunity = { community -> onOpenCommunity = { community ->
navigator?.push( navigatorCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },
onOpenCreator = { u -> onOpenCreator = { u ->
if (u.id != uiState.user?.id) { if (u.id != uiState.user?.id) {
navigator?.push(UserDetailScreen(u)) navigatorCoordinator.getRootNavigator()
?.push(UserDetailScreen(u))
} }
}, },
onUpVote = { onUpVote = {
model.reduce( model.reduce(
SavedItemsMviModel.Intent.UpVotePost( SavedItemsMviModel.Intent.UpVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -261,7 +274,7 @@ class SavedItemsScreen : Screen {
onDownVote = { onDownVote = {
model.reduce( model.reduce(
SavedItemsMviModel.Intent.DownVotePost( SavedItemsMviModel.Intent.DownVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -269,7 +282,7 @@ class SavedItemsScreen : Screen {
onSave = { onSave = {
model.reduce( model.reduce(
SavedItemsMviModel.Intent.SavePost( SavedItemsMviModel.Intent.SavePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -278,10 +291,10 @@ class SavedItemsScreen : Screen {
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = post, originalPost = post,
) )
bottomSheetNavigator.show(screen) navigatorCoordinator.getBottomNavigator()?.show(screen)
}, },
onImageClick = { url -> onImageClick = { url ->
navigator?.push( navigatorCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url), ZoomableImageScreen(url),
) )
}, },
@ -293,7 +306,7 @@ class SavedItemsScreen : Screen {
onOptionSelected = { optionIndex -> onOptionSelected = { optionIndex ->
when (optionIndex) { when (optionIndex) {
2 -> { 2 -> {
bottomSheetNavigator.show( navigatorCoordinator.getBottomNavigator()?.show(
CreateReportScreen( CreateReportScreen(
postId = post.id postId = post.id
) )
@ -305,7 +318,11 @@ class SavedItemsScreen : Screen {
} }
else -> { else -> {
model.reduce(SavedItemsMviModel.Intent.SharePost(idx)) model.reduce(
SavedItemsMviModel.Intent.SharePost(
post.id
)
)
} }
} }
}, },
@ -330,14 +347,14 @@ class SavedItemsScreen : Screen {
} }
} }
} else { } else {
itemsIndexed(uiState.comments) { idx, comment -> items(uiState.comments) { comment ->
CommentCard( CommentCard(
comment = comment, comment = comment,
separateUpAndDownVotes = uiState.separateUpAndDownVotes, separateUpAndDownVotes = uiState.separateUpAndDownVotes,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
hideIndent = true, hideIndent = true,
onClick = { onClick = {
navigator?.push( navigatorCoordinator.getRootNavigator()?.push(
PostDetailScreen( PostDetailScreen(
post = PostModel(id = comment.postId), post = PostModel(id = comment.postId),
highlightCommentId = comment.id, highlightCommentId = comment.id,
@ -347,7 +364,7 @@ class SavedItemsScreen : Screen {
onUpVote = { onUpVote = {
model.reduce( model.reduce(
SavedItemsMviModel.Intent.UpVoteComment( SavedItemsMviModel.Intent.UpVoteComment(
index = idx, id = comment.id,
feedback = true, feedback = true,
), ),
) )
@ -355,7 +372,7 @@ class SavedItemsScreen : Screen {
onDownVote = { onDownVote = {
model.reduce( model.reduce(
SavedItemsMviModel.Intent.DownVoteComment( SavedItemsMviModel.Intent.DownVoteComment(
index = idx, id = comment.id,
feedback = true, feedback = true,
), ),
) )
@ -363,7 +380,7 @@ class SavedItemsScreen : Screen {
onSave = { onSave = {
model.reduce( model.reduce(
SavedItemsMviModel.Intent.SaveComment( SavedItemsMviModel.Intent.SaveComment(
index = idx, id = comment.id,
feedback = true, feedback = true,
), ),
) )
@ -373,7 +390,7 @@ class SavedItemsScreen : Screen {
originalPost = PostModel(id = comment.postId), originalPost = PostModel(id = comment.postId),
originalComment = comment, originalComment = comment,
) )
bottomSheetNavigator.show(screen) navigatorCoordinator.getBottomNavigator()?.show(screen)
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(stringResource(MR.strings.post_action_see_raw))
@ -382,7 +399,7 @@ class SavedItemsScreen : Screen {
onOptionSelected = { optionIndex -> onOptionSelected = { optionIndex ->
when (optionIndex) { when (optionIndex) {
1 -> { 1 -> {
bottomSheetNavigator.show( navigatorCoordinator.getBottomNavigator()?.show(
CreateReportScreen( CreateReportScreen(
commentId = comment.id commentId = comment.id
) )

View File

@ -41,11 +41,13 @@ class SavedItemsViewModel(
private var currentPage: Int = 1 private var currentPage: Int = 1
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
(it as? PostModel)?.also { post -> (it as? PostModel)?.also { post ->
handlePostUpdate(post) handlePostUpdate(post)
} }
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated
)
} }
fun finalize() { fun finalize() {
@ -80,37 +82,39 @@ class SavedItemsViewModel(
SavedItemsMviModel.Intent.Refresh -> refresh() SavedItemsMviModel.Intent.Refresh -> refresh()
is SavedItemsMviModel.Intent.ChangeSection -> changeSection(intent.section) is SavedItemsMviModel.Intent.ChangeSection -> changeSection(intent.section)
is SavedItemsMviModel.Intent.DownVoteComment -> toggleDownVoteComment( is SavedItemsMviModel.Intent.DownVoteComment -> toggleDownVoteComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is SavedItemsMviModel.Intent.DownVotePost -> toggleDownVotePost( is SavedItemsMviModel.Intent.DownVotePost -> toggleDownVotePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is SavedItemsMviModel.Intent.SaveComment -> toggleSaveComment( is SavedItemsMviModel.Intent.SaveComment -> toggleSaveComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is SavedItemsMviModel.Intent.SavePost -> toggleSavePost( is SavedItemsMviModel.Intent.SavePost -> toggleSavePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is SavedItemsMviModel.Intent.UpVoteComment -> toggleUpVoteComment( is SavedItemsMviModel.Intent.UpVoteComment -> toggleUpVoteComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is SavedItemsMviModel.Intent.UpVotePost -> toggleUpVotePost( is SavedItemsMviModel.Intent.UpVotePost -> toggleUpVotePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is SavedItemsMviModel.Intent.ChangeSort -> applySortType(intent.value) is SavedItemsMviModel.Intent.ChangeSort -> applySortType(intent.value)
is SavedItemsMviModel.Intent.SharePost -> share(post = uiState.value.posts[intent.index]) is SavedItemsMviModel.Intent.SharePost -> share(
post = uiState.value.posts.first { it.id == intent.id }
)
} }
} }

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail package com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
@ -8,6 +9,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
@Stable
interface UserDetailMviModel : interface UserDetailMviModel :
MviModel<UserDetailMviModel.Intent, UserDetailMviModel.UiState, UserDetailMviModel.Effect>, MviModel<UserDetailMviModel.Intent, UserDetailMviModel.UiState, UserDetailMviModel.Effect>,
ScreenModel { ScreenModel {
@ -17,14 +19,14 @@ interface UserDetailMviModel :
data object Refresh : Intent data object Refresh : Intent
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class ChangeSection(val section: UserDetailSection) : Intent data class ChangeSection(val section: UserDetailSection) : Intent
data class UpVotePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class DownVotePost(val index: Int, val feedback: Boolean = false) : Intent data class DownVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class SavePost(val id: Int, val feedback: Boolean = false) : Intent
data class UpVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class UpVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class DownVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class DownVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class SaveComment(val index: Int, val feedback: Boolean = false) : Intent data class SaveComment(val id: Int, val feedback: Boolean = false) : Intent
data object HapticIndication : Intent data object HapticIndication : Intent
data class SharePost(val index: Int) : Intent data class SharePost(val id: Int) : Intent
data object Block : Intent data object Block : Intent
data object BlockInstance : Intent data object BlockInstance : Intent
} }

View File

@ -14,7 +14,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -59,7 +59,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
@ -88,6 +87,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.report.CreateReportScreen
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs
@ -121,8 +121,6 @@ class UserDetailScreen(
val genericError = stringResource(MR.strings.message_generic_error) val genericError = stringResource(MR.strings.message_generic_error)
val successMessage = stringResource(MR.strings.message_operation_successful) val successMessage = stringResource(MR.strings.message_operation_successful)
val isOnOtherInstance = otherInstance.isNotEmpty() val isOnOtherInstance = otherInstance.isNotEmpty()
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
@ -133,8 +131,11 @@ class UserDetailScreen(
val downvoteColor by themeRepository.downvoteColor.collectAsState() val downvoteColor by themeRepository.downvoteColor.collectAsState()
val defaultUpvoteColor = MaterialTheme.colorScheme.primary val defaultUpvoteColor = MaterialTheme.colorScheme.primary
val defaultDownVoteColor = MaterialTheme.colorScheme.tertiary val defaultDownVoteColor = MaterialTheme.colorScheme.tertiary
val navigationCoordinator = remember { getNavigationCoordinator() }
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
var rawContent by remember { mutableStateOf<Any?>(null) } var rawContent by remember { mutableStateOf<Any?>(null) }
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
DisposableEffect(key) { DisposableEffect(key) {
drawerCoordinator.setGesturesEnabled(false) drawerCoordinator.setGesturesEnabled(false)
@ -143,6 +144,33 @@ class UserDetailScreen(
drawerCoordinator.setGesturesEnabled(true) drawerCoordinator.setGesturesEnabled(true)
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
UserDetailMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
model.reduce(UserDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
notificationCenter.addObserver(
{
model.reduce(UserDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
}
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { model.effects.onEach {
when (it) { when (it) {
@ -166,8 +194,6 @@ class UserDetailScreen(
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colorScheme.background) .background(MaterialTheme.colorScheme.background)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection)
.padding(Spacing.xs), .padding(Spacing.xs),
topBar = { topBar = {
val userName = user.name val userName = user.name
@ -194,16 +220,7 @@ class UserDetailScreen(
val sheet = SortBottomSheet( val sheet = SortBottomSheet(
expandTop = true, expandTop = true,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
UserDetailMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
), ),
imageVector = uiState.sortType.toIcon(), imageVector = uiState.sortType.toIcon(),
@ -212,6 +229,7 @@ class UserDetailScreen(
) )
}, },
navigationIcon = { navigationIcon = {
val navigator = navigationCoordinator.getRootNavigator()
if (navigator?.canPop == true) { if (navigator?.canPop == true) {
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
@ -242,7 +260,7 @@ class UserDetailScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ExpandLess, icon = Icons.Default.ExpandLess,
text = stringResource(MR.strings.action_back_to_top), text = stringResource(MR.strings.action_back_to_top),
onSelected = { onSelected = rememberCallback {
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
topAppBarState.heightOffset = 0f topAppBarState.heightOffset = 0f
@ -254,9 +272,9 @@ class UserDetailScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.Chat, icon = Icons.Default.Chat,
text = stringResource(MR.strings.action_chat), text = stringResource(MR.strings.action_chat),
onSelected = { onSelected = rememberCallback {
val screen = InboxChatScreen(otherUserId = user.id) val screen = InboxChatScreen(otherUserId = user.id)
navigator?.push(screen) navigationCoordinator.getRootNavigator()?.push(screen)
}, },
) )
} }
@ -277,6 +295,14 @@ class UserDetailScreen(
Box( Box(
modifier = Modifier modifier = Modifier
.padding(padding) .padding(padding)
.let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.nestedScroll(fabNestedScrollConnection)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
@ -295,7 +321,8 @@ class UserDetailScreen(
stringResource(MR.strings.community_detail_block_instance), stringResource(MR.strings.community_detail_block_instance),
), ),
onOpenImage = rememberCallbackArgs { url -> onOpenImage = rememberCallbackArgs { url ->
navigator?.push(ZoomableImageScreen(url)) navigationCoordinator.getRootNavigator()
?.push(ZoomableImageScreen(url))
}, },
onOptionSelected = rememberCallbackArgs { optionIdx -> onOptionSelected = rememberCallbackArgs { optionIdx ->
when (optionIdx) { when (optionIdx) {
@ -337,7 +364,7 @@ class UserDetailScreen(
} }
} }
} }
itemsIndexed(uiState.posts) { idx, post -> items(uiState.posts) { post ->
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled, enabled = uiState.swipeActionsEnabled,
@ -377,12 +404,12 @@ class UserDetailScreen(
}, },
onDismissToStart = rememberCallback(model) { onDismissToStart = rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVotePost(idx), UserDetailMviModel.Intent.UpVotePost(post.id),
) )
}, },
onDismissToEnd = rememberCallback(model) { onDismissToEnd = rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVotePost(idx), UserDetailMviModel.Intent.DownVotePost(post.id),
) )
}, },
content = { content = {
@ -395,7 +422,8 @@ class UserDetailScreen(
separateUpAndDownVotes = uiState.separateUpAndDownVotes, separateUpAndDownVotes = uiState.separateUpAndDownVotes,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
onClick = rememberCallback { onClick = rememberCallback {
navigator?.push(PostDetailScreen(post = post)) navigationCoordinator.getRootNavigator()
?.push(PostDetailScreen(post = post))
}, },
onUpVote = if (isOnOtherInstance) { onUpVote = if (isOnOtherInstance) {
null null
@ -403,7 +431,7 @@ class UserDetailScreen(
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVotePost( UserDetailMviModel.Intent.UpVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -415,7 +443,7 @@ class UserDetailScreen(
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVotePost( UserDetailMviModel.Intent.DownVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -427,14 +455,15 @@ class UserDetailScreen(
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.SavePost( UserDetailMviModel.Intent.SavePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
} }
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push(CommunityDetailScreen(community)) navigationCoordinator.getRootNavigator()
?.push(CommunityDetailScreen(community))
}, },
onReply = if (isOnOtherInstance) { onReply = if (isOnOtherInstance) {
null null
@ -443,18 +472,12 @@ class UserDetailScreen(
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = post, originalPost = post,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(screen)
model.reduce(UserDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
} }
}, },
onImageClick = rememberCallbackArgs { url -> onImageClick = rememberCallbackArgs { url ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url), ZoomableImageScreen(url),
) )
}, },
@ -466,7 +489,8 @@ class UserDetailScreen(
onOptionSelected = rememberCallbackArgs { optionIdx -> onOptionSelected = rememberCallbackArgs { optionIdx ->
when (optionIdx) { when (optionIdx) {
2 -> { 2 -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()
?.show(
CreateReportScreen( CreateReportScreen(
postId = post.id postId = post.id
) )
@ -478,7 +502,7 @@ class UserDetailScreen(
} }
else -> model.reduce( else -> model.reduce(
UserDetailMviModel.Intent.SharePost(idx) UserDetailMviModel.Intent.SharePost(post.id)
) )
} }
}) })
@ -512,7 +536,7 @@ class UserDetailScreen(
) )
} }
} }
itemsIndexed(uiState.comments) { idx, comment -> items(uiState.comments) { comment ->
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled, enabled = uiState.swipeActionsEnabled,
@ -551,12 +575,12 @@ class UserDetailScreen(
}, },
onDismissToStart = rememberCallback(model) { onDismissToStart = rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVoteComment(idx), UserDetailMviModel.Intent.UpVoteComment(comment.id),
) )
}, },
onDismissToEnd = rememberCallback(model) { onDismissToEnd = rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVoteComment(idx), UserDetailMviModel.Intent.DownVoteComment(comment.id),
) )
}, },
content = { content = {
@ -569,7 +593,7 @@ class UserDetailScreen(
hideAuthor = true, hideAuthor = true,
hideIndent = true, hideIndent = true,
onClick = rememberCallback { onClick = rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen( PostDetailScreen(
post = PostModel(id = comment.postId), post = PostModel(id = comment.postId),
highlightCommentId = comment.id, highlightCommentId = comment.id,
@ -582,7 +606,7 @@ class UserDetailScreen(
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.SaveComment( UserDetailMviModel.Intent.SaveComment(
index = idx, id = comment.id,
feedback = true, feedback = true,
), ),
) )
@ -594,7 +618,7 @@ class UserDetailScreen(
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVoteComment( UserDetailMviModel.Intent.UpVoteComment(
index = idx, id = comment.id,
feedback = true, feedback = true,
), ),
) )
@ -606,7 +630,7 @@ class UserDetailScreen(
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVoteComment( UserDetailMviModel.Intent.DownVoteComment(
index = idx, id = comment.id,
feedback = true, feedback = true,
), ),
) )
@ -620,18 +644,13 @@ class UserDetailScreen(
originalPost = PostModel(id = comment.postId), originalPost = PostModel(id = comment.postId),
originalComment = comment, originalComment = comment,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(screen)
model.reduce(UserDetailMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
} }
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push(CommunityDetailScreen(community)) navigationCoordinator.getRootNavigator()
?.push(CommunityDetailScreen(community))
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_see_raw)) add(stringResource(MR.strings.post_action_see_raw))
@ -640,7 +659,8 @@ class UserDetailScreen(
onOptionSelected = rememberCallbackArgs { optionId -> onOptionSelected = rememberCallbackArgs { optionId ->
when (optionId) { when (optionId) {
1 -> { 1 -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()
?.show(
CreateReportScreen( CreateReportScreen(
commentId = comment.id commentId = comment.id
) )

View File

@ -45,11 +45,13 @@ class UserDetailViewModel(
private var currentPage = 1 private var currentPage = 1
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
(it as? PostModel)?.also { post -> (it as? PostModel)?.also { post ->
handlePostUpdate(post) handlePostUpdate(post)
} }
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated
)
} }
fun finalize() { fun finalize() {
@ -92,13 +94,13 @@ class UserDetailViewModel(
is UserDetailMviModel.Intent.ChangeSort -> applySortType(intent.value) is UserDetailMviModel.Intent.ChangeSort -> applySortType(intent.value)
is UserDetailMviModel.Intent.ChangeSection -> changeSection(intent.section) is UserDetailMviModel.Intent.ChangeSection -> changeSection(intent.section)
is UserDetailMviModel.Intent.DownVoteComment -> toggleDownVoteComment( is UserDetailMviModel.Intent.DownVoteComment -> toggleDownVoteComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is UserDetailMviModel.Intent.DownVotePost -> { is UserDetailMviModel.Intent.DownVotePost -> {
toggleDownVote( toggleDownVote(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
} }
@ -107,27 +109,27 @@ class UserDetailViewModel(
UserDetailMviModel.Intent.LoadNextPage -> loadNextPage() UserDetailMviModel.Intent.LoadNextPage -> loadNextPage()
UserDetailMviModel.Intent.Refresh -> refresh() UserDetailMviModel.Intent.Refresh -> refresh()
is UserDetailMviModel.Intent.SaveComment -> toggleSaveComment( is UserDetailMviModel.Intent.SaveComment -> toggleSaveComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is UserDetailMviModel.Intent.SavePost -> toggleSave( is UserDetailMviModel.Intent.SavePost -> toggleSave(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is UserDetailMviModel.Intent.UpVoteComment -> toggleUpVoteComment( is UserDetailMviModel.Intent.UpVoteComment -> toggleUpVoteComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is UserDetailMviModel.Intent.UpVotePost -> toggleUpVote( is UserDetailMviModel.Intent.UpVotePost -> toggleUpVote(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is UserDetailMviModel.Intent.SharePost -> share( is UserDetailMviModel.Intent.SharePost -> share(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
) )
UserDetailMviModel.Intent.Block -> blockUser() UserDetailMviModel.Intent.Block -> blockUser()

View File

@ -33,7 +33,7 @@ class WebViewScreen(
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
var shareHelper = remember { getShareHelper() } var shareHelper = remember { getShareHelper() }
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
@ -54,7 +54,7 @@ class WebViewScreen(
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,

View File

@ -1,10 +1,12 @@
package com.github.diegoberaldin.raccoonforlemmy.core.notifications package com.github.diegoberaldin.raccoonforlemmy.core.notifications
import androidx.compose.runtime.Stable
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
/** /**
* Utility to publish and subscribe for broadcast notifications. * Utility to publish and subscribe for broadcast notifications.
*/ */
@Stable
interface NotificationCenter { interface NotificationCenter {
/** /**

View File

@ -1,5 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist package com.github.diegoberaldin.raccoonforlemmy.feature.home.postlist
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
@ -7,6 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
@Stable
interface PostListMviModel : interface PostListMviModel :
MviModel<PostListMviModel.Intent, PostListMviModel.UiState, PostListMviModel.Effect>, MviModel<PostListMviModel.Intent, PostListMviModel.UiState, PostListMviModel.Effect>,
ScreenModel { ScreenModel {
@ -16,15 +18,15 @@ interface PostListMviModel :
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class ChangeSort(val value: SortType) : Intent data class ChangeSort(val value: SortType) : Intent
data class ChangeListing(val value: ListingType) : Intent data class ChangeListing(val value: ListingType) : Intent
data class UpVotePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class DownVotePost(val index: Int, val feedback: Boolean = false) : Intent data class DownVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class SavePost(val id: Int, val feedback: Boolean = false) : Intent
data class HandlePostUpdate(val post: PostModel) : Intent data class HandlePostUpdate(val post: PostModel) : Intent
data object HapticIndication : Intent data object HapticIndication : Intent
data class DeletePost(val id: Int) : Intent data class DeletePost(val id: Int) : Intent
data class SharePost(val index: Int) : Intent data class SharePost(val id: Int) : Intent
data class MarkAsRead(val index: Int) : Intent data class MarkAsRead(val id: Int) : Intent
data class Hide(val index: Int) : Intent data class Hide(val id: Int) : Intent
data object ClearRead : Intent data object ClearRead : Intent
} }

View File

@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -49,7 +49,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Dimensions import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Dimensions
@ -61,7 +60,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Floatin
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardPlaceholder
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getFabNestedScrollConnection import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getFabNestedScrollConnection
@ -97,13 +95,11 @@ class PostListScreen : Screen {
val model = rememberScreenModel { getHomeScreenModel() } val model = rememberScreenModel { getHomeScreenModel() }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
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 navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
val upvoteColor by themeRepository.upvoteColor.collectAsState() val upvoteColor by themeRepository.upvoteColor.collectAsState()
@ -122,7 +118,7 @@ class PostListScreen : Screen {
notificationCenter.removeObserver(key) notificationCenter.removeObserver(key)
} }
} }
LaunchedEffect(navigator) { LaunchedEffect(Unit) {
navigationCoordinator.onDoubleTabSelection.onEach { tab -> navigationCoordinator.onDoubleTabSelection.onEach { tab ->
if (tab == HomeTab) { if (tab == HomeTab) {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
@ -140,20 +136,41 @@ class PostListScreen : Screen {
} }
}.launchIn(this) }.launchIn(this)
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{ result ->
(result as? ListingType)?.also {
model.reduce(PostListMviModel.Intent.ChangeListing(it))
}
}, key, NotificationCenterContractKeys.ChangeFeedType
)
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
PostListMviModel.Intent.ChangeSort(sortType)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
model.reduce(PostListMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
notificationCenter.addObserver(
{
model.reduce(PostListMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.PostCreated
)
}
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier.padding(Spacing.xxs),
.padding(Spacing.xxs)
.let {
val connection = navigationCoordinator.getBottomBarScrollConnection()
if (connection != null && settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(connection)
} else {
it
}
}
.nestedScroll(fabNestedScrollConnection)
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
PostsTopBar( PostsTopBar(
currentInstance = uiState.instance, currentInstance = uiState.instance,
@ -169,25 +186,13 @@ class PostListScreen : Screen {
val sheet = ListingTypeBottomSheet( val sheet = ListingTypeBottomSheet(
isLogged = uiState.isLogged, isLogged = uiState.isLogged,
) )
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? ListingType)?.also {
model.reduce(PostListMviModel.Intent.ChangeListing(it))
}
}, key, NotificationCenterContractKeys.ChangeFeedType)
bottomSheetNavigator.show(sheet)
}, },
onSelectSortType = rememberCallback { onSelectSortType = rememberCallback {
val sheet = SortBottomSheet( val sheet = SortBottomSheet(
expandTop = true, expandTop = true,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
PostListMviModel.Intent.ChangeSort(sortType)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
) )
}, },
@ -207,7 +212,7 @@ class PostListScreen : Screen {
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ExpandLess, icon = Icons.Default.ExpandLess,
text = stringResource(MR.strings.action_back_to_top), text = stringResource(MR.strings.action_back_to_top),
onSelected = { onSelected = rememberCallback {
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
topAppBarState.heightOffset = 0f topAppBarState.heightOffset = 0f
@ -218,7 +223,7 @@ class PostListScreen : Screen {
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ClearAll, icon = Icons.Default.ClearAll,
text = stringResource(MR.strings.action_clear_read), text = stringResource(MR.strings.action_clear_read),
onSelected = { onSelected = rememberCallback {
model.reduce(PostListMviModel.Intent.ClearRead) model.reduce(PostListMviModel.Intent.ClearRead)
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
@ -241,6 +246,22 @@ class PostListScreen : Screen {
modifier = Modifier modifier = Modifier
.padding(padding) .padding(padding)
.fillMaxWidth() .fillMaxWidth()
.let {
val connection = navigationCoordinator.getBottomBarScrollConnection()
if (connection != null && settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(connection)
} else {
it
}
}
.let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.nestedScroll(fabNestedScrollConnection)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
@ -258,7 +279,7 @@ class PostListScreen : Screen {
} }
} }
} }
itemsIndexed(uiState.posts) { idx, post -> items(uiState.posts) { post ->
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled, enabled = uiState.swipeActionsEnabled,
@ -273,14 +294,14 @@ class PostListScreen : Screen {
DismissValue.Default -> Color.Transparent DismissValue.Default -> Color.Transparent
} }
}, },
onGestureBegin = rememberCallback(model) { onGestureBegin = {
model.reduce(PostListMviModel.Intent.HapticIndication) model.reduce(PostListMviModel.Intent.HapticIndication)
}, },
onDismissToStart = rememberCallback(model) { onDismissToStart = rememberCallback(model) {
model.reduce(PostListMviModel.Intent.UpVotePost(idx)) model.reduce(PostListMviModel.Intent.UpVotePost(post.id))
}, },
onDismissToEnd = rememberCallback(model) { onDismissToEnd = rememberCallback(model) {
model.reduce(PostListMviModel.Intent.DownVotePost(idx)) model.reduce(PostListMviModel.Intent.DownVotePost(post.id))
}, },
swipeContent = { direction -> swipeContent = { direction ->
val icon = when (direction) { val icon = when (direction) {
@ -302,25 +323,25 @@ class PostListScreen : Screen {
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
blurNsfw = uiState.blurNsfw, blurNsfw = uiState.blurNsfw,
onClick = rememberCallback(model) { onClick = rememberCallback(model) {
model.reduce(PostListMviModel.Intent.MarkAsRead(idx)) model.reduce(PostListMviModel.Intent.MarkAsRead(post.id))
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen(post), PostDetailScreen(post),
) )
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator = rememberCallbackArgs { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(user), UserDetailScreen(user),
) )
}, },
onUpVote = rememberCallback(model) { onUpVote = rememberCallback(model) {
model.reduce( model.reduce(
PostListMviModel.Intent.UpVotePost( PostListMviModel.Intent.UpVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -328,7 +349,7 @@ class PostListScreen : Screen {
onDownVote = rememberCallback(model) { onDownVote = rememberCallback(model) {
model.reduce( model.reduce(
PostListMviModel.Intent.DownVotePost( PostListMviModel.Intent.DownVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -336,27 +357,22 @@ class PostListScreen : Screen {
onSave = rememberCallback(model) { onSave = rememberCallback(model) {
model.reduce( model.reduce(
PostListMviModel.Intent.SavePost( PostListMviModel.Intent.SavePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
}, },
onReply = rememberCallback(model) { // onReply = rememberCallback(model) {
val screen = CreateCommentScreen( // val screen = CreateCommentScreen(
originalPost = post, // originalPost = post,
) // )
notificationCenter.addObserver( // bottomSheetNavigator.show(screen)
{ // },
model.reduce(PostListMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
},
onImageClick = rememberCallbackArgs(model) { url -> onImageClick = rememberCallbackArgs(model) { url ->
model.reduce(PostListMviModel.Intent.MarkAsRead(idx)) model.reduce(PostListMviModel.Intent.MarkAsRead(post.id))
navigator?.push(ZoomableImageScreen(url)) navigationCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url)
)
}, },
options = buildList { options = buildList {
add(stringResource(MR.strings.post_action_share)) add(stringResource(MR.strings.post_action_share))
@ -375,20 +391,15 @@ class PostListScreen : Screen {
) )
4 -> { 4 -> {
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()
{ ?.show(
model.reduce(PostListMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.PostCreated
)
bottomSheetNavigator.show(
CreatePostScreen(editedPost = post) CreatePostScreen(editedPost = post)
) )
} }
3 -> { 3 -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()
?.show(
CreateReportScreen(postId = post.id) CreateReportScreen(postId = post.id)
) )
} }
@ -397,10 +408,10 @@ class PostListScreen : Screen {
rawContent = post rawContent = post
} }
1 -> model.reduce(PostListMviModel.Intent.Hide(idx)) 1 -> model.reduce(PostListMviModel.Intent.Hide(post.id))
else -> model.reduce( else -> model.reduce(
PostListMviModel.Intent.SharePost(idx) PostListMviModel.Intent.SharePost(post.id)
) )
} }
} }

View File

@ -45,23 +45,31 @@ class PostListViewModel(
private var hideReadPosts = false private var hideReadPosts = false
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
(it as? PostModel)?.also { post -> (it as? PostModel)?.also { post ->
handlePostUpdate(post) handlePostUpdate(post)
} }
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated
notificationCenter.addObserver({ )
notificationCenter.addObserver(
{
(it as? PostModel)?.also { post -> (it as? PostModel)?.also { post ->
handlePostDelete(post.id) handlePostDelete(post.id)
} }
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostDeleted) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostDeleted
notificationCenter.addObserver({ )
notificationCenter.addObserver(
{
handleLogout() handleLogout()
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout
notificationCenter.addObserver({ )
notificationCenter.addObserver(
{
// apply new feed and sort type // apply new feed and sort type
firstLoad = true firstLoad = true
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.ResetContents) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.ResetContents
)
} }
fun finalize() { fun finalize() {
@ -134,17 +142,17 @@ class PostListViewModel(
is PostListMviModel.Intent.ChangeSort -> applySortType(intent.value) is PostListMviModel.Intent.ChangeSort -> applySortType(intent.value)
is PostListMviModel.Intent.ChangeListing -> applyListingType(intent.value) is PostListMviModel.Intent.ChangeListing -> applyListingType(intent.value)
is PostListMviModel.Intent.DownVotePost -> toggleDownVote( is PostListMviModel.Intent.DownVotePost -> toggleDownVote(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is PostListMviModel.Intent.SavePost -> toggleSave( is PostListMviModel.Intent.SavePost -> toggleSave(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is PostListMviModel.Intent.UpVotePost -> toggleUpVote( is PostListMviModel.Intent.UpVotePost -> toggleUpVote(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
@ -152,15 +160,15 @@ class PostListViewModel(
is PostListMviModel.Intent.HandlePostUpdate -> handlePostUpdate(intent.post) is PostListMviModel.Intent.HandlePostUpdate -> handlePostUpdate(intent.post)
is PostListMviModel.Intent.DeletePost -> handlePostDelete(intent.id) is PostListMviModel.Intent.DeletePost -> handlePostDelete(intent.id)
is PostListMviModel.Intent.SharePost -> { is PostListMviModel.Intent.SharePost -> {
share(post = uiState.value.posts[intent.index]) share(post = uiState.value.posts.first { it.id == intent.id })
} }
is PostListMviModel.Intent.MarkAsRead -> { is PostListMviModel.Intent.MarkAsRead -> {
markAsRead(post = uiState.value.posts[intent.index]) markAsRead(post = uiState.value.posts.first { it.id == intent.id })
} }
PostListMviModel.Intent.ClearRead -> clearRead() PostListMviModel.Intent.ClearRead -> clearRead()
is PostListMviModel.Intent.Hide -> hide(post = uiState.value.posts[intent.index]) is PostListMviModel.Intent.Hide -> hide(post = uiState.value.posts.first { it.id == intent.id })
} }
} }

View File

@ -26,7 +26,6 @@ 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.navigator.CurrentScreen import cafe.adriel.voyager.navigator.CurrentScreen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabNavigator import cafe.adriel.voyager.navigator.tab.TabNavigator
@ -35,9 +34,11 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SectionSelector
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.InboxTypeSheet import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.InboxTypeSheet
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxViewModel
@ -66,16 +67,30 @@ object InboxScreen : Tab {
val model = rememberScreenModel { getInboxViewModel() } val model = rememberScreenModel { getInboxViewModel() }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
val navigationCoordinator = remember { getNavigationCoordinator() }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
DisposableEffect(key) { DisposableEffect(key) {
onDispose { onDispose {
notificationCenter.removeObserver(key) notificationCenter.removeObserver(key)
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{
(it as? Boolean)?.also { value ->
model.reduce(
InboxMviModel.Intent.ChangeUnreadOnly(value)
)
}
}, key, NotificationCenterContractKeys.ChangeInboxType
)
}
Scaffold( Scaffold(
modifier = Modifier.padding(Spacing.xxs), modifier = Modifier.padding(Spacing.xxs),
@ -115,14 +130,7 @@ object InboxScreen : Tab {
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
val sheet = InboxTypeSheet() val sheet = InboxTypeSheet()
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? Boolean)?.also { value ->
model.reduce(
InboxMviModel.Intent.ChangeUnreadOnly(value)
)
}
}, key, NotificationCenterContractKeys.ChangeInboxType)
bottomSheetNavigator.show(sheet)
}, },
), ),
text = text, text = text,
@ -162,7 +170,13 @@ object InboxScreen : Tab {
Column( Column(
modifier = Modifier modifier = Modifier
.padding(paddingValues) .padding(paddingValues)
.nestedScroll(scrollBehavior.nestedScrollConnection), .let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
},
verticalArrangement = Arrangement.spacedBy(Spacing.s), verticalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
SectionSelector( SectionSelector(

View File

@ -1,10 +1,12 @@
package com.github.diegoberaldin.raccoonforlemmy.feature.inbox.mentions package com.github.diegoberaldin.raccoonforlemmy.feature.inbox.mentions
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PersonMentionModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PersonMentionModel
@Stable
interface InboxMentionsMviModel : interface InboxMentionsMviModel :
MviModel<InboxMentionsMviModel.Intent, InboxMentionsMviModel.UiState, InboxMentionsMviModel.Effect>, MviModel<InboxMentionsMviModel.Intent, InboxMentionsMviModel.UiState, InboxMentionsMviModel.Effect>,
ScreenModel { ScreenModel {
@ -12,10 +14,10 @@ interface InboxMentionsMviModel :
sealed interface Intent { sealed interface Intent {
data object Refresh : Intent data object Refresh : Intent
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class MarkAsRead(val read: Boolean, val index: Int) : Intent data class MarkAsRead(val read: Boolean, val id: Int) : Intent
data object HapticIndication : Intent data object HapticIndication : Intent
data class UpVoteComment(val index: Int) : Intent data class UpVoteComment(val id: Int) : Intent
data class DownVoteComment(val index: Int) : Intent data class DownVoteComment(val id: Int) : Intent
} }
data class UiState( data class UiState(

View File

@ -9,7 +9,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -73,8 +73,8 @@ class InboxMentionsScreen : Tab {
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
LaunchedEffect(navigationCoordinator) { LaunchedEffect(navigationCoordinator) {
navigationCoordinator.onDoubleTabSelection.onEach { navigationCoordinator.onDoubleTabSelection.onEach {
if (it == InboxTab) { if (it == InboxTab) {
@ -129,7 +129,7 @@ class InboxMentionsScreen : Tab {
) )
} }
} }
itemsIndexed(uiState.mentions) { idx, mention -> items(uiState.mentions) { mention ->
val endColor = MaterialTheme.colorScheme.secondary val endColor = MaterialTheme.colorScheme.secondary
val startColor = MaterialTheme.colorScheme.tertiary val startColor = MaterialTheme.colorScheme.tertiary
SwipeableCard( SwipeableCard(
@ -149,7 +149,7 @@ class InboxMentionsScreen : Tab {
model.reduce( model.reduce(
InboxMentionsMviModel.Intent.MarkAsRead( InboxMentionsMviModel.Intent.MarkAsRead(
read = true, read = true,
index = idx, id = mention.id,
), ),
) )
}, },
@ -157,7 +157,7 @@ class InboxMentionsScreen : Tab {
model.reduce( model.reduce(
InboxMentionsMviModel.Intent.MarkAsRead( InboxMentionsMviModel.Intent.MarkAsRead(
read = false, read = false,
index = idx, id = mention.id,
), ),
) )
}, },
@ -181,7 +181,7 @@ class InboxMentionsScreen : Tab {
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
separateUpAndDownVotes = uiState.separateUpAndDownVotes, separateUpAndDownVotes = uiState.separateUpAndDownVotes,
onOpenPost = rememberCallbackArgs { post -> onOpenPost = rememberCallbackArgs { post ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen( PostDetailScreen(
post = post, post = post,
highlightCommentId = mention.comment.id, highlightCommentId = mention.comment.id,
@ -189,20 +189,24 @@ class InboxMentionsScreen : Tab {
) )
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator = rememberCallbackArgs { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(user), UserDetailScreen(user),
) )
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },
onUpVote = rememberCallbackArgs(model) { onUpVote = rememberCallbackArgs(model) {
model.reduce(InboxMentionsMviModel.Intent.UpVoteComment(idx)) model.reduce(InboxMentionsMviModel.Intent.UpVoteComment(mention.id))
}, },
onDownVote = rememberCallbackArgs(model) { onDownVote = rememberCallbackArgs(model) {
model.reduce(InboxMentionsMviModel.Intent.DownVoteComment(idx)) model.reduce(
InboxMentionsMviModel.Intent.DownVoteComment(
mention.id
)
)
}, },
) )
}, },

View File

@ -36,9 +36,11 @@ class InboxMentionsViewModel(
private var currentPage: Int = 1 private var currentPage: Int = 1
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
handleLogout() handleLogout()
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout
)
} }
fun finalize() { fun finalize() {
@ -81,18 +83,18 @@ class InboxMentionsViewModel(
is InboxMentionsMviModel.Intent.MarkAsRead -> { is InboxMentionsMviModel.Intent.MarkAsRead -> {
markAsRead( markAsRead(
read = intent.read, read = intent.read,
mention = mvi.uiState.value.mentions[intent.index], mention = uiState.value.mentions.first { it.id == intent.id },
) )
} }
InboxMentionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate() InboxMentionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
is InboxMentionsMviModel.Intent.DownVoteComment -> toggleDownVoteComment( is InboxMentionsMviModel.Intent.DownVoteComment -> toggleDownVoteComment(
mention = mvi.uiState.value.mentions[intent.index], mention = uiState.value.mentions.first { it.id == intent.id },
feedback = true, feedback = true,
) )
is InboxMentionsMviModel.Intent.UpVoteComment -> toggleUpVoteComment( is InboxMentionsMviModel.Intent.UpVoteComment -> toggleUpVoteComment(
mention = mvi.uiState.value.mentions[intent.index], mention = uiState.value.mentions.first { it.id == intent.id },
feedback = true, feedback = true,
) )
} }

View File

@ -1,9 +1,11 @@
package com.github.diegoberaldin.raccoonforlemmy.feature.inbox.messages package com.github.diegoberaldin.raccoonforlemmy.feature.inbox.messages
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel
@Stable
interface InboxMessagesMviModel : interface InboxMessagesMviModel :
MviModel<InboxMessagesMviModel.Intent, InboxMessagesMviModel.UiState, InboxMessagesMviModel.Effect>, MviModel<InboxMessagesMviModel.Intent, InboxMessagesMviModel.UiState, InboxMessagesMviModel.Effect>,
ScreenModel { ScreenModel {

View File

@ -36,6 +36,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.chat.InboxChatScre
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxMessagesViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.di.getInboxMessagesViewModel
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.ui.InboxTab import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.ui.InboxTab
import com.github.diegoberaldin.raccoonforlemmy.resources.MR import com.github.diegoberaldin.raccoonforlemmy.resources.MR
@ -57,7 +58,6 @@ class InboxMessagesScreen : Tab {
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
LaunchedEffect(navigationCoordinator) { LaunchedEffect(navigationCoordinator) {
navigationCoordinator.onDoubleTabSelection.onEach { navigationCoordinator.onDoubleTabSelection.onEach {
@ -117,15 +117,15 @@ class InboxMessagesScreen : Tab {
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
lastMessage = chat.content.orEmpty(), lastMessage = chat.content.orEmpty(),
lastMessageDate = chat.publishDate, lastMessageDate = chat.publishDate,
onOpenUser = { user -> onOpenUser = rememberCallbackArgs { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(user) UserDetailScreen(user)
) )
}, },
onOpen = { onOpen = rememberCallback {
val userId = otherUser?.id val userId = otherUser?.id
if (userId != null) { if (userId != null) {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
InboxChatScreen(userId) InboxChatScreen(userId)
) )
} }

View File

@ -32,9 +32,11 @@ class InboxMessagesViewModel(
private var currentPage: Int = 1 private var currentPage: Int = 1
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
handleLogout() handleLogout()
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout
)
} }
fun finalize() { fun finalize() {

View File

@ -1,10 +1,12 @@
package com.github.diegoberaldin.raccoonforlemmy.feature.inbox.replies package com.github.diegoberaldin.raccoonforlemmy.feature.inbox.replies
import androidx.compose.runtime.Stable
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PersonMentionModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PersonMentionModel
@Stable
interface InboxRepliesMviModel : interface InboxRepliesMviModel :
MviModel<InboxRepliesMviModel.Intent, InboxRepliesMviModel.UiState, InboxRepliesMviModel.Effect>, MviModel<InboxRepliesMviModel.Intent, InboxRepliesMviModel.UiState, InboxRepliesMviModel.Effect>,
ScreenModel { ScreenModel {
@ -12,10 +14,10 @@ interface InboxRepliesMviModel :
sealed interface Intent { sealed interface Intent {
data object Refresh : Intent data object Refresh : Intent
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class MarkAsRead(val read: Boolean, val index: Int) : Intent data class MarkAsRead(val read: Boolean, val id: Int) : Intent
data object HapticIndication : Intent data object HapticIndication : Intent
data class UpVoteComment(val index: Int) : Intent data class UpVoteComment(val id: Int) : Intent
data class DownVoteComment(val index: Int) : Intent data class DownVoteComment(val id: Int) : Intent
} }
data class UiState( data class UiState(

View File

@ -9,7 +9,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -72,8 +72,8 @@ class InboxRepliesScreen : Tab {
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
LaunchedEffect(navigationCoordinator) { LaunchedEffect(navigationCoordinator) {
navigationCoordinator.onDoubleTabSelection.onEach { navigationCoordinator.onDoubleTabSelection.onEach {
if (it == InboxTab) { if (it == InboxTab) {
@ -128,7 +128,7 @@ class InboxRepliesScreen : Tab {
) )
} }
} }
itemsIndexed(uiState.replies) { idx, mention -> items(uiState.replies) { reply ->
val endColor = MaterialTheme.colorScheme.secondary val endColor = MaterialTheme.colorScheme.secondary
val startColor = MaterialTheme.colorScheme.tertiary val startColor = MaterialTheme.colorScheme.tertiary
SwipeableCard( SwipeableCard(
@ -148,7 +148,7 @@ class InboxRepliesScreen : Tab {
model.reduce( model.reduce(
InboxRepliesMviModel.Intent.MarkAsRead( InboxRepliesMviModel.Intent.MarkAsRead(
read = true, read = true,
index = idx, id = reply.id,
), ),
) )
}, },
@ -156,7 +156,7 @@ class InboxRepliesScreen : Tab {
model.reduce( model.reduce(
InboxRepliesMviModel.Intent.MarkAsRead( InboxRepliesMviModel.Intent.MarkAsRead(
read = false, read = false,
index = idx, id = reply.id,
), ),
) )
}, },
@ -174,34 +174,34 @@ class InboxRepliesScreen : Tab {
}, },
content = { content = {
InboxCard( InboxCard(
mention = mention, mention = reply,
postLayout = uiState.postLayout, postLayout = uiState.postLayout,
type = InboxCardType.Reply, type = InboxCardType.Reply,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
separateUpAndDownVotes = uiState.separateUpAndDownVotes, separateUpAndDownVotes = uiState.separateUpAndDownVotes,
onOpenPost = rememberCallbackArgs { post -> onOpenPost = rememberCallbackArgs { post ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen( PostDetailScreen(
post = post, post = post,
highlightCommentId = mention.comment.id, highlightCommentId = reply.comment.id,
), ),
) )
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator = rememberCallbackArgs { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(user), UserDetailScreen(user),
) )
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },
onUpVote = rememberCallbackArgs(model) { onUpVote = rememberCallbackArgs(model) {
model.reduce(InboxRepliesMviModel.Intent.UpVoteComment(idx)) model.reduce(InboxRepliesMviModel.Intent.UpVoteComment(reply.id))
}, },
onDownVote = rememberCallbackArgs(model) { onDownVote = rememberCallbackArgs(model) {
model.reduce(InboxRepliesMviModel.Intent.DownVoteComment(idx)) model.reduce(InboxRepliesMviModel.Intent.DownVoteComment(reply.id))
}, },
) )
}, },

View File

@ -39,9 +39,11 @@ class InboxRepliesViewModel(
private var currentUserId: Int? = null private var currentUserId: Int? = null
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
handleLogout() handleLogout()
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout
)
} }
fun finalize() { fun finalize() {
@ -85,19 +87,19 @@ class InboxRepliesViewModel(
is InboxRepliesMviModel.Intent.MarkAsRead -> { is InboxRepliesMviModel.Intent.MarkAsRead -> {
markAsRead( markAsRead(
read = intent.read, read = intent.read,
mention = mvi.uiState.value.replies[intent.index] mention = uiState.value.replies.first { it.id == intent.id },
) )
} }
InboxRepliesMviModel.Intent.HapticIndication -> hapticFeedback.vibrate() InboxRepliesMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
is InboxRepliesMviModel.Intent.DownVoteComment -> toggleDownVoteComment( is InboxRepliesMviModel.Intent.DownVoteComment -> toggleDownVoteComment(
mention = mvi.uiState.value.replies[intent.index], mention = uiState.value.replies.first { it.id == intent.id },
feedback = true, feedback = true,
) )
is InboxRepliesMviModel.Intent.UpVoteComment -> toggleUpVoteComment( is InboxRepliesMviModel.Intent.UpVoteComment -> toggleUpVoteComment(
mention = mvi.uiState.value.replies[intent.index], mention = uiState.value.replies.first { it.id == intent.id },
feedback = true, feedback = true,
) )
} }

View File

@ -17,14 +17,14 @@ interface ProfileLoggedMviModel :
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class DeletePost(val id: Int) : Intent data class DeletePost(val id: Int) : Intent
data class DeleteComment(val id: Int) : Intent data class DeleteComment(val id: Int) : Intent
data class SharePost(val index: Int) : Intent data class SharePost(val id: Int) : Intent
data class UpVotePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class DownVotePost(val index: Int, val feedback: Boolean = false) : Intent data class DownVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class SavePost(val id: Int, val feedback: Boolean = false) : Intent
data class UpVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class UpVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class DownVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class DownVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class SaveComment(val index: Int, val feedback: Boolean = false) : Intent data class SaveComment(val id: Int, val feedback: Boolean = false) : Intent
} }
data class UiState( data class UiState(

View File

@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text import androidx.compose.material.Text
@ -34,7 +34,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions import cafe.adriel.voyager.navigator.tab.TabOptions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
@ -82,12 +81,10 @@ internal object ProfileLoggedScreen : Tab {
val user = uiState.user val user = uiState.user
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
var rawContent by remember { mutableStateOf<Any?>(null) } var rawContent by remember { mutableStateOf<Any?>(null) }
LaunchedEffect(navigator) { LaunchedEffect(Unit) {
navigationCoordinator.onDoubleTabSelection.onEach { tab -> navigationCoordinator.onDoubleTabSelection.onEach { tab ->
if (tab == ProfileTab) { if (tab == ProfileTab) {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
@ -99,6 +96,22 @@ internal object ProfileLoggedScreen : Tab {
notificationCenter.removeObserver(key) notificationCenter.removeObserver(key)
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{
model.reduce(ProfileLoggedMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.PostCreated
)
notificationCenter.addObserver(
{
model.reduce(ProfileLoggedMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
}
if (user != null) { if (user != null) {
Column( Column(
@ -127,7 +140,8 @@ internal object ProfileLoggedScreen : Tab {
user = user, user = user,
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
onOpenImage = rememberCallbackArgs { url -> onOpenImage = rememberCallbackArgs { url ->
navigator?.push(ZoomableImageScreen(url)) navigationCoordinator.getRootNavigator()
?.push(ZoomableImageScreen(url))
}, },
) )
SectionSelector( SectionSelector(
@ -167,7 +181,7 @@ internal object ProfileLoggedScreen : Tab {
} }
} }
} }
itemsIndexed(uiState.posts) { idx, post -> items(uiState.posts) { post ->
PostCard( PostCard(
post = post, post = post,
postLayout = uiState.postLayout, postLayout = uiState.postLayout,
@ -177,41 +191,41 @@ internal object ProfileLoggedScreen : Tab {
hideAuthor = true, hideAuthor = true,
blurNsfw = false, blurNsfw = false,
onClick = rememberCallback { onClick = rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen(post), PostDetailScreen(post),
) )
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },
onImageClick = rememberCallbackArgs { url -> onImageClick = rememberCallbackArgs { url ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url), ZoomableImageScreen(url),
) )
}, },
onUpVote = rememberCallback(model) { onUpVote = rememberCallback(model) {
model.reduce( model.reduce(
ProfileLoggedMviModel.Intent.UpVotePost( ProfileLoggedMviModel.Intent.UpVotePost(
idx, id = post.id,
true feedback = true
) )
) )
}, },
onDownVote = rememberCallback(model) { onDownVote = rememberCallback(model) {
model.reduce( model.reduce(
ProfileLoggedMviModel.Intent.DownVotePost( ProfileLoggedMviModel.Intent.DownVotePost(
idx, id = post.id,
true feedback = true
) )
) )
}, },
onSave = rememberCallback(model) { onSave = rememberCallback(model) {
model.reduce( model.reduce(
ProfileLoggedMviModel.Intent.SavePost( ProfileLoggedMviModel.Intent.SavePost(
idx, id = post.id,
true feedback = true
) )
) )
}, },
@ -228,14 +242,7 @@ internal object ProfileLoggedScreen : Tab {
) )
2 -> { 2 -> {
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()?.show(
{
model.reduce(ProfileLoggedMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.PostCreated
)
bottomSheetNavigator.show(
CreatePostScreen( CreatePostScreen(
editedPost = post, editedPost = post,
) )
@ -247,7 +254,7 @@ internal object ProfileLoggedScreen : Tab {
} }
else -> model.reduce( else -> model.reduce(
ProfileLoggedMviModel.Intent.SharePost(idx) ProfileLoggedMviModel.Intent.SharePost(post.id)
) )
} }
}, },
@ -281,7 +288,7 @@ internal object ProfileLoggedScreen : Tab {
) )
} }
} }
itemsIndexed(uiState.comments) { idx, comment -> items(uiState.comments) { comment ->
CommentCard( CommentCard(
modifier = Modifier.background(MaterialTheme.colorScheme.background), modifier = Modifier.background(MaterialTheme.colorScheme.background),
comment = comment, comment = comment,
@ -291,7 +298,7 @@ internal object ProfileLoggedScreen : Tab {
hideAuthor = true, hideAuthor = true,
hideIndent = true, hideIndent = true,
onClick = rememberCallback { onClick = rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen( PostDetailScreen(
post = PostModel(id = comment.postId), post = PostModel(id = comment.postId),
highlightCommentId = comment.id, highlightCommentId = comment.id,
@ -301,24 +308,24 @@ internal object ProfileLoggedScreen : Tab {
onUpVote = rememberCallback(model) { onUpVote = rememberCallback(model) {
model.reduce( model.reduce(
ProfileLoggedMviModel.Intent.UpVoteComment( ProfileLoggedMviModel.Intent.UpVoteComment(
idx, id = comment.id,
true feedback = true
) )
) )
}, },
onDownVote = rememberCallback(model) { onDownVote = rememberCallback(model) {
model.reduce( model.reduce(
ProfileLoggedMviModel.Intent.DownVoteComment( ProfileLoggedMviModel.Intent.DownVoteComment(
idx, id = comment.id,
true feedback = true
) )
) )
}, },
onSave = rememberCallback(model) { onSave = rememberCallback(model) {
model.reduce( model.reduce(
ProfileLoggedMviModel.Intent.SaveComment( ProfileLoggedMviModel.Intent.SaveComment(
idx, id = comment.id,
true feedback = true
) )
) )
}, },
@ -338,14 +345,7 @@ internal object ProfileLoggedScreen : Tab {
} }
1 -> { 1 -> {
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()?.show(
{
model.reduce(ProfileLoggedMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(
CreateCommentScreen( CreateCommentScreen(
editedComment = comment, editedComment = comment,
) )

View File

@ -46,16 +46,20 @@ class ProfileLoggedViewModel(
private var currentPage = 1 private var currentPage = 1
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
(it as? PostModel)?.also { post -> (it as? PostModel)?.also { post ->
handlePostUpdate(post) handlePostUpdate(post)
} }
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostUpdated
notificationCenter.addObserver({ )
notificationCenter.addObserver(
{
(it as? PostModel)?.also { post -> (it as? PostModel)?.also { post ->
handlePostDelete(post.id) handlePostDelete(post.id)
} }
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostDeleted) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.PostDeleted
)
} }
fun finalize() { fun finalize() {
@ -112,36 +116,36 @@ class ProfileLoggedViewModel(
} }
is ProfileLoggedMviModel.Intent.SharePost -> share( is ProfileLoggedMviModel.Intent.SharePost -> share(
post = uiState.value.posts[intent.index] post = uiState.value.posts.first { it.id == intent.id },
) )
is ProfileLoggedMviModel.Intent.DownVoteComment -> toggleDownVoteComment( is ProfileLoggedMviModel.Intent.DownVoteComment -> toggleDownVoteComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is ProfileLoggedMviModel.Intent.DownVotePost -> toggleDownVotePost( is ProfileLoggedMviModel.Intent.DownVotePost -> toggleDownVotePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is ProfileLoggedMviModel.Intent.SaveComment -> toggleSaveComment( is ProfileLoggedMviModel.Intent.SaveComment -> toggleSaveComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is ProfileLoggedMviModel.Intent.SavePost -> toggleSavePost( is ProfileLoggedMviModel.Intent.SavePost -> toggleSavePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is ProfileLoggedMviModel.Intent.UpVoteComment -> toggleUpVoteComment( is ProfileLoggedMviModel.Intent.UpVoteComment -> toggleUpVoteComment(
comment = uiState.value.comments[intent.index], comment = uiState.value.comments.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is ProfileLoggedMviModel.Intent.UpVotePost -> toggleUpVotePost( is ProfileLoggedMviModel.Intent.UpVotePost -> toggleUpVotePost(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
} }

View File

@ -45,7 +45,6 @@ import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
@ -74,7 +73,7 @@ class LoginBottomSheet : Screen {
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val genericError = stringResource(MR.strings.message_generic_error) val genericError = stringResource(MR.strings.message_generic_error)
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { model.effects.onEach {
@ -86,14 +85,13 @@ class LoginBottomSheet : Screen {
} }
LoginBottomSheetMviModel.Effect.LoginSuccess -> { LoginBottomSheetMviModel.Effect.LoginSuccess -> {
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} }
} }
}.launchIn(this) }.launchIn(this)
} }
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
val settingsRepository = remember { getSettingsRepository() } val settingsRepository = remember { getSettingsRepository() }
Box( Box(
@ -125,12 +123,12 @@ class LoginBottomSheet : Screen {
IconButton( IconButton(
modifier = Modifier.align(Alignment.TopEnd), modifier = Modifier.align(Alignment.TopEnd),
onClick = { onClick = {
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
handleUrl( handleUrl(
url = HELP_URL, url = HELP_URL,
openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser, openExternal = settingsRepository.currentSettings.value.openUrlsInExternalBrowser,
uriHandler = uriHandler, uriHandler = uriHandler,
navigator = navigator navigator = navigationCoordinator.getRootNavigator(),
) )
}, },
) { ) {

View File

@ -28,7 +28,6 @@ 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.navigator.CurrentScreen import cafe.adriel.voyager.navigator.CurrentScreen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabNavigator import cafe.adriel.voyager.navigator.tab.TabNavigator
@ -36,6 +35,8 @@ import cafe.adriel.voyager.navigator.tab.TabOptions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.di.getProfileScreenModel import com.github.diegoberaldin.raccoonforlemmy.feature.profile.di.getProfileScreenModel
@ -66,9 +67,11 @@ internal object ProfileMainScreen : Tab {
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
val navigationCoordinator = remember { getNavigationCoordinator() }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
Scaffold( Scaffold(
modifier = Modifier.padding(Spacing.xxs), modifier = Modifier.padding(Spacing.xxs),
@ -106,7 +109,8 @@ internal object ProfileMainScreen : Tab {
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
bottomSheetNavigator.show(ManageAccountsScreen()) navigationCoordinator.getBottomNavigator()
?.show(ManageAccountsScreen())
}, },
), ),
imageVector = Icons.Default.ManageAccounts, imageVector = Icons.Default.ManageAccounts,
@ -130,11 +134,17 @@ internal object ProfileMainScreen : Tab {
}, },
) )
}, },
) { ) { paddinValues ->
Box( Box(
modifier = Modifier modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection) .padding(paddinValues)
.padding(it), .let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
},
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
// wait until logging status is determined // wait until logging status is determined

View File

@ -28,6 +28,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -36,11 +37,11 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomImage import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomImage
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.di.getManageAccountsViewModel import com.github.diegoberaldin.raccoonforlemmy.feature.profile.di.getManageAccountsViewModel
@ -57,13 +58,13 @@ class ManageAccountsScreen : Screen {
val model = rememberScreenModel { getManageAccountsViewModel() } val model = rememberScreenModel { getManageAccountsViewModel() }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { effect -> model.effects.onEach { effect ->
when (effect) { when (effect) {
ManageAccountsMviModel.Effect.Close -> { ManageAccountsMviModel.Effect.Close -> {
bottomSheetNavigator.hide() navigationCoordinator.getBottomNavigator()?.hide()
} }
} }
}.launchIn(this) }.launchIn(this)
@ -151,7 +152,7 @@ class ManageAccountsScreen : Screen {
Spacer(modifier = Modifier.height(Spacing.m)) Spacer(modifier = Modifier.height(Spacing.m))
Button( Button(
onClick = { onClick = {
bottomSheetNavigator.show(LoginBottomSheet()) navigationCoordinator.getBottomNavigator()?.show(LoginBottomSheet())
}, },
) { ) {
Row( Row(

View File

@ -9,12 +9,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions import cafe.adriel.voyager.navigator.tab.TabOptions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheet import com.github.diegoberaldin.raccoonforlemmy.feature.profile.login.LoginBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.resources.MR import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.compose.stringResource
@ -28,7 +29,8 @@ internal object ProfileNotLoggedScreen : Tab {
@Composable @Composable
override fun Content() { override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val navigationCoordinator = remember { getNavigationCoordinator() }
Column( Column(
modifier = Modifier.fillMaxSize().padding(horizontal = Spacing.m), modifier = Modifier.fillMaxSize().padding(horizontal = Spacing.m),
verticalArrangement = Arrangement.spacedBy(Spacing.xs), verticalArrangement = Arrangement.spacedBy(Spacing.xs),
@ -40,7 +42,7 @@ internal object ProfileNotLoggedScreen : Tab {
Button( Button(
modifier = Modifier.align(Alignment.CenterHorizontally), modifier = Modifier.align(Alignment.CenterHorizontally),
onClick = { onClick = {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()?.show(
LoginBottomSheet(), LoginBottomSheet(),
) )
}, },

View File

@ -16,12 +16,12 @@ interface ExploreMviModel :
data class SetListingType(val value: ListingType) : Intent data class SetListingType(val value: ListingType) : Intent
data class SetSortType(val value: SortType) : Intent data class SetSortType(val value: SortType) : Intent
data class SetResultType(val value: SearchResultType) : Intent data class SetResultType(val value: SearchResultType) : Intent
data class UpVotePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class DownVotePost(val index: Int, val feedback: Boolean = false) : Intent data class DownVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class SavePost(val id: Int, val feedback: Boolean = false) : Intent
data class UpVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class UpVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class DownVoteComment(val index: Int, val feedback: Boolean = false) : Intent data class DownVoteComment(val id: Int, val feedback: Boolean = false) : Intent
data class SaveComment(val index: Int, val feedback: Boolean = false) : Intent data class SaveComment(val id: Int, val feedback: Boolean = false) : Intent
} }
data class UiState( data class UiState(

View File

@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
@ -51,7 +51,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
@ -71,6 +70,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallbackArgs
@ -98,8 +98,6 @@ class ExploreScreen : Screen {
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
@ -114,13 +112,40 @@ class ExploreScreen : Screen {
} }
} }
} }
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
DisposableEffect(key) { DisposableEffect(key) {
onDispose { onDispose {
notificationCenter.removeObserver(key) notificationCenter.removeObserver(key)
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{ result ->
(result as? ListingType)?.also {
model.reduce(ExploreMviModel.Intent.SetListingType(it))
}
}, key, NotificationCenterContractKeys.ChangeFeedType
)
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
ExploreMviModel.Intent.SetSortType(sortType)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
model.reduce(ExploreMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
}
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
LaunchedEffect(navigator) { LaunchedEffect(Unit) {
navigationCoordinator.onDoubleTabSelection.onEach { tab -> navigationCoordinator.onDoubleTabSelection.onEach { tab ->
if (tab == ExploreTab) { if (tab == ExploreTab) {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
@ -140,10 +165,7 @@ class ExploreScreen : Screen {
} }
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier.padding(Spacing.xxs),
.padding(Spacing.xxs)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(keyboardScrollConnection),
topBar = { topBar = {
ExploreTopBar( ExploreTopBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
@ -154,26 +176,14 @@ class ExploreScreen : Screen {
val sheet = ListingTypeBottomSheet( val sheet = ListingTypeBottomSheet(
isLogged = uiState.isLogged, isLogged = uiState.isLogged,
) )
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? ListingType)?.also {
model.reduce(ExploreMviModel.Intent.SetListingType(it))
}
}, key, NotificationCenterContractKeys.ChangeFeedType)
bottomSheetNavigator.show(sheet)
}, },
onSelectSortType = rememberCallback { onSelectSortType = rememberCallback {
focusManager.clearFocus() focusManager.clearFocus()
val sheet = SortBottomSheet( val sheet = SortBottomSheet(
expandTop = true, expandTop = true,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
ExploreMviModel.Intent.SetSortType(sortType)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
onHamburgerTapped = rememberCallback { onHamburgerTapped = rememberCallback {
scope.launch { scope.launch {
@ -265,7 +275,16 @@ class ExploreScreen : Screen {
{ model.reduce(ExploreMviModel.Intent.Refresh) }, { model.reduce(ExploreMviModel.Intent.Refresh) },
) )
Box( Box(
modifier = Modifier.padding(Spacing.xxs).pullRefresh(pullRefreshState), modifier = Modifier.padding(Spacing.xxs)
.let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.nestedScroll(keyboardScrollConnection)
.pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
state = lazyListState, state = lazyListState,
@ -282,7 +301,7 @@ class ExploreScreen : Screen {
} }
} }
} }
itemsIndexed(uiState.results) { idx, result -> items(uiState.results) { result ->
when (result) { when (result) {
is CommunityModel -> { is CommunityModel -> {
CommunityItem( CommunityItem(
@ -290,7 +309,7 @@ class ExploreScreen : Screen {
.fillMaxWidth() .fillMaxWidth()
.onClick( .onClick(
rememberCallback { rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(result), CommunityDetailScreen(result),
) )
}, },
@ -309,24 +328,24 @@ class ExploreScreen : Screen {
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
blurNsfw = uiState.blurNsfw, blurNsfw = uiState.blurNsfw,
onClick = rememberCallback { onClick = rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen(result), PostDetailScreen(result),
) )
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity = rememberCallbackArgs { community ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator = rememberCallbackArgs { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(user), UserDetailScreen(user),
) )
}, },
onUpVote = rememberCallback(model) { onUpVote = rememberCallback(model) {
model.reduce( model.reduce(
ExploreMviModel.Intent.UpVotePost( ExploreMviModel.Intent.UpVotePost(
index = idx, id = result.id,
feedback = true, feedback = true,
), ),
) )
@ -334,7 +353,7 @@ class ExploreScreen : Screen {
onDownVote = rememberCallback(model) { onDownVote = rememberCallback(model) {
model.reduce( model.reduce(
ExploreMviModel.Intent.DownVotePost( ExploreMviModel.Intent.DownVotePost(
index = idx, id = result.id,
feedback = true, feedback = true,
), ),
) )
@ -342,7 +361,7 @@ class ExploreScreen : Screen {
onSave = rememberCallback(model) { onSave = rememberCallback(model) {
model.reduce( model.reduce(
ExploreMviModel.Intent.SavePost( ExploreMviModel.Intent.SavePost(
index = idx, id = result.id,
feedback = true, feedback = true,
), ),
) )
@ -351,17 +370,10 @@ class ExploreScreen : Screen {
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = result, originalPost = result,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()?.show(screen)
{
model.reduce(ExploreMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
}, },
onImageClick = rememberCallbackArgs { url -> onImageClick = rememberCallbackArgs { url ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url), ZoomableImageScreen(url),
) )
}, },
@ -381,7 +393,7 @@ class ExploreScreen : Screen {
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
hideIndent = true, hideIndent = true,
onClick = rememberCallback { onClick = rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen( PostDetailScreen(
post = PostModel(id = result.postId), post = PostModel(id = result.postId),
highlightCommentId = result.id, highlightCommentId = result.id,
@ -391,7 +403,7 @@ class ExploreScreen : Screen {
onUpVote = rememberCallback(model) { onUpVote = rememberCallback(model) {
model.reduce( model.reduce(
ExploreMviModel.Intent.UpVoteComment( ExploreMviModel.Intent.UpVoteComment(
index = idx, id = result.id,
feedback = true, feedback = true,
), ),
) )
@ -399,7 +411,7 @@ class ExploreScreen : Screen {
onDownVote = rememberCallback(model) { onDownVote = rememberCallback(model) {
model.reduce( model.reduce(
ExploreMviModel.Intent.DownVoteComment( ExploreMviModel.Intent.DownVoteComment(
index = idx, id = result.id,
feedback = true, feedback = true,
), ),
) )
@ -407,7 +419,7 @@ class ExploreScreen : Screen {
onSave = rememberCallback(model) { onSave = rememberCallback(model) {
model.reduce( model.reduce(
ExploreMviModel.Intent.SaveComment( ExploreMviModel.Intent.SaveComment(
index = idx, id = result.id,
feedback = true, feedback = true,
), ),
) )
@ -417,22 +429,15 @@ class ExploreScreen : Screen {
originalPost = PostModel(id = result.postId), originalPost = PostModel(id = result.postId),
originalComment = result, originalComment = result,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()?.show(screen)
{
model.reduce(ExploreMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
}, },
onOpenCommunity = rememberCallbackArgs { onOpenCommunity = rememberCallbackArgs {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(it) CommunityDetailScreen(it)
) )
}, },
onOpenCreator = rememberCallbackArgs { onOpenCreator = rememberCallbackArgs {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(it) UserDetailScreen(it)
) )
}, },
@ -449,7 +454,7 @@ class ExploreScreen : Screen {
.fillMaxWidth() .fillMaxWidth()
.onClick( .onClick(
rememberCallback { rememberCallback {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(result), UserDetailScreen(result),
) )
}, },

View File

@ -49,13 +49,17 @@ class ExploreViewModel(
private var firstLoad = true private var firstLoad = true
init { init {
notificationCenter.addObserver({ notificationCenter.addObserver(
{
handleLogout() handleLogout()
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.Logout
notificationCenter.addObserver({ )
notificationCenter.addObserver(
{
// apply new feed and sort type // apply new feed and sort type
firstLoad = true firstLoad = true
}, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.ResetContents) }, this::class.simpleName.orEmpty(), NotificationCenterContractKeys.ResetContents
)
} }
fun finalize() { fun finalize() {
@ -127,32 +131,32 @@ class ExploreViewModel(
is ExploreMviModel.Intent.SetSortType -> changeSortType(intent.value) is ExploreMviModel.Intent.SetSortType -> changeSortType(intent.value)
is ExploreMviModel.Intent.SetResultType -> changeResultType(intent.value) is ExploreMviModel.Intent.SetResultType -> changeResultType(intent.value)
is ExploreMviModel.Intent.DownVotePost -> toggleDownVote( is ExploreMviModel.Intent.DownVotePost -> toggleDownVote(
post = uiState.value.results[intent.index] as PostModel, post = uiState.value.results.first { (it as? PostModel)?.id == intent.id } as PostModel,
feedback = intent.feedback, feedback = intent.feedback,
) )
is ExploreMviModel.Intent.SavePost -> toggleSave( is ExploreMviModel.Intent.SavePost -> toggleSave(
post = uiState.value.results[intent.index] as PostModel, post = uiState.value.results.first { (it as? PostModel)?.id == intent.id } as PostModel,
feedback = intent.feedback, feedback = intent.feedback,
) )
is ExploreMviModel.Intent.UpVotePost -> toggleUpVote( is ExploreMviModel.Intent.UpVotePost -> toggleUpVote(
post = uiState.value.results[intent.index] as PostModel, post = uiState.value.results.first { (it as? PostModel)?.id == intent.id } as PostModel,
feedback = intent.feedback, feedback = intent.feedback,
) )
is ExploreMviModel.Intent.DownVoteComment -> toggleDownVoteComment( is ExploreMviModel.Intent.DownVoteComment -> toggleDownVoteComment(
comment = uiState.value.results[intent.index] as CommentModel, comment = uiState.value.results.first { (it as? CommentModel)?.id == intent.id } as CommentModel,
feedback = intent.feedback, feedback = intent.feedback,
) )
is ExploreMviModel.Intent.SaveComment -> toggleSaveComment( is ExploreMviModel.Intent.SaveComment -> toggleSaveComment(
comment = uiState.value.results[intent.index] as CommentModel, comment = uiState.value.results.first { (it as? CommentModel)?.id == intent.id } as CommentModel,
feedback = intent.feedback, feedback = intent.feedback,
) )
is ExploreMviModel.Intent.UpVoteComment -> toggleUpVoteComment( is ExploreMviModel.Intent.UpVoteComment -> toggleUpVoteComment(
comment = uiState.value.results[intent.index] as CommentModel, comment = uiState.value.results.first { (it as? CommentModel)?.id == intent.id } as CommentModel,
feedback = intent.feedback, feedback = intent.feedback,
) )
} }

View File

@ -11,8 +11,8 @@ interface ManageSubscriptionsMviModel :
sealed interface Intent { sealed interface Intent {
data object Refresh : Intent data object Refresh : Intent
data object HapticIndication : Intent data object HapticIndication : Intent
data class Unsubscribe(val index: Int) : Intent data class Unsubscribe(val id: Int) : Intent
data class DeleteMultiCommunity(val index: Int) : Intent data class DeleteMultiCommunity(val id: Int) : Intent
} }
data class UiState( data class UiState(

View File

@ -13,7 +13,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -78,7 +78,7 @@ class ManageSubscriptionsScreen : Screen {
val model = rememberScreenModel { getManageSubscriptionsViewModel() } val model = rememberScreenModel { getManageSubscriptionsViewModel() }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigatorCoordinator = remember { getNavigationCoordinator() }
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
@ -94,9 +94,6 @@ class ManageSubscriptionsScreen : Screen {
} }
Scaffold( Scaffold(
modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { title = {
@ -111,7 +108,7 @@ class ManageSubscriptionsScreen : Screen {
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigatorCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,
@ -136,7 +133,7 @@ class ManageSubscriptionsScreen : Screen {
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ExpandLess, icon = Icons.Default.ExpandLess,
text = stringResource(MR.strings.action_back_to_top), text = stringResource(MR.strings.action_back_to_top),
onSelected = { onSelected = rememberCallback {
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
topAppBarState.heightOffset = 0f topAppBarState.heightOffset = 0f
@ -156,7 +153,10 @@ class ManageSubscriptionsScreen : Screen {
}, },
) )
Box( Box(
modifier = Modifier.padding(paddingValues) modifier = Modifier
.padding(paddingValues)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
@ -178,7 +178,9 @@ class ManageSubscriptionsScreen : Screen {
Icon( Icon(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.push(MultiCommunityEditorScreen()) navigatorCoordinator.getRootNavigator()?.push(
MultiCommunityEditorScreen()
)
}, },
), ),
imageVector = Icons.Default.AddCircle, imageVector = Icons.Default.AddCircle,
@ -187,7 +189,7 @@ class ManageSubscriptionsScreen : Screen {
) )
} }
} }
itemsIndexed(uiState.multiCommunities) { idx, community -> items(uiState.multiCommunities) { community ->
val endColor = MaterialTheme.colorScheme.secondary val endColor = MaterialTheme.colorScheme.secondary
val startColor = MaterialTheme.colorScheme.tertiary val startColor = MaterialTheme.colorScheme.tertiary
SwipeableCard( SwipeableCard(
@ -203,13 +205,15 @@ class ManageSubscriptionsScreen : Screen {
model.reduce(ManageSubscriptionsMviModel.Intent.HapticIndication) model.reduce(ManageSubscriptionsMviModel.Intent.HapticIndication)
}, },
onDismissToStart = rememberCallback { onDismissToStart = rememberCallback {
navigator?.push( navigatorCoordinator.getRootNavigator()?.push(
MultiCommunityEditorScreen(community), MultiCommunityEditorScreen(community),
) )
}, },
onDismissToEnd = rememberCallback(model) { onDismissToEnd = rememberCallback(model) {
model.reduce( model.reduce(
ManageSubscriptionsMviModel.Intent.DeleteMultiCommunity(idx), ManageSubscriptionsMviModel.Intent.DeleteMultiCommunity(
(community.id ?: 0).toInt()
),
) )
}, },
swipeContent = { direction -> swipeContent = { direction ->
@ -229,7 +233,7 @@ class ManageSubscriptionsScreen : Screen {
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
.background(MaterialTheme.colorScheme.background).onClick( .background(MaterialTheme.colorScheme.background).onClick(
rememberCallback { rememberCallback {
navigator?.push( navigatorCoordinator.getRootNavigator()?.push(
MultiCommunityScreen(community), MultiCommunityScreen(community),
) )
}, },
@ -252,7 +256,7 @@ class ManageSubscriptionsScreen : Screen {
) )
} }
} }
itemsIndexed(uiState.communities) { idx, community -> items(uiState.communities) { community ->
val endColor = MaterialTheme.colorScheme.secondary val endColor = MaterialTheme.colorScheme.secondary
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@ -268,7 +272,7 @@ class ManageSubscriptionsScreen : Screen {
}, },
onDismissToStart = rememberCallback(model) { onDismissToStart = rememberCallback(model) {
model.reduce( model.reduce(
ManageSubscriptionsMviModel.Intent.Unsubscribe(idx), ManageSubscriptionsMviModel.Intent.Unsubscribe(community.id),
) )
}, },
swipeContent = { _ -> swipeContent = { _ ->
@ -285,7 +289,7 @@ class ManageSubscriptionsScreen : Screen {
.background(MaterialTheme.colorScheme.background) .background(MaterialTheme.colorScheme.background)
.onClick( .onClick(
rememberCallback { rememberCallback {
navigator?.push( navigatorCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },

View File

@ -63,11 +63,13 @@ class ManageSubscriptionsViewModel(
ManageSubscriptionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate() ManageSubscriptionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
ManageSubscriptionsMviModel.Intent.Refresh -> refresh() ManageSubscriptionsMviModel.Intent.Refresh -> refresh()
is ManageSubscriptionsMviModel.Intent.Unsubscribe -> handleUnsubscription( is ManageSubscriptionsMviModel.Intent.Unsubscribe -> handleUnsubscription(
community = uiState.value.communities[intent.index], community = uiState.value.communities.first { it.id == intent.id },
) )
is ManageSubscriptionsMviModel.Intent.DeleteMultiCommunity -> deleteMultiCommunity( is ManageSubscriptionsMviModel.Intent.DeleteMultiCommunity -> deleteMultiCommunity(
community = uiState.value.multiCommunities[intent.index], community = uiState.value.multiCommunities.first {
(it.id ?: 0).toInt() == intent.id
},
) )
} }
} }

View File

@ -14,12 +14,12 @@ interface MultiCommunityMviModel :
data object LoadNextPage : Intent data object LoadNextPage : Intent
data class ChangeSort(val value: SortType) : Intent data class ChangeSort(val value: SortType) : Intent
data object HapticIndication : Intent data object HapticIndication : Intent
data class UpVotePost(val index: Int, val feedback: Boolean = false) : Intent data class UpVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class DownVotePost(val index: Int, val feedback: Boolean = false) : Intent data class DownVotePost(val id: Int, val feedback: Boolean = false) : Intent
data class SavePost(val index: Int, val feedback: Boolean = false) : Intent data class SavePost(val id: Int, val feedback: Boolean = false) : Intent
data class SharePost(val index: Int) : Intent data class SharePost(val id: Int) : Intent
data class MarkAsRead(val index: Int) : Intent data class MarkAsRead(val id: Int) : Intent
data class Hide(val index: Int) : Intent data class Hide(val id: Int) : Intent
data object ClearRead : Intent data object ClearRead : Intent
} }

View File

@ -13,7 +13,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -39,6 +39,7 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -53,7 +54,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
@ -76,6 +76,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDet
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.MultiCommunityModel
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
@ -95,11 +96,9 @@ class MultiCommunityScreen(
val model = rememberScreenModel { getMultiCommunityViewModel(community) } val model = rememberScreenModel { getMultiCommunityViewModel(community) }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val bottomNavCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { bottomNavCoordinator.getRootNavigator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
val upvoteColor by themeRepository.upvoteColor.collectAsState() val upvoteColor by themeRepository.upvoteColor.collectAsState()
@ -111,6 +110,9 @@ class MultiCommunityScreen(
val fabNestedScrollConnection = remember { getFabNestedScrollConnection() } val fabNestedScrollConnection = remember { getFabNestedScrollConnection() }
val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState() val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState()
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
DisposableEffect(key) { DisposableEffect(key) {
drawerCoordinator.setGesturesEnabled(false) drawerCoordinator.setGesturesEnabled(false)
onDispose { onDispose {
@ -118,12 +120,28 @@ class MultiCommunityScreen(
drawerCoordinator.setGesturesEnabled(true) drawerCoordinator.setGesturesEnabled(true)
} }
} }
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
MultiCommunityMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
model.reduce(MultiCommunityMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
}
Scaffold( Scaffold(
modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection),
topBar = { topBar = {
val sortType = uiState.sortType val sortType = uiState.sortType
TopAppBar( TopAppBar(
@ -139,7 +157,7 @@ class MultiCommunityScreen(
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,
@ -176,16 +194,7 @@ class MultiCommunityScreen(
val sheet = SortBottomSheet( val sheet = SortBottomSheet(
expandTop = true, expandTop = true,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
MultiCommunityMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
), ),
imageVector = sortType.toIcon(), imageVector = sortType.toIcon(),
@ -212,7 +221,7 @@ class MultiCommunityScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ExpandLess, icon = Icons.Default.ExpandLess,
text = stringResource(MR.strings.action_back_to_top), text = stringResource(MR.strings.action_back_to_top),
onSelected = { onSelected = rememberCallback {
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
topAppBarState.heightOffset = 0f topAppBarState.heightOffset = 0f
@ -223,7 +232,7 @@ class MultiCommunityScreen(
this += FloatingActionButtonMenuItem( this += FloatingActionButtonMenuItem(
icon = Icons.Default.ClearAll, icon = Icons.Default.ClearAll,
text = stringResource(MR.strings.action_clear_read), text = stringResource(MR.strings.action_clear_read),
onSelected = { onSelected = rememberCallback {
model.reduce(MultiCommunityMviModel.Intent.ClearRead) model.reduce(MultiCommunityMviModel.Intent.ClearRead)
scope.launch { scope.launch {
lazyListState.scrollToItem(0) lazyListState.scrollToItem(0)
@ -245,6 +254,14 @@ class MultiCommunityScreen(
modifier = Modifier modifier = Modifier
.padding(padding) .padding(padding)
.fillMaxWidth() .fillMaxWidth()
.let {
if (settings.hideNavigationBarWhileScrolling) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
it
}
}
.nestedScroll(fabNestedScrollConnection)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
@ -262,7 +279,7 @@ class MultiCommunityScreen(
} }
} }
} }
itemsIndexed(uiState.posts) { idx, post -> items(uiState.posts) { post ->
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled, enabled = uiState.swipeActionsEnabled,
@ -281,10 +298,10 @@ class MultiCommunityScreen(
model.reduce(MultiCommunityMviModel.Intent.HapticIndication) model.reduce(MultiCommunityMviModel.Intent.HapticIndication)
}, },
onDismissToStart = { onDismissToStart = {
model.reduce(MultiCommunityMviModel.Intent.UpVotePost(idx)) model.reduce(MultiCommunityMviModel.Intent.UpVotePost(post.id))
}, },
onDismissToEnd = { onDismissToEnd = {
model.reduce(MultiCommunityMviModel.Intent.DownVotePost(idx)) model.reduce(MultiCommunityMviModel.Intent.DownVotePost(post.id))
}, },
swipeContent = { direction -> swipeContent = { direction ->
val icon = when (direction) { val icon = when (direction) {
@ -306,25 +323,25 @@ class MultiCommunityScreen(
autoLoadImages = uiState.autoLoadImages, autoLoadImages = uiState.autoLoadImages,
blurNsfw = uiState.blurNsfw, blurNsfw = uiState.blurNsfw,
onClick = { onClick = {
model.reduce(MultiCommunityMviModel.Intent.MarkAsRead(idx)) model.reduce(MultiCommunityMviModel.Intent.MarkAsRead(post.id))
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
PostDetailScreen(post), PostDetailScreen(post),
) )
}, },
onOpenCommunity = { community -> onOpenCommunity = { community ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen(community), CommunityDetailScreen(community),
) )
}, },
onOpenCreator = { user -> onOpenCreator = { user ->
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
UserDetailScreen(user), UserDetailScreen(user),
) )
}, },
onUpVote = { onUpVote = {
model.reduce( model.reduce(
MultiCommunityMviModel.Intent.UpVotePost( MultiCommunityMviModel.Intent.UpVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -332,7 +349,7 @@ class MultiCommunityScreen(
onDownVote = { onDownVote = {
model.reduce( model.reduce(
MultiCommunityMviModel.Intent.DownVotePost( MultiCommunityMviModel.Intent.DownVotePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -340,7 +357,7 @@ class MultiCommunityScreen(
onSave = { onSave = {
model.reduce( model.reduce(
MultiCommunityMviModel.Intent.SavePost( MultiCommunityMviModel.Intent.SavePost(
index = idx, id = post.id,
feedback = true, feedback = true,
), ),
) )
@ -349,18 +366,11 @@ class MultiCommunityScreen(
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = post, originalPost = post,
) )
notificationCenter.addObserver( navigationCoordinator.getBottomNavigator()?.show(screen)
{
model.reduce(MultiCommunityMviModel.Intent.Refresh)
},
key,
NotificationCenterContractKeys.CommentCreated
)
bottomSheetNavigator.show(screen)
}, },
onImageClick = { url -> onImageClick = { url ->
model.reduce(MultiCommunityMviModel.Intent.MarkAsRead(idx)) model.reduce(MultiCommunityMviModel.Intent.MarkAsRead(post.id))
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
ZoomableImageScreen(url), ZoomableImageScreen(url),
) )
}, },
@ -372,16 +382,21 @@ class MultiCommunityScreen(
onOptionSelected = { optionIdx -> onOptionSelected = { optionIdx ->
when (optionIdx) { when (optionIdx) {
2 -> { 2 -> {
bottomSheetNavigator.show( navigationCoordinator.getBottomNavigator()?.show(
CreateReportScreen( CreateReportScreen(
postId = post.id postId = post.id
) )
) )
} }
1 -> model.reduce(MultiCommunityMviModel.Intent.Hide(idx)) 1 -> model.reduce(
MultiCommunityMviModel.Intent.Hide(
post.id
)
)
else -> model.reduce( else -> model.reduce(
MultiCommunityMviModel.Intent.SharePost(idx) MultiCommunityMviModel.Intent.SharePost(post.id)
) )
} }
} }

View File

@ -89,7 +89,7 @@ class MultiCommunityViewModel(
when (intent) { when (intent) {
is MultiCommunityMviModel.Intent.ChangeSort -> applySortType(intent.value) is MultiCommunityMviModel.Intent.ChangeSort -> applySortType(intent.value)
is MultiCommunityMviModel.Intent.DownVotePost -> toggleDownVote( is MultiCommunityMviModel.Intent.DownVotePost -> toggleDownVote(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
@ -97,19 +97,25 @@ class MultiCommunityViewModel(
MultiCommunityMviModel.Intent.LoadNextPage -> loadNextPage() MultiCommunityMviModel.Intent.LoadNextPage -> loadNextPage()
MultiCommunityMviModel.Intent.Refresh -> refresh() MultiCommunityMviModel.Intent.Refresh -> refresh()
is MultiCommunityMviModel.Intent.SavePost -> toggleSave( is MultiCommunityMviModel.Intent.SavePost -> toggleSave(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
is MultiCommunityMviModel.Intent.SharePost -> share(post = uiState.value.posts[intent.index]) is MultiCommunityMviModel.Intent.SharePost -> share(
post = uiState.value.posts.first { it.id == intent.id }
)
is MultiCommunityMviModel.Intent.UpVotePost -> toggleUpVote( is MultiCommunityMviModel.Intent.UpVotePost -> toggleUpVote(
post = uiState.value.posts[intent.index], post = uiState.value.posts.first { it.id == intent.id },
feedback = intent.feedback, feedback = intent.feedback,
) )
MultiCommunityMviModel.Intent.ClearRead -> clearRead() MultiCommunityMviModel.Intent.ClearRead -> clearRead()
is MultiCommunityMviModel.Intent.MarkAsRead -> markAsRead(post = uiState.value.posts[intent.index]) is MultiCommunityMviModel.Intent.MarkAsRead -> markAsRead(
is MultiCommunityMviModel.Intent.Hide -> hide(post = uiState.value.posts[intent.index]) post = uiState.value.posts.first { it.id == intent.id })
is MultiCommunityMviModel.Intent.Hide -> hide(
post = uiState.value.posts.first { it.id == intent.id })
} }
} }
@ -140,7 +146,7 @@ class MultiCommunityViewModel(
currentIds = if (refreshing) emptyList() else currentState.posts.map { it.id } currentIds = if (refreshing) emptyList() else currentState.posts.map { it.id }
) )
val canFetchMore = paginator.canFetchMore val canFetchMore = paginator.canFetchMore
val itemsToAdd = itemList.orEmpty().filter { post -> val itemsToAdd = itemList.filter { post ->
if (includeNsfw) { if (includeNsfw) {
true true
} else { } else {

View File

@ -12,7 +12,7 @@ interface MultiCommunityEditorMviModel :
data class SetName(val value: String) : Intent data class SetName(val value: String) : Intent
data class SetSearch(val value: String) : Intent data class SetSearch(val value: String) : Intent
data class SelectImage(val index: Int?) : Intent data class SelectImage(val index: Int?) : Intent
data class ToggleCommunity(val index: Int) : Intent data class ToggleCommunity(val id: Int) : Intent
data object Submit : Intent data object Submit : Intent
} }

View File

@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@ -81,13 +82,13 @@ class MultiCommunityEditorScreen(
val model = rememberScreenModel { getMultiCommunityEditorViewModel(editedCommunity) } val model = rememberScreenModel { getMultiCommunityEditorViewModel(editedCommunity) }
model.bindToLifecycle(key) model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
LaunchedEffect(model) { LaunchedEffect(model) {
model.effects.onEach { model.effects.onEach {
when (it) { when (it) {
MultiCommunityEditorMviModel.Effect.Close -> { MultiCommunityEditorMviModel.Effect.Close -> {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
} }
} }
}.launchIn(this) }.launchIn(this)
@ -114,7 +115,7 @@ class MultiCommunityEditorScreen(
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
rememberCallback { rememberCallback {
navigator?.pop() navigationCoordinator.getRootNavigator()?.pop()
}, },
), ),
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,
@ -326,7 +327,7 @@ class MultiCommunityEditorScreen(
.weight(1f), .weight(1f),
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
itemsIndexed(uiState.communities) { idx, communityItem -> items(uiState.communities) { communityItem ->
val community = communityItem.first val community = communityItem.first
val selected = communityItem.second val selected = communityItem.second
Row( Row(
@ -342,7 +343,7 @@ class MultiCommunityEditorScreen(
onCheckedChange = { onCheckedChange = {
model.reduce( model.reduce(
MultiCommunityEditorMviModel.Intent.ToggleCommunity( MultiCommunityEditorMviModel.Intent.ToggleCommunity(
idx community.id
) )
) )
}, },

View File

@ -52,7 +52,7 @@ class MultiCommunityEditorViewModel(
when (intent) { when (intent) {
is MultiCommunityEditorMviModel.Intent.SelectImage -> selectImage(intent.index) is MultiCommunityEditorMviModel.Intent.SelectImage -> selectImage(intent.index)
is MultiCommunityEditorMviModel.Intent.SetName -> mvi.updateState { it.copy(name = intent.value) } is MultiCommunityEditorMviModel.Intent.SetName -> mvi.updateState { it.copy(name = intent.value) }
is MultiCommunityEditorMviModel.Intent.ToggleCommunity -> toggleCommunity(intent.index) 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()
} }
@ -109,10 +109,9 @@ class MultiCommunityEditorViewModel(
mvi.updateState { it.copy(icon = image) } mvi.updateState { it.copy(icon = image) }
} }
private fun toggleCommunity(index: Int) { private fun toggleCommunity(communityId: Int) {
val toggledCommunity = uiState.value.communities[index]
val newCommunities = communities.map { item -> val newCommunities = communities.map { item ->
if (item.first.id == toggledCommunity.first.id) { if (item.first.id == communityId) {
item.first to !item.second item.first to !item.second
} else { } else {
item item

View File

@ -65,7 +65,7 @@ class AboutDialog : Screen {
viewModel.bindToLifecycle(key) viewModel.bindToLifecycle(key)
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val settingsRepository = remember { getSettingsRepository() } val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState() val settings by settingsRepository.currentSettings.collectAsState()
val uiState by viewModel.uiState.collectAsState() val uiState by viewModel.uiState.collectAsState()
@ -75,7 +75,7 @@ class AboutDialog : Screen {
viewModel.effects.onEach { effect -> viewModel.effects.onEach { effect ->
when (effect) { when (effect) {
is AboutDialogMviModel.Effect.OpenCommunity -> { is AboutDialogMviModel.Effect.OpenCommunity -> {
navigator?.push( navigationCoordinator.getRootNavigator()?.push(
CommunityDetailScreen( CommunityDetailScreen(
community = effect.community, community = effect.community,
otherInstance = effect.instance, otherInstance = effect.instance,
@ -126,7 +126,7 @@ class AboutDialog : Screen {
url = CHANGELOG_URL, url = CHANGELOG_URL,
openExternal = settings.openUrlsInExternalBrowser, openExternal = settings.openUrlsInExternalBrowser,
uriHandler = uriHandler, uriHandler = uriHandler,
navigator = navigator, navigator = navigationCoordinator.getRootNavigator(),
) )
} }
) )
@ -138,7 +138,7 @@ class AboutDialog : Screen {
url = REPORT_URL, url = REPORT_URL,
openExternal = settings.openUrlsInExternalBrowser, openExternal = settings.openUrlsInExternalBrowser,
uriHandler = uriHandler, uriHandler = uriHandler,
navigator = navigator, navigator = navigationCoordinator.getRootNavigator(),
) )
}, },
) { ) {
@ -170,7 +170,7 @@ class AboutDialog : Screen {
url = WEBSITE_URL, url = WEBSITE_URL,
openExternal = settings.openUrlsInExternalBrowser, openExternal = settings.openUrlsInExternalBrowser,
uriHandler = uriHandler, uriHandler = uriHandler,
navigator = navigator, navigator = navigationCoordinator.getRootNavigator(),
) )
}, },
) )

View File

@ -39,7 +39,6 @@ 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.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.FontScale import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.FontScale
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
@ -95,36 +94,20 @@ class SettingsScreen : Screen {
val model = rememberScreenModel { getSettingsViewModel() } val model = rememberScreenModel { getSettingsViewModel() }
model.bindToLifecycle(SettingsTab.key) model.bindToLifecycle(SettingsTab.key)
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
val drawerCoordinator = remember { getDrawerCoordinator() } val drawerCoordinator = remember { getDrawerCoordinator() }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
LaunchedEffect(navigator) {
navigationCoordinator.onDoubleTabSelection.onEach { tab ->
if (tab == SettingsTab) {
scrollState.scrollTo(0)
topAppBarState.heightOffset = 0f
topAppBarState.contentOffset = 0f
}
}.launchIn(this)
}
DisposableEffect(key) {
onDispose {
notificationCenter.removeObserver(key)
}
}
val languageRepository = remember { getLanguageRepository() } val languageRepository = remember { getLanguageRepository() }
val lang by languageRepository.currentLanguage.collectAsState() val lang by languageRepository.currentLanguage.collectAsState()
var uiFontSizeWorkaround by remember { mutableStateOf(true) } var uiFontSizeWorkaround by remember { mutableStateOf(true) }
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
var upvoteColorDialogOpened by remember { mutableStateOf(false) }
var downvoteColorDialogOpened by remember { mutableStateOf(false) }
var infoDialogOpened by remember { mutableStateOf(false) }
LaunchedEffect(themeRepository) { LaunchedEffect(themeRepository) {
themeRepository.uiFontScale.drop(1).onEach { themeRepository.uiFontScale.drop(1).onEach {
@ -133,12 +116,131 @@ class SettingsScreen : Screen {
uiFontSizeWorkaround = true uiFontSizeWorkaround = true
}.launchIn(this) }.launchIn(this)
} }
LaunchedEffect(Unit) {
navigationCoordinator.onDoubleTabSelection.onEach { tab ->
if (tab == SettingsTab) {
scrollState.scrollTo(0)
topAppBarState.heightOffset = 0f
topAppBarState.contentOffset = 0f
}
}.launchIn(this)
}
DisposableEffect(key) {
onDispose {
notificationCenter.removeObserver(key)
}
}
LaunchedEffect(notificationCenter) {
notificationCenter.addObserver(
{ result ->
(result as? String)?.also { lang ->
model.reduce(SettingsMviModel.Intent.ChangeLanguage(lang))
}
}, key, NotificationCenterContractKeys.ChangeLanguage
)
notificationCenter.addObserver(
{ result ->
(result as? UiTheme)?.also { value ->
model.reduce(SettingsMviModel.Intent.ChangeUiTheme(value))
}
}, key, NotificationCenterContractKeys.ChangeTheme
)
notificationCenter.addObserver(
{ result ->
model.reduce(
SettingsMviModel.Intent.ChangeCustomSeedColor(
result as? Color?
)
)
}, key, NotificationCenterContractKeys.ChangeColor
)
notificationCenter.addObserver(
{ result ->
(result as? UiFontFamily)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangeUiFontFamily(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangeFontFamily
)
notificationCenter.addObserver(
{ result ->
(result as? Float)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangeUiFontSize(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangeFontSize
)
notificationCenter.addObserver(
{ result ->
(result as? Float)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangeContentFontSize(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangeFontSize
)
notificationCenter.addObserver(
{ result ->
(result as? PostLayout)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangePostLayout(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangePostLayout
)
notificationCenter.addObserver(
{ result ->
(result as? ListingType)?.also {
model.reduce(
SettingsMviModel.Intent.ChangeDefaultListingType(
it
)
)
}
}, key, NotificationCenterContractKeys.ChangeFeedType
)
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
SettingsMviModel.Intent.ChangeDefaultPostSortType(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
(it as? SortType)?.also { sortType ->
model.reduce(
SettingsMviModel.Intent.ChangeDefaultCommentSortType(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType
)
notificationCenter.addObserver(
{
infoDialogOpened = false
}, key, NotificationCenterContractKeys.CloseDialog
)
}
if (!uiFontSizeWorkaround) { if (!uiFontSizeWorkaround) {
return return
} }
var upvoteColorDialogOpened by remember { mutableStateOf(false) }
var downvoteColorDialogOpened by remember { mutableStateOf(false) }
var infoDialogOpened by remember { mutableStateOf(false) }
Scaffold( Scaffold(
modifier = Modifier.padding(Spacing.xxs), modifier = Modifier.padding(Spacing.xxs),
@ -194,12 +296,7 @@ class SettingsScreen : Screen {
value = uiState.lang.toLanguageName(), value = uiState.lang.toLanguageName(),
onTap = rememberCallback { onTap = rememberCallback {
val sheet = LanguageBottomSheet() val sheet = LanguageBottomSheet()
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? String)?.also { lang ->
model.reduce(SettingsMviModel.Intent.ChangeLanguage(lang))
}
}, key, NotificationCenterContractKeys.ChangeLanguage)
bottomSheetNavigator.show(sheet)
}, },
) )
@ -209,12 +306,7 @@ class SettingsScreen : Screen {
value = uiState.uiTheme.toReadableName(), value = uiState.uiTheme.toReadableName(),
onTap = rememberCallback { onTap = rememberCallback {
val sheet = ThemeBottomSheet() val sheet = ThemeBottomSheet()
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? UiTheme)?.also { value ->
model.reduce(SettingsMviModel.Intent.ChangeUiTheme(value))
}
}, key, NotificationCenterContractKeys.ChangeTheme)
bottomSheetNavigator.show(sheet)
}, },
) )
@ -243,14 +335,7 @@ class SettingsScreen : Screen {
).primary, ).primary,
onTap = rememberCallback { onTap = rememberCallback {
val sheet = ColorBottomSheet() val sheet = ColorBottomSheet()
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
model.reduce(
SettingsMviModel.Intent.ChangeCustomSeedColor(
result as? Color?
)
)
}, key, NotificationCenterContractKeys.ChangeColor)
bottomSheetNavigator.show(sheet)
}, },
) )
// upvote and downvote colors // upvote and downvote colors
@ -275,16 +360,7 @@ class SettingsScreen : Screen {
value = uiState.uiFontFamily.toReadableName(), value = uiState.uiFontFamily.toReadableName(),
onTap = rememberCallback { onTap = rememberCallback {
val sheet = FontFamilyBottomSheet() val sheet = FontFamilyBottomSheet()
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? UiFontFamily)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangeUiFontFamily(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangeFontFamily)
bottomSheetNavigator.show(sheet)
}, },
) )
// font scale // font scale
@ -299,16 +375,7 @@ class SettingsScreen : Screen {
FontScale.Small, FontScale.Small,
), ),
) )
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? Float)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangeUiFontSize(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangeFontSize)
bottomSheetNavigator.show(sheet)
}, },
) )
SettingsRow( SettingsRow(
@ -316,16 +383,7 @@ class SettingsScreen : Screen {
value = uiState.contentFontScale.toReadableName(), value = uiState.contentFontScale.toReadableName(),
onTap = rememberCallback { onTap = rememberCallback {
val sheet = FontScaleBottomSheet() val sheet = FontScaleBottomSheet()
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? Float)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangeContentFontSize(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangeFontSize)
bottomSheetNavigator.show(sheet)
}, },
) )
@ -335,16 +393,7 @@ class SettingsScreen : Screen {
value = uiState.postLayout.toReadableName(), value = uiState.postLayout.toReadableName(),
onTap = rememberCallback { onTap = rememberCallback {
val sheet = PostLayoutBottomSheet() val sheet = PostLayoutBottomSheet()
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? PostLayout)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangePostLayout(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangePostLayout)
bottomSheetNavigator.show(sheet)
}, },
) )
@ -400,16 +449,7 @@ class SettingsScreen : Screen {
val sheet = ListingTypeBottomSheet( val sheet = ListingTypeBottomSheet(
isLogged = uiState.isLogged, isLogged = uiState.isLogged,
) )
notificationCenter.addObserver({ result -> navigationCoordinator.getBottomNavigator()?.show(sheet)
(result as? ListingType)?.also {
model.reduce(
SettingsMviModel.Intent.ChangeDefaultListingType(
it
)
)
}
}, key, NotificationCenterContractKeys.ChangeFeedType)
bottomSheetNavigator.show(sheet)
}, },
) )
@ -421,16 +461,7 @@ class SettingsScreen : Screen {
val sheet = SortBottomSheet( val sheet = SortBottomSheet(
expandTop = true, expandTop = true,
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
SettingsMviModel.Intent.ChangeDefaultPostSortType(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
) )
@ -448,16 +479,7 @@ class SettingsScreen : Screen {
SortType.Controversial, SortType.Controversial,
), ),
) )
notificationCenter.addObserver({ navigationCoordinator.getBottomNavigator()?.show(sheet)
(it as? SortType)?.also { sortType ->
model.reduce(
SettingsMviModel.Intent.ChangeDefaultCommentSortType(
sortType
)
)
}
}, key, NotificationCenterContractKeys.ChangeSortType)
bottomSheetNavigator.show(sheet)
}, },
) )
@ -623,9 +645,6 @@ class SettingsScreen : Screen {
} }
if (infoDialogOpened) { if (infoDialogOpened) {
notificationCenter.addObserver({
infoDialogOpened = false
}, key, NotificationCenterContractKeys.CloseDialog)
AboutDialog().Content() AboutDialog().Content()
} }
} }

View File

@ -208,6 +208,6 @@
<string name="settings_ui_font_scale">Dimensione testo UI</string> <string name="settings_ui_font_scale">Dimensione testo UI</string>
<string name="settings_ui_theme">Tema interfaccia</string> <string name="settings_ui_theme">Tema interfaccia</string>
<string name="settings_upvote_color">Colore voti positivi</string> <string name="settings_upvote_color">Colore voti positivi</string>
<string name="settings_hide_navigation_bar">Nascondi barra di navigation durante lo scroll <string name="settings_hide_navigation_bar">Nascondi barra di navigazione durante lo scroll
</string> </string>
</resources> </resources>

View File

@ -227,7 +227,9 @@ fun App() {
topEnd = CornerSize.xl topEnd = CornerSize.xl
), ),
sheetBackgroundColor = MaterialTheme.colorScheme.background, sheetBackgroundColor = MaterialTheme.colorScheme.background,
) { ) { bottomNavigator ->
navigationCoordinator.setBottomNavigator(bottomNavigator)
ModalNavigationDrawer( ModalNavigationDrawer(
drawerState = drawerState, drawerState = drawerState,
gesturesEnabled = drawerGestureEnabled, gesturesEnabled = drawerGestureEnabled,

View File

@ -84,8 +84,8 @@ internal object MainScreen : Screen {
} }
} }
TabNavigator(HomeTab) { TabNavigator(HomeTab) { tabNavigator ->
LaunchedEffect(it.current) { LaunchedEffect(tabNavigator.current) {
// when the current tab chanes, reset the bottom bar offset to the default value // when the current tab chanes, reset the bottom bar offset to the default value
model.reduce(MainScreenMviModel.Intent.SetBottomBarOffsetHeightPx(0f)) model.reduce(MainScreenMviModel.Intent.SetBottomBarOffsetHeightPx(0f))
} }