feat(posts): add possibility to reply to posts and comments (#1)

This commit is contained in:
Diego Beraldin 2023-09-04 22:50:06 +02:00 committed by GitHub
parent 376f84cfef
commit b371950d7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 392 additions and 15 deletions

View File

@ -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
}

View File

@ -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)
}
)
)
}
)
},
)

View File

@ -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

View File

@ -0,0 +1,23 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
interface CreateCommentMviModel :
MviModel<CreateCommentMviModel.Intent, CreateCommentMviModel.UiState, CreateCommentMviModel.Effect> {
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
}
}

View File

@ -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)
}
)
}
}
}
}
}

View File

@ -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<CreateCommentMviModel.Intent, CreateCommentMviModel.UiState, CreateCommentMviModel.Effect> = DefaultMviModel(
CreateCommentMviModel.UiState()
),
private val identityRepository: IdentityRepository,
private val commentRepository: CommentRepository,
) : ScreenModel,
MviModel<CreateCommentMviModel.Intent, CreateCommentMviModel.UiState, CreateCommentMviModel.Effect> 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))
}
}
}
}

View File

@ -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(),
)
}
}

View File

@ -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

View File

@ -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,

View File

@ -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)
}
)
)
}
)
},
)

View File

@ -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)
}
)
)
}
)
},
)

View File

@ -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)
}
)
)
}
)
},
)

View File

@ -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
}
}

View File

@ -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,
)

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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)
}
)
)
}
)
},
)

View File

@ -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,
)
}

View File

@ -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
}
}

View File

@ -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 {

View File

@ -100,4 +100,7 @@
<string name="inbox_item_reply_post">replied to your post in</string>
<string name="inbox_item_reply_comment">replied to your comment in</string>
<string name="inbox_item_mention">mentioned you in</string>
<string name="create_comment_title">New comment</string>
<string name="create_comment_body">Comment body</string>
</resources>

View File

@ -94,7 +94,10 @@
<string name="inbox_listing_type_title">Tipo inbox</string>
<string name="inbox_listing_type_all">Tutti</string>
<string name="inbox_listing_type_unread">Non letti</string>
<string name="inbox_item_reply_post">replied to your post in</string>
<string name="inbox_item_reply_comment">replied to your comment in</string>
<string name="inbox_item_mention">mentioned you in</string>
<string name="inbox_item_reply_post">ha risposto al tuo post su</string>
<string name="inbox_item_reply_comment">ha risposto al tuo commento tu</string>
<string name="inbox_item_mention">ti ha menzionato in</string>
<string name="create_comment_title">Nuovo commento</string>
<string name="create_comment_body">Contenuto commento</string>
</resources>