feat: edit chat message (#310); closes #226, #202

* feat: add possibility to edit messages; closes #226

* fix: chat loading messages; closes #202
This commit is contained in:
Diego Beraldin 2023-12-16 14:17:36 +01:00 committed by GitHub
parent b878c3d0eb
commit 08c1490502
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 292 additions and 69 deletions

View File

@ -0,0 +1,14 @@
package com.github.diegoberaldin.raccoonforlemmy.core.api.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class EditPrivateMessageForm(
@SerialName("content")
val content: String,
@SerialName("private_message_id")
val privateMessageId: PrivateMessageId,
@SerialName("auth")
val auth: String,
)

View File

@ -1,7 +1,9 @@
package com.github.diegoberaldin.raccoonforlemmy.core.api.service package com.github.diegoberaldin.raccoonforlemmy.core.api.service
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePrivateMessageForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePrivateMessageForm
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditPrivateMessageForm
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPrivateMessageAsReadForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPrivateMessageAsReadForm
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PersonId
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PrivateMessageResponse import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PrivateMessageResponse
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PrivateMessagesResponse import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.PrivateMessagesResponse
import de.jensklingenberg.ktorfit.Response import de.jensklingenberg.ktorfit.Response
@ -10,6 +12,7 @@ import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.Header import de.jensklingenberg.ktorfit.http.Header
import de.jensklingenberg.ktorfit.http.Headers import de.jensklingenberg.ktorfit.http.Headers
import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.POST
import de.jensklingenberg.ktorfit.http.PUT
import de.jensklingenberg.ktorfit.http.Query import de.jensklingenberg.ktorfit.http.Query
interface PrivateMessageService { interface PrivateMessageService {
@ -18,6 +21,7 @@ interface PrivateMessageService {
@Header("Authorization") authHeader: String? = null, @Header("Authorization") authHeader: String? = null,
@Query("auth") auth: String? = null, @Query("auth") auth: String? = null,
@Query("page") page: Int? = null, @Query("page") page: Int? = null,
@Query("creator_id") creatorId: PersonId? = null,
@Query("limit") limit: Int? = null, @Query("limit") limit: Int? = null,
@Query("unread_only") unreadOnly: Boolean? = null, @Query("unread_only") unreadOnly: Boolean? = null,
): Response<PrivateMessagesResponse> ): Response<PrivateMessagesResponse>
@ -29,6 +33,13 @@ interface PrivateMessageService {
@Body form: CreatePrivateMessageForm, @Body form: CreatePrivateMessageForm,
): Response<PrivateMessageResponse> ): Response<PrivateMessageResponse>
@PUT("private_message")
@Headers("Content-Type: application/json")
suspend fun editPrivateMessage(
@Header("Authorization") authHeader: String? = null,
@Body form: EditPrivateMessageForm,
): Response<PrivateMessageResponse>
@POST("private_message/mark_as_read") @POST("private_message/mark_as_read")
@Headers("Content-Type: application/json") @Headers("Content-Type: application/json")
suspend fun markPrivateMessageAsRead( suspend fun markPrivateMessageAsRead(

View File

@ -29,10 +29,12 @@ interface InboxChatMviModel :
} }
} }
data class EditMessage(val value: Int) : Intent
data class SubmitNewMessage(val value: String) : Intent data class SubmitNewMessage(val value: String) : Intent
} }
data class UiState( data class UiState(
val initial: Boolean = true,
val refreshing: Boolean = false, val refreshing: Boolean = false,
val loading: Boolean = false, val loading: Boolean = false,
val canFetchMore: Boolean = true, val canFetchMore: Boolean = true,
@ -41,6 +43,7 @@ interface InboxChatMviModel :
val otherUserAvatar: String? = null, val otherUserAvatar: String? = null,
val messages: List<PrivateMessageModel> = emptyList(), val messages: List<PrivateMessageModel> = emptyList(),
val autoLoadImages: Boolean = true, val autoLoadImages: Boolean = true,
val editedMessageId: Int? = null,
) )
sealed interface Effect { sealed interface Effect {

View File

@ -56,11 +56,14 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.toTypography import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.toTypography
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
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.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
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.getInboxChatViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getInboxChatViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs
import com.github.diegoberaldin.raccoonforlemmy.core.utils.gallery.getGalleryHelper import com.github.diegoberaldin.raccoonforlemmy.core.utils.gallery.getGalleryHelper
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
@ -158,7 +161,14 @@ class InboxChatScreen(
), ),
label = { label = {
Text( Text(
text = stringResource(MR.strings.inbox_chat_message), text = buildString {
append(stringResource(MR.strings.inbox_chat_message))
if (uiState.editedMessageId != null) {
append(" (")
append(stringResource(MR.strings.post_action_edit))
append(")")
}
},
style = typography.bodyMedium, style = typography.bodyMedium,
) )
}, },
@ -217,6 +227,11 @@ class InboxChatScreen(
item { item {
Spacer(modifier = Modifier.height(Spacing.s)) Spacer(modifier = Modifier.height(Spacing.s))
} }
if (uiState.messages.isEmpty() && uiState.initial) {
items(10) {
MessageCardPlaceholder()
}
}
items(uiState.messages) { message -> items(uiState.messages) { message ->
val isMyMessage = message.creator?.id == uiState.currentUserId val isMyMessage = message.creator?.id == uiState.currentUserId
val content = message.content.orEmpty() val content = message.content.orEmpty()
@ -225,13 +240,37 @@ class InboxChatScreen(
isMyMessage = isMyMessage, isMyMessage = isMyMessage,
content = content, content = content,
date = date, date = date,
options = buildList {
if (isMyMessage) {
this += Option(
OptionId.Edit,
stringResource(MR.strings.post_action_edit)
)
}
},
onOptionSelected = rememberCallbackArgs { optionId ->
when (optionId) {
OptionId.Edit -> {
model.reduce(
InboxChatMviModel.Intent.EditMessage(
message.id
)
)
message.content?.also {
textFieldValue = TextFieldValue(text = it)
}
}
else -> Unit
}
}
) )
} }
item { item {
if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) { if (!uiState.initial && !uiState.loading && !uiState.refreshing && uiState.canFetchMore) {
model.reduce(InboxChatMviModel.Intent.LoadNextPage) model.reduce(InboxChatMviModel.Intent.LoadNextPage)
} }
if (uiState.loading && !uiState.refreshing) { if (!uiState.initial && uiState.loading && !uiState.refreshing) {
Box( Box(
modifier = Modifier.fillMaxWidth().padding(Spacing.xs), modifier = Modifier.fillMaxWidth().padding(Spacing.xs),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,

View File

@ -6,6 +6,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationC
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PrivateMessageRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PrivateMessageRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
@ -59,6 +60,10 @@ class InboxChatViewModel(
otherUserAvatar = user?.avatar, otherUserAvatar = user?.avatar,
) )
} }
if (uiState.value.messages.isEmpty()) {
refresh(initial = true)
}
} }
} }
} }
@ -66,59 +71,80 @@ class InboxChatViewModel(
override fun reduce(intent: InboxChatMviModel.Intent) { override fun reduce(intent: InboxChatMviModel.Intent) {
when (intent) { when (intent) {
InboxChatMviModel.Intent.LoadNextPage -> loadNextPage() InboxChatMviModel.Intent.LoadNextPage -> {
is InboxChatMviModel.Intent.SubmitNewMessage -> submitNewMessage(intent.value) mvi.scope?.launch(Dispatchers.IO) {
is InboxChatMviModel.Intent.ImageSelected -> loadImageAndAppendUrlInBody(intent.value) loadNextPage()
}
}
is InboxChatMviModel.Intent.SubmitNewMessage -> {
submitNewMessage(intent.value)
}
is InboxChatMviModel.Intent.ImageSelected -> {
loadImageAndAppendUrlInBody(intent.value)
}
is InboxChatMviModel.Intent.EditMessage -> {
uiState.value.messages.firstOrNull { it.id == intent.value }?.also { message ->
startEditingMessage(message)
}
}
} }
} }
private fun refresh() { private suspend fun refresh(initial: Boolean = false) {
currentPage = 1 currentPage = 1
mvi.updateState { it.copy(canFetchMore = true, refreshing = true) } mvi.updateState {
it.copy(
initial = initial,
canFetchMore = true,
refreshing = true
)
}
loadNextPage() loadNextPage()
} }
private fun loadNextPage() { private suspend fun loadNextPage() {
val currentState = mvi.uiState.value val currentState = mvi.uiState.value
if (!currentState.canFetchMore || currentState.loading) { if (!currentState.canFetchMore || currentState.loading) {
mvi.updateState { it.copy(refreshing = false) } mvi.updateState { it.copy(refreshing = false) }
return return
} }
mvi.scope?.launch(Dispatchers.IO) { mvi.updateState { it.copy(loading = true) }
mvi.updateState { it.copy(loading = true) } val auth = identityRepository.authToken.value
val auth = identityRepository.authToken.value val refreshing = currentState.refreshing
val refreshing = currentState.refreshing val itemList = messageRepository.getAll(
val itemList = messageRepository.getAll( creatorId = otherUserId,
auth = auth, auth = auth,
page = currentPage, page = currentPage,
unreadOnly = false, unreadOnly = false,
)?.filter { )?.onEach {
it.creator?.id == otherUserId || it.recipient?.id == otherUserId if (!it.read) {
}?.onEach { markAsRead(true, it.id)
if (!it.read) {
launch {
markAsRead(true, it.id)
}
}
}
if (!itemList.isNullOrEmpty()) {
currentPage++
} }
}
if (!itemList.isNullOrEmpty()) {
currentPage++
}
mvi.updateState { val itemsToAdd = itemList.orEmpty().filter {
val newItems = if (refreshing) { it.creator?.id == otherUserId || it.recipient?.id == otherUserId
itemList.orEmpty() }
} else { mvi.updateState {
it.messages + itemList.orEmpty() val newItems = if (refreshing) {
} itemsToAdd
it.copy( } else {
messages = newItems, it.messages + itemsToAdd
loading = false,
canFetchMore = itemList?.isEmpty() != true,
refreshing = false,
)
} }
it.copy(
messages = newItems,
loading = false,
canFetchMore = itemList?.isEmpty() != true,
refreshing = false,
initial = false,
)
} }
} }
@ -153,15 +179,36 @@ class InboxChatViewModel(
} }
} }
private fun startEditingMessage(message: PrivateMessageModel) {
mvi.updateState {
it.copy(
editedMessageId = message.id,
)
}
}
private fun submitNewMessage(text: String) { private fun submitNewMessage(text: String) {
val editedMessageId = uiState.value.editedMessageId
if (text.isNotEmpty()) { if (text.isNotEmpty()) {
mvi.scope?.launch { mvi.scope?.launch {
val auth = identityRepository.authToken.value val auth = identityRepository.authToken.value
messageRepository.create( if (editedMessageId == null) {
message = text, messageRepository.create(
auth = auth, message = text,
recipiendId = otherUserId, recipiendId = otherUserId,
) auth = auth,
)
} else {
messageRepository.edit(
messageId = editedMessageId,
message = text,
auth = auth,
)
}
mvi.updateState {
it.copy(editedMessageId = null)
}
refresh() refresh()
} }
} }

View File

@ -12,27 +12,44 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreHoriz
import androidx.compose.material.icons.filled.Schedule import androidx.compose.material.icons.filled.Schedule
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.Path
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
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.CustomDropDown
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomizedContent import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomizedContent
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Option
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardBody import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PostCardBody
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.datetime.prettifyDate import com.github.diegoberaldin.raccoonforlemmy.core.utils.datetime.prettifyDate
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLocalDp
@Composable @Composable
internal fun MessageCard( internal fun MessageCard(
isMyMessage: Boolean = false, isMyMessage: Boolean = false,
content: String = "", content: String = "",
date: String = "", date: String = "",
options: List<Option> = emptyList(),
onOptionSelected: ((OptionId) -> Unit)? = null,
) { ) {
val color = if (isMyMessage) { val color = if (isMyMessage) {
MaterialTheme.colorScheme.tertiaryContainer MaterialTheme.colorScheme.tertiaryContainer
@ -46,6 +63,10 @@ internal fun MessageCard(
} }
val longDistance = Spacing.l val longDistance = Spacing.l
val mediumDistance = Spacing.s val mediumDistance = Spacing.s
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.75f)
var optionsExpanded by remember { mutableStateOf(false) }
var optionsOffset by remember { mutableStateOf(Offset.Zero) }
Box { Box {
Canvas( Canvas(
modifier = Modifier.size(mediumDistance).let { modifier = Modifier.size(mediumDistance).let {
@ -95,30 +116,74 @@ internal fun MessageCard(
PostCardBody( PostCardBody(
text = content, text = content,
) )
Row( Box {
horizontalArrangement = Arrangement.spacedBy(Spacing.xxxs), Row(
verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(Spacing.xxxs),
) { verticalAlignment = Alignment.CenterVertically,
Spacer(modifier = Modifier.weight(1f)) ) {
if (options.isNotEmpty()) {
Icon(
modifier = Modifier.size(IconSize.m)
.padding(Spacing.xs)
.onGloballyPositioned {
optionsOffset = it.positionInParent()
}
.onClick(
onClick = rememberCallback {
optionsExpanded = true
},
),
imageVector = Icons.Default.MoreHoriz,
contentDescription = null,
tint = ancillaryColor
)
}
Spacer(modifier = Modifier.weight(1f))
if (date.isNotEmpty()) { if (date.isNotEmpty()) {
val buttonModifier = Modifier.size(IconSize.m).padding(3.5.dp) val buttonModifier = Modifier.size(IconSize.m).padding(3.5.dp)
Icon( Icon(
modifier = buttonModifier, modifier = buttonModifier,
imageVector = Icons.Default.Schedule, imageVector = Icons.Default.Schedule,
contentDescription = null, contentDescription = null,
tint = textColor, tint = ancillaryColor,
) )
Text( Text(
text = date.prettifyDate(), text = date.prettifyDate(),
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
color = textColor, color = ancillaryColor,
) )
} else { } else {
Text( Text(
text = "", text = "",
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
) )
}
}
CustomDropDown(
expanded = optionsExpanded,
onDismiss = {
optionsExpanded = false
},
offset = DpOffset(
x = optionsOffset.x.toLocalDp(),
y = optionsOffset.y.toLocalDp(),
),
) {
options.forEach { option ->
Text(
modifier = Modifier.padding(
horizontal = Spacing.m,
vertical = Spacing.s,
).onClick(
onClick = rememberCallback {
optionsExpanded = false
onOptionSelected?.invoke(option.id)
},
),
text = option.text,
)
}
} }
} }
} }

View File

@ -0,0 +1,23 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.chat
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.shimmerEffect
@Composable
fun MessageCardPlaceholder() {
Box(
modifier = Modifier
.height(100.dp)
.fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect()
)
}

View File

@ -77,7 +77,6 @@ fun InboxReplySubtitle(
val defaultDownVoteColor = MaterialTheme.colorScheme.tertiary val defaultDownVoteColor = MaterialTheme.colorScheme.tertiary
var optionsExpanded by remember { mutableStateOf(false) } var optionsExpanded by remember { mutableStateOf(false) }
var optionsOffset by remember { mutableStateOf(Offset.Zero) } var optionsOffset by remember { mutableStateOf(Offset.Zero) }
val fullColor = MaterialTheme.colorScheme.onBackground
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.75f) val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.75f)
Column( Column(

View File

@ -1,6 +1,7 @@
package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePrivateMessageForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CreatePrivateMessageForm
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.EditPrivateMessageForm
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPrivateMessageAsReadForm import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.MarkPrivateMessageAsReadForm
import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PrivateMessageModel
@ -13,6 +14,7 @@ internal class DefaultPrivateMessageRepository(
override suspend fun getAll( override suspend fun getAll(
auth: String?, auth: String?,
creatorId: Int?,
page: Int, page: Int,
limit: Int, limit: Int,
unreadOnly: Boolean, unreadOnly: Boolean,
@ -20,6 +22,7 @@ internal class DefaultPrivateMessageRepository(
val response = services.privateMessages.getPrivateMessages( val response = services.privateMessages.getPrivateMessages(
authHeader = auth.toAuthHeader(), authHeader = auth.toAuthHeader(),
auth = auth, auth = auth,
creatorId = creatorId,
limit = limit, limit = limit,
page = page, page = page,
unreadOnly = unreadOnly, unreadOnly = unreadOnly,
@ -44,6 +47,18 @@ internal class DefaultPrivateMessageRepository(
) )
} }
override suspend fun edit(messageId: Int, message: String, auth: String?) {
val data = EditPrivateMessageForm(
content = message,
auth = auth.orEmpty(),
privateMessageId = messageId,
)
services.privateMessages.editPrivateMessage(
authHeader = auth.toAuthHeader(),
form = data,
)
}
override suspend fun markAsRead( override suspend fun markAsRead(
messageId: Int, messageId: Int,
auth: String?, auth: String?,

View File

@ -10,6 +10,7 @@ interface PrivateMessageRepository {
suspend fun getAll( suspend fun getAll(
auth: String? = null, auth: String? = null,
creatorId: Int? = null,
page: Int, page: Int,
limit: Int = DEFAULT_PAGE_SIZE, limit: Int = DEFAULT_PAGE_SIZE,
unreadOnly: Boolean = true, unreadOnly: Boolean = true,
@ -21,6 +22,12 @@ interface PrivateMessageRepository {
recipiendId: Int, recipiendId: Int,
) )
suspend fun edit(
messageId: Int,
message: String,
auth: String? = null,
)
suspend fun markAsRead( suspend fun markAsRead(
messageId: Int, messageId: Int,
auth: String? = null, auth: String? = null,