118 lines
4.2 KiB
Kotlin
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()
|
||
}
|
||
}
|