diff --git a/core-commonui/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt b/core-commonui/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt index 3bcae1a72..4cb29cac0 100644 --- a/core-commonui/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt +++ b/core-commonui/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.di import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.CommunityInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel @@ -73,3 +74,11 @@ actual fun getUserCommentsViewModel(user: UserModel): UserCommentsViewModel { ) return res } + +actual fun getCreateCommentViewModel(postId: Int, parentId: Int?): CreateCommentViewModel { + val res: CreateCommentViewModel by inject( + clazz = CreateCommentViewModel::class.java, + parameters = { parametersOf(postId, parentId) } + ) + return res +} \ No newline at end of file diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt index 2a1e2e859..f83718849 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt @@ -67,6 +67,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.Comm import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Dropdown import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard 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.di.getCommunityDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet @@ -470,6 +471,17 @@ class CommunityDetailScreen( ) } }, + onReply = { + bottomSheetNavigator.show( + CreateCommentScreen( + originalPost = post, + onCommentCreated = { + bottomSheetNavigator.hide() + model.reduce(CommunityDetailMviModel.Intent.Refresh) + } + ) + ) + } ) }, ) diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/PostCardFooter.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/PostCardFooter.kt index 4a2c9078b..769d85141 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/PostCardFooter.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/PostCardFooter.kt @@ -60,6 +60,7 @@ fun PostCardFooter( Text( modifier = Modifier.padding(end = Spacing.s), text = "$comments", + style = MaterialTheme.typography.labelSmall, ) } if (date != null) { @@ -98,6 +99,7 @@ fun PostCardFooter( } } }, + style = MaterialTheme.typography.labelSmall, ) } Spacer(modifier = Modifier.weight(1f)) @@ -149,6 +151,7 @@ fun PostCardFooter( ) Text( text = "$score", + style = MaterialTheme.typography.labelSmall, ) Image( modifier = buttonModifier diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentMviModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentMviModel.kt new file mode 100644 index 000000000..dc6d132a6 --- /dev/null +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentMviModel.kt @@ -0,0 +1,23 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment + +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel + +interface CreateCommentMviModel : + MviModel { + + sealed interface Intent { + data class SetText(val value: String) : Intent + + object Send : Intent + } + + data class UiState( + val text: String = "", + ) + + sealed interface Effect { + object Success : Effect + + data class Failure(val message: String?) : Effect + } +} diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentScreen.kt new file mode 100644 index 000000000..32d94db6e --- /dev/null +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentScreen.kt @@ -0,0 +1,167 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment + +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 +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Send +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.model.rememberScreenModel +import cafe.adriel.voyager.core.screen.Screen +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getCreateCommentViewModel +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.CommentCard +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel +import com.github.diegoberaldin.raccoonforlemmy.resources.MR +import dev.icerock.moko.resources.compose.stringResource +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +class CreateCommentScreen( + private val originalPost: PostModel, + private val originalComment: CommentModel? = null, + private val onCommentCreated: () -> Unit = {}, +) : Screen { + @OptIn(ExperimentalMaterial3Api::class) + @Composable + override fun Content() { + val model = rememberScreenModel { + getCreateCommentViewModel(postId = originalPost.id, parentId = originalComment?.id) + } + model.bindToLifecycle(key) + val uiState by model.uiState.collectAsState() + val snackbarHostState = remember { SnackbarHostState() } + val genericError = stringResource(MR.strings.message_generic_error) + + LaunchedEffect(model) { + model.effects.onEach { + when (it) { + is CreateCommentMviModel.Effect.Failure -> { + snackbarHostState.showSnackbar(it.message ?: genericError) + } + + CreateCommentMviModel.Effect.Success -> onCommentCreated() + } + }.launchIn(this) + } + + Scaffold( + topBar = { + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(Spacing.xxs), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier.width(60.dp) + .height(1.dp) + .background( + color = MaterialTheme.colorScheme.onSurface, + shape = RoundedCornerShape(1.dp), + ), + ) + Text( + text = stringResource(MR.strings.create_comment_title), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onBackground, + ) + } + }, + snackbarHost = { + SnackbarHost(snackbarHostState) + } + ) { padding -> + val scrollState = rememberScrollState() + Column( + modifier = Modifier.padding(padding) + .verticalScroll(scrollState) + ) { + LaunchedEffect(Unit) { + scrollState.scrollTo(scrollState.maxValue) + } + + if (originalComment != null) { + CommentCard(comment = originalComment) + } else if (originalPost != null) { + PostCard( + post = originalPost, + blurNsfw = false + ) + } + + Box( + modifier = Modifier.fillMaxWidth() + .height(1.dp) + .background( + color = MaterialTheme.colorScheme.onSurface, + shape = RoundedCornerShape(1.dp), + ), + ) + + + TextField( + modifier = Modifier.height(300.dp).fillMaxWidth(), + label = { + Text(text = stringResource(MR.strings.create_comment_body)) + }, + value = uiState.text, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Ascii, + autoCorrect = false, + imeAction = ImeAction.Done, + ), + onValueChange = { value -> + model.reduce(CreateCommentMviModel.Intent.SetText(value)) + }, + ) + + Row { + Spacer(modifier = Modifier.weight(1f)) + IconButton( + content = { + Icon( + imageVector = Icons.Default.Send, + contentDescription = null, + ) + }, + onClick = { + model.reduce(CreateCommentMviModel.Intent.Send) + } + ) + } + } + } + } +} \ No newline at end of file diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentViewModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentViewModel.kt new file mode 100644 index 000000000..2ce744d7f --- /dev/null +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/createcomment/CreateCommentViewModel.kt @@ -0,0 +1,53 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment + +import cafe.adriel.voyager.core.model.ScreenModel +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel +import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.launch + +class CreateCommentViewModel( + private val postId: Int, + private val parentId: Int?, + private val mvi: DefaultMviModel = DefaultMviModel( + CreateCommentMviModel.UiState() + ), + private val identityRepository: IdentityRepository, + private val commentRepository: CommentRepository, +) : ScreenModel, + MviModel by mvi { + + override fun reduce(intent: CreateCommentMviModel.Intent) { + when (intent) { + is CreateCommentMviModel.Intent.SetText -> { + mvi.updateState { + it.copy(text = intent.value) + } + } + + CreateCommentMviModel.Intent.Send -> submit() + } + } + + private fun submit() { + mvi.scope.launch(Dispatchers.IO) { + try { + val auth = identityRepository.authToken.value.orEmpty() + val text = uiState.value.text + commentRepository.create( + postId = postId, + parentId = parentId, + text = text, + auth = auth, + ) + mvi.emitEffect(CreateCommentMviModel.Effect.Success) + } catch (e: Throwable) { + val message = e.message + mvi.emitEffect(CreateCommentMviModel.Effect.Failure(message)) + } + } + } +} \ No newline at end of file diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt index 31c78a507..3f1c507be 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/CommonUiModule.kt @@ -5,6 +5,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.Comm import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.CommunityInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailMviModel @@ -84,4 +85,12 @@ val commonUiModule = module { identityRepository = get(), ) } + factory { params -> + CreateCommentViewModel( + postId = params[0], + parentId = params[1], + identityRepository = get(), + commentRepository = get(), + ) + } } diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt index 93ae6a736..622bc1ab8 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.di import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.CommunityInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel @@ -39,3 +40,8 @@ expect fun getUserCommentsViewModel( expect fun getInstanceInfoViewModel( url: String, ): InstanceInfoViewModel + +expect fun getCreateCommentViewModel( + postId: Int, + parentId: Int? = null, +): CreateCommentViewModel \ No newline at end of file diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/CommentCard.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/CommentCard.kt index cbdcf9e76..0e69290c0 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/CommentCard.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/CommentCard.kt @@ -48,6 +48,7 @@ fun CommentCard( saved = comment.saved, upVoted = comment.myVote > 0, downVoted = comment.myVote < 0, + comments = comment.comments, onUpVote = onUpVote, onDownVote = onDownVote, onSave = onSave, diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt index af79d6981..21d1b8642 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt @@ -56,6 +56,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCar import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardSubtitle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardTitle 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.di.getPostDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailScreen @@ -300,6 +301,18 @@ class PostDetailScreen( ), ) }, + onReply = { + bottomSheetNavigator.show( + CreateCommentScreen( + originalPost = post, + originalComment = comment, + onCommentCreated = { + bottomSheetNavigator.hide() + model.reduce(PostDetailMviModel.Intent.Refresh) + } + ) + ) + } ) }, ) diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/comments/UserDetailCommentsScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/comments/UserDetailCommentsScreen.kt index 3ff2be930..c078acfa0 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/comments/UserDetailCommentsScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/comments/UserDetailCommentsScreen.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.unit.dp import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle @@ -43,10 +44,12 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Section import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserCounters import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserHeader +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getUserCommentsViewModel 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.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel import com.github.diegoberaldin.raccoonforlemmy.resources.MR import dev.icerock.moko.resources.compose.stringResource @@ -69,6 +72,7 @@ internal class UserDetailCommentsScreen( ) { getUserCommentsViewModel(user) } model.bindToLifecycle(key) val uiState by model.uiState.collectAsState() + val bottomSheetNavigator = LocalBottomSheetNavigator.current LaunchedEffect(parentModel) { parentModel.uiState.map { it.sortType }.distinctUntilChanged().onEach { sortType -> @@ -207,6 +211,18 @@ internal class UserDetailCommentsScreen( ), ) }, + onReply = { + bottomSheetNavigator.show( + CreateCommentScreen( + originalPost = PostModel(id = comment.postId), + originalComment = comment, + onCommentCreated = { + bottomSheetNavigator.hide() + model.reduce(UserCommentsMviModel.Intent.Refresh) + } + ) + ) + } ) }, ) diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/posts/UserDetailPostsScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/posts/UserDetailPostsScreen.kt index ebe038332..adfa86482 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/posts/UserDetailPostsScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/posts/UserDetailPostsScreen.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.unit.dp import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator import cafe.adriel.voyager.navigator.currentOrThrow import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing @@ -47,6 +48,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Section import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserCounters import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserHeader +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getUserPostsViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailSection import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel @@ -77,6 +79,7 @@ internal class UserDetailPostsScreen( model.bindToLifecycle(key) val uiState by model.uiState.collectAsState() val navigator = LocalNavigator.currentOrThrow + val bottomSheetNavigator = LocalBottomSheetNavigator.current LaunchedEffect(parentModel) { parentModel.uiState.map { it.sortType }.distinctUntilChanged().onEach { sortType -> @@ -228,6 +231,17 @@ internal class UserDetailPostsScreen( ), ) }, + onReply = { + bottomSheetNavigator.show( + CreateCommentScreen( + originalPost = post, + onCommentCreated = { + bottomSheetNavigator.hide() + model.reduce(UserPostsMviModel.Intent.Refresh) + } + ) + ) + } ) }, ) diff --git a/core-commonui/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt b/core-commonui/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt index 8ea646ba4..d5b45382d 100644 --- a/core-commonui/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt +++ b/core-commonui/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/di/Utils.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.di import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.CommunityInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.userdetail.UserDetailViewModel @@ -15,30 +16,33 @@ import org.koin.core.component.inject import org.koin.core.parameter.parametersOf actual fun getPostDetailViewModel(post: PostModel): PostDetailViewModel = - PostDetailScreenViewModelHelper.getPostDetailModel(post) + CommonUiViewModelHelper.getPostDetailModel(post) actual fun getCommunityDetailViewModel( community: CommunityModel, otherInstance: String, ): CommunityDetailViewModel = - PostDetailScreenViewModelHelper.getCommunityDetailModel(community, otherInstance) + CommonUiViewModelHelper.getCommunityDetailModel(community, otherInstance) actual fun getCommunityInfoViewModel(community: CommunityModel): CommunityInfoViewModel = - PostDetailScreenViewModelHelper.getCommunityInfoModel(community) + CommonUiViewModelHelper.getCommunityInfoModel(community) actual fun getInstanceInfoViewModel(url: String): InstanceInfoViewModel = - PostDetailScreenViewModelHelper.getInstanceInfoModel(url) + CommonUiViewModelHelper.getInstanceInfoModel(url) actual fun getUserDetailViewModel(user: UserModel): UserDetailViewModel = - PostDetailScreenViewModelHelper.getUserDetailModel(user) + CommonUiViewModelHelper.getUserDetailModel(user) actual fun getUserPostsViewModel(user: UserModel): UserPostsViewModel = - PostDetailScreenViewModelHelper.getUserPostsModel(user) + CommonUiViewModelHelper.getUserPostsModel(user) actual fun getUserCommentsViewModel(user: UserModel): UserCommentsViewModel = - PostDetailScreenViewModelHelper.getUserCommentsModel(user) + CommonUiViewModelHelper.getUserCommentsModel(user) -object PostDetailScreenViewModelHelper : KoinComponent { +actual fun getCreateCommentViewModel(postId: Int, parentId: Int?): CreateCommentViewModel = + CommonUiViewModelHelper.getCreateCommentModel(postId, parentId) + +object CommonUiViewModelHelper : KoinComponent { fun getPostDetailModel(post: PostModel): PostDetailViewModel { val model: PostDetailViewModel by inject( @@ -91,4 +95,11 @@ object PostDetailScreenViewModelHelper : KoinComponent { ) return model } + + fun getCreateCommentModel(postId: Int, parentId: Int?): CreateCommentViewModel { + val model: CreateCommentViewModel by inject( + parameters = { parametersOf(postId, parentId) } + ) + return model + } } diff --git a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt index 859928fd5..049135ad2 100644 --- a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt +++ b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data data class CommentModel( val id: Int = 0, + val postId: Int = 0, val text: String, val community: CommunityModel? = null, val creator: UserModel? = null, @@ -9,4 +10,5 @@ data class CommentModel( val myVote: Int = 0, val saved: Boolean = false, val publishDate: String? = null, + val comments: Int? = null, ) diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt index 1d916688f..b878ea702 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt @@ -1,5 +1,6 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreateCommentLikeForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SaveCommentForm import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider @@ -85,4 +86,19 @@ class CommentRepository( ) services.comment.save(data) } + + suspend fun create( + postId: Int, + parentId: Int?, + text: String, + auth: String, + ) { + val data = CreateCommentForm( + content = text, + postId = postId, + parentId = parentId, + auth = auth, + ) + services.comment.create(data) + } } diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt index 05ee928ac..a2ed10d1d 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt @@ -4,7 +4,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentReplyView import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentSortType import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentView import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.Community -import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommunityFollowerView import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.All import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.Local import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.Subscribed @@ -103,6 +102,8 @@ internal fun CommentView.toModel() = CommentModel( saved = saved, myVote = myVote ?: 0, publishDate = comment.published, + postId = comment.postId, + comments = counts.childCount, ) internal fun Community.toModel() = CommunityModel( @@ -127,6 +128,7 @@ internal fun PersonMentionView.toModel() = PersonMentionModel( ), comment = CommentModel( id = comment.id, + postId = comment.postId, text = comment.content, community = community.toModel(), ), @@ -150,6 +152,7 @@ internal fun CommentReplyView.toModel() = PersonMentionModel( ), comment = CommentModel( id = comment.id, + postId = comment.postId, text = comment.content, community = community.toModel(), publishDate = comment.published, diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListScreen.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListScreen.kt index 4e3958634..192791c08 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListScreen.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/postlist/PostListScreen.kt @@ -44,6 +44,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycl import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCard 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.modals.ListingTypeBottomSheet import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailScreen @@ -223,6 +224,17 @@ class PostListScreen : Screen { ), ) }, + onReply = { + bottomSheetNavigator.show( + CreateCommentScreen( + originalPost = post, + onCommentCreated = { + bottomSheetNavigator.hide() + model.reduce(PostListMviModel.Intent.Refresh) + } + ) + ) + } ) }, ) diff --git a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheet.kt b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheet.kt index 39285296e..be77a20af 100644 --- a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheet.kt +++ b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheet.kt @@ -68,13 +68,14 @@ class LoginBottomSheet( val uiState by model.uiState.collectAsState() val snackbarHostState = remember { SnackbarHostState() } + val genericError = stringResource(MR.strings.message_generic_error) LaunchedEffect(model) { model.effects.onEach { when (it) { is LoginBottomSheetMviModel.Effect.LoginError -> { snackbarHostState.showSnackbar( - message = it.message, + message = it.message ?: genericError, ) } diff --git a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetMviModel.kt b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetMviModel.kt index 5f2914f83..50d894173 100644 --- a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetMviModel.kt +++ b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetMviModel.kt @@ -26,7 +26,7 @@ interface LoginBottomSheetMviModel : ) sealed interface Effect { - data class LoginError(val message: String) : Effect + data class LoginError(val message: String?) : Effect object LoginSuccess : Effect } } diff --git a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetViewModel.kt b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetViewModel.kt index 787d67ed6..1bd23a7ef 100644 --- a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetViewModel.kt +++ b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/login/LoginBottomSheetViewModel.kt @@ -106,7 +106,7 @@ class LoginBottomSheetViewModel( if (result.isFailure) { result.exceptionOrNull()?.also { - val message = it.message ?: "Generic error" + val message = it.message mvi.emitEffect(LoginBottomSheetMviModel.Effect.LoginError(message)) } } else { diff --git a/resources/src/commonMain/resources/MR/base/strings.xml b/resources/src/commonMain/resources/MR/base/strings.xml index bee50e969..96d1b0656 100644 --- a/resources/src/commonMain/resources/MR/base/strings.xml +++ b/resources/src/commonMain/resources/MR/base/strings.xml @@ -100,4 +100,7 @@ replied to your post in replied to your comment in mentioned you in + + New comment + Comment body \ No newline at end of file diff --git a/resources/src/commonMain/resources/MR/it/strings.xml b/resources/src/commonMain/resources/MR/it/strings.xml index f746f1fc1..8dad1fb50 100644 --- a/resources/src/commonMain/resources/MR/it/strings.xml +++ b/resources/src/commonMain/resources/MR/it/strings.xml @@ -94,7 +94,10 @@ Tipo inbox Tutti Non letti - replied to your post in - replied to your comment in - mentioned you in + ha risposto al tuo post su + ha risposto al tuo commento tu + ti ha menzionato in + + Nuovo commento + Contenuto commento \ No newline at end of file