fix(navigation): refresh after new post and comment with notification

This commit is contained in:
Diego Beraldin 2023-09-12 13:51:51 +02:00
parent b707bd3e59
commit 9f59398ec6
14 changed files with 78 additions and 110 deletions

View File

@ -85,7 +85,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImag
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
@ -140,8 +139,8 @@ class CommunityDetailScreen(
}
}
Scaffold(
modifier = Modifier.background(MaterialTheme.colorScheme.surface).padding(Spacing.xs),
Scaffold(modifier = Modifier.background(MaterialTheme.colorScheme.surface)
.padding(Spacing.xs),
topBar = {
val communityName = community.name
val communityHost = community.host
@ -168,7 +167,11 @@ class CommunityDetailScreen(
)
notificationCenter.addObserver({
(it as? SortType)?.also { sortType ->
model.reduce(CommunityDetailMviModel.Intent.ChangeSort(sortType))
model.reduce(
CommunityDetailMviModel.Intent.ChangeSort(
sortType
)
)
}
}, key, sheet.key)
bottomSheetNavigator.show(sheet)
@ -204,11 +207,13 @@ class CommunityDetailScreen(
backgroundColor = MaterialTheme.colorScheme.secondary,
shape = CircleShape,
onClick = {
bottomSheetNavigator.show(
CreatePostScreen(
communityId = community.id,
),
val screen = CreatePostScreen(
communityId = community.id,
)
notificationCenter.addObserver({
model.reduce(CommunityDetailMviModel.Intent.Refresh)
}, key, screen.key)
bottomSheetNavigator.show(screen)
},
content = {
Icon(
@ -218,16 +223,13 @@ class CommunityDetailScreen(
},
)
}
}
) { padding ->
}) { padding ->
val pullRefreshState = rememberPullRefreshState(uiState.refreshing, {
model.reduce(CommunityDetailMviModel.Intent.Refresh)
})
Box(
modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection)
.padding(padding)
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection).padding(padding)
.pullRefresh(pullRefreshState),
) {
LazyColumn(
@ -265,18 +267,13 @@ class CommunityDetailScreen(
)
}
Icon(
modifier = Modifier
.padding(
modifier = Modifier.padding(
top = Spacing.s,
end = Spacing.s,
)
.background(
).background(
color = MaterialTheme.colorScheme.primary,
shape = CircleShape,
)
.padding(Spacing.s)
.align(Alignment.TopEnd)
.onClick {
).padding(Spacing.s).align(Alignment.TopEnd).onClick {
optionsExpanded = true
},
imageVector = Icons.Rounded.MoreVert,
@ -329,8 +326,7 @@ class CommunityDetailScreen(
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
if (communityIcon.isNotEmpty()) {
val painterResource =
asyncPainterResource(data = communityIcon)
val painterResource = asyncPainterResource(data = communityIcon)
KamelImage(
modifier = Modifier.padding(Spacing.xxxs).size(iconSize)
.clip(RoundedCornerShape(iconSize / 2)),
@ -363,8 +359,7 @@ class CommunityDetailScreen(
)
if (!isOnOtherInstance) {
Button(
modifier = Modifier
.align(Alignment.CenterHorizontally)
modifier = Modifier.align(Alignment.CenterHorizontally)
.padding(top = Spacing.m),
onClick = {
when (community.subscribed) {
@ -530,11 +525,13 @@ class CommunityDetailScreen(
}
},
onReply = {
bottomSheetNavigator.show(
CreateCommentScreen(
originalPost = Json.encodeToString(post),
),
val screen = CreateCommentScreen(
originalPost = Json.encodeToString(post),
)
notificationCenter.addObserver({
model.reduce(CommunityDetailMviModel.Intent.Refresh)
}, key, screen.key)
bottomSheetNavigator.show(screen)
},
onImageClick = { url ->
navigator?.push(

View File

@ -29,7 +29,6 @@ class CommunityDetailViewModel(
private val postsRepository: PostsRepository,
private val keyStore: TemporaryKeyStore,
private val hapticFeedback: HapticFeedback,
private val notificationCenter: NotificationCenter,
) : MviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect> by mvi,
ScreenModel {
private var currentPage: Int = 1
@ -44,17 +43,6 @@ class CommunityDetailViewModel(
blurNsfw = keyStore[KeyStoreKeys.BlurNsfw, true],
)
}
mvi.scope.launch {
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.PostCreated -> {
refresh()
}
else -> Unit
}
}
}
if (mvi.uiState.value.posts.isEmpty()) {
refresh()

View File

@ -18,7 +18,6 @@ class CreateCommentViewModel(
),
private val identityRepository: IdentityRepository,
private val commentRepository: CommentRepository,
private val notificationCenter: NotificationCenter,
) : ScreenModel,
MviModel<CreateCommentMviModel.Intent, CreateCommentMviModel.UiState, CreateCommentMviModel.Effect> by mvi {
@ -46,7 +45,6 @@ class CreateCommentViewModel(
auth = auth,
)
mvi.emitEffect(CreateCommentMviModel.Effect.Success)
notificationCenter.send(NotificationCenter.Event.CommentCreated)
} catch (e: Throwable) {
val message = e.message
mvi.emitEffect(CreateCommentMviModel.Effect.Failure(message))

View File

@ -1,8 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -10,8 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
@ -47,6 +43,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
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.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.flow.launchIn
@ -64,6 +61,7 @@ class CreatePostScreen(
val snackbarHostState = remember { SnackbarHostState() }
val genericError = stringResource(MR.strings.message_generic_error)
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
val notificationCenter = remember { getNotificationCenter() }
LaunchedEffect(model) {
model.effects.onEach {
@ -73,6 +71,7 @@ class CreatePostScreen(
}
CreatePostMviModel.Effect.Success -> {
notificationCenter.getObserver(key)?.also { o -> o.invoke(Unit) }
navigator?.pop()
}
}

View File

@ -17,7 +17,6 @@ class CreatePostViewModel(
),
private val identityRepository: IdentityRepository,
private val postsRepository: PostsRepository,
private val notificationCenter: NotificationCenter,
) : ScreenModel,
MviModel<CreatePostMviModel.Intent, CreatePostMviModel.UiState, CreatePostMviModel.Effect> by mvi {
@ -55,7 +54,6 @@ class CreatePostViewModel(
} catch (e: Throwable) {
val message = e.message
mvi.emitEffect(CreatePostMviModel.Effect.Failure(message))
notificationCenter.send(NotificationCenter.Event.PostCreated)
}
}
}

View File

@ -47,7 +47,6 @@ val commonUiModule = module {
postsRepository = get(),
keyStore = get(),
hapticFeedback = get(),
notificationCenter = get(),
)
}
factory { params ->
@ -71,7 +70,6 @@ val commonUiModule = module {
postsRepository = get(),
hapticFeedback = get(),
keyStore = get(),
notificationCenter = get(),
)
}
factory {
@ -100,7 +98,6 @@ val commonUiModule = module {
parentId = params[1],
identityRepository = get(),
commentRepository = get(),
notificationCenter = get(),
)
}
factory { params ->
@ -108,7 +105,6 @@ val commonUiModule = module {
communityId = params[0],
identityRepository = get(),
postsRepository = get(),
notificationCenter = get(),
)
}
}

View File

@ -80,7 +80,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCo
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getPostDetailViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
@ -191,11 +190,13 @@ class PostDetailScreen(
shape = CircleShape,
backgroundColor = MaterialTheme.colorScheme.secondary,
onClick = {
bottomSheetNavigator.show(
CreateCommentScreen(
originalPost = Json.encodeToString(post),
),
val screen = CreateCommentScreen(
originalPost = Json.encodeToString(post),
)
notificationCenter.addObserver({
model.reduce(PostDetailMviModel.Intent.Refresh)
}, key, screen.key)
bottomSheetNavigator.show(screen)
},
content = {
Icon(
@ -396,12 +397,14 @@ class PostDetailScreen(
),
)
}, onReply = {
bottomSheetNavigator.show(
CreateCommentScreen(
originalPost = Json.encodeToString(post),
originalComment = Json.encodeToString(comment),
),
val screen = CreateCommentScreen(
originalPost = Json.encodeToString(post),
originalComment = Json.encodeToString(comment),
)
notificationCenter.addObserver({
model.reduce(PostDetailMviModel.Intent.Refresh)
}, key, screen.key)
bottomSheetNavigator.show(screen)
})
},
)

View File

@ -16,7 +16,6 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentR
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
class PostDetailViewModel(
@ -42,17 +41,6 @@ class PostDetailViewModel(
post = post,
)
}
mvi.scope.launch {
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.CommentCreated -> {
refresh()
}
else -> Unit
}
}
}
if (mvi.uiState.value.comments.isEmpty()) {
refresh()

View File

@ -38,15 +38,6 @@ class UserCommentsViewModel(
if (user != null) {
mvi.updateState { it.copy(user = user) }
}
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.CommentCreated -> {
refresh()
}
else -> Unit
}
}.launchIn(this)
}
}

View File

@ -26,6 +26,7 @@ import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -51,6 +52,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getUserComments
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.CommentCard
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailSection
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
@ -84,6 +86,12 @@ internal class UserDetailCommentsScreen(
model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState()
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val notificationCenter = remember { getNotificationCenter() }
DisposableEffect(key) {
onDispose {
notificationCenter.removeObserver(key)
}
}
LaunchedEffect(parentModel) {
parentModel?.uiState?.map { it.sortType }?.distinctUntilChanged()?.onEach { sortType ->
@ -219,12 +227,14 @@ internal class UserDetailCommentsScreen(
)
},
onReply = {
bottomSheetNavigator.show(
CreateCommentScreen(
originalPost = Json.encodeToString(PostModel(id = comment.postId)),
originalComment = Json.encodeToString(comment),
),
val screen = CreateCommentScreen(
originalPost = Json.encodeToString(PostModel(id = comment.postId)),
originalComment = Json.encodeToString(comment),
)
notificationCenter.addObserver({
model.reduce(UserCommentsMviModel.Intent.Refresh)
}, key, screen.key)
bottomSheetNavigator.show(screen)
}
)
},

View File

@ -26,6 +26,7 @@ import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -56,6 +57,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImag
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailSection
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.stringResource
@ -93,6 +95,12 @@ internal class UserDetailPostsScreen(
val uiState by model.uiState.collectAsState()
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val notificationCenter = remember { getNotificationCenter() }
DisposableEffect(key) {
onDispose {
notificationCenter.removeObserver(key)
}
}
LaunchedEffect(parentModel) {
parentModel?.uiState?.map { it.sortType }?.distinctUntilChanged()?.onEach { sortType ->
@ -245,11 +253,13 @@ internal class UserDetailPostsScreen(
)
},
onReply = {
bottomSheetNavigator.show(
CreateCommentScreen(
originalPost = Json.encodeToString(post),
)
val screen = CreateCommentScreen(
originalPost = Json.encodeToString(post),
)
notificationCenter.addObserver({
model.reduce(UserPostsMviModel.Intent.Refresh)
}, key, screen.key)
bottomSheetNavigator.show(screen)
},
onImageClick = { url ->
navigator?.push(

View File

@ -27,7 +27,6 @@ class UserPostsViewModel(
private val postsRepository: PostsRepository,
private val hapticFeedback: HapticFeedback,
private val keyStore: TemporaryKeyStore,
private val notificationCenter: NotificationCenter,
) : ScreenModel,
MviModel<UserPostsMviModel.Intent, UserPostsMviModel.UiState, UserPostsMviModel.Effect> by mvi {
@ -45,15 +44,6 @@ class UserPostsViewModel(
)
}
}
notificationCenter.events.onEach { evt ->
when (evt) {
NotificationCenter.Event.CommentCreated -> {
refresh()
}
else -> Unit
}
}.launchIn(this)
}
}

View File

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

View File

@ -255,11 +255,13 @@ class PostListScreen : Screen {
)
},
onReply = {
bottomSheetNavigator.show(
CreateCommentScreen(
originalPost = Json.encodeToString(post),
)
val screen = CreateCommentScreen(
originalPost = Json.encodeToString(post),
)
notificationCenter.addObserver({
model.reduce(PostListMviModel.Intent.Refresh)
}, key, screen.key)
bottomSheetNavigator.show(screen)
},
onImageClick = { url ->
navigator?.push(