Files
forkmessager/client-mobile/chats/data/local/mappers/MessageMappers.kt
T

118 lines
4.2 KiB
Kotlin

package chats.data.local.mappers
import chats.data.local.database.MessageEntity
import chats.domain.model.Message
import chats.domain.model.MessageStatus
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
private val gson = Gson()
/**
* Преобразует Domain Message в Entity для сохранения в Room
*/
fun Message.toEntity(status: MessageStatus = MessageStatus.SENT): MessageEntity {
return MessageEntity(
localId = this.id.takeIf { it.isNotBlank() } ?: java.util.UUID.randomUUID().toString(),
serverId = if (status == MessageStatus.SENT || status == MessageStatus.DELIVERED || status == MessageStatus.READ) this.id else null,
idempotencyKey = java.util.UUID.randomUUID().toString(),
chatId = this.chatId,
senderId = this.senderId,
senderName = this.senderName,
senderAvatar = this.senderAvatar,
content = this.content,
sequenceId = this.sequenceId.toLong(),
createdAt = this.createdAt,
mediaType = this.mediaType.name,
mediaJson = gson.toJson(this.media),
reactionsJson = gson.toJson(this.reactions),
status = status,
isPinned = this.isPinned,
isForwarded = this.isForwarded,
forwardedFromName = this.forwardedFromName,
replyToServerId = this.replyTo?.id,
createdAtMillis = parseTimestamp(this.createdAt),
updatedAtMillis = System.currentTimeMillis()
)
}
/**
* Преобразует Entity в Domain Message для отображения в UI
*/
fun MessageEntity.toDomain(): Message {
val mediaListType = object : TypeToken<List<chats.domain.model.Media>>() {}.type
val reactionsMapType = object : TypeToken<Map<String, Int>>() {}.type
return Message(
id = this.serverId ?: this.localId,
chatId = this.chatId,
senderId = this.senderId,
senderName = this.senderName,
senderAvatar = this.senderAvatar,
content = this.content,
sequenceId = this.sequenceId.toInt(),
createdAt = this.createdAt,
media = try {
gson.fromJson<List<chats.domain.model.Media>>(this.mediaJson, mediaListType) ?: emptyList()
} catch (e: Exception) {
emptyList()
},
mediaType = try {
chats.domain.model.MediaType.valueOf(this.mediaType)
} catch (e: Exception) {
chats.domain.model.MediaType.TEXT
},
reactions = try {
gson.fromJson<Map<String, Int>>(this.reactionsJson, reactionsMapType) ?: emptyMap()
} catch (e: Exception) {
emptyMap()
},
isRead = this.status == MessageStatus.READ,
isPinned = this.isPinned,
isForwarded = this.isForwarded,
forwardedFromName = this.forwardedFromName,
replyTo = null, // replyTo загружается отдельно если нужно
status = this.status
)
}
/**
* Создает новое локальное сообщение со статусом PENDING
*/
fun createPendingMessageEntity(
chatId: String,
senderId: String,
senderName: String,
content: String?,
mediaType: String = "TEXT",
mediaJson: String = "[]",
replyToId: String? = null
): MessageEntity {
val localId = java.util.UUID.randomUUID().toString()
return MessageEntity(
localId = localId,
serverId = null,
idempotencyKey = localId, // Используем localId как idempotency key
chatId = chatId,
senderId = senderId,
senderName = senderName,
content = content,
sequenceId = -1, // Будет обновлено после получения с сервера
createdAt = java.time.ZonedDateTime.now().toString(),
mediaType = mediaType,
mediaJson = mediaJson,
status = MessageStatus.PENDING,
replyToServerId = replyToId,
createdAtMillis = System.currentTimeMillis(),
updatedAtMillis = System.currentTimeMillis()
)
}
private fun parseTimestamp(createdAt: String): Long {
return try {
java.time.ZonedDateTime.parse(createdAt).toInstant().toEpochMilli()
} catch (e: Exception) {
System.currentTimeMillis()
}
}