144 lines
5.9 KiB
Kotlin
144 lines
5.9 KiB
Kotlin
package chats.data.repository
|
|
|
|
import chats.data.remote.api.ChatApi
|
|
import chats.data.remote.api.SendMessageRequest
|
|
import chats.data.remote.dto.ChatDto
|
|
import chats.data.remote.dto.MessageDto
|
|
import chats.data.remote.dto.MediaItemDto
|
|
import chats.data.remote.dto.ReactionDto
|
|
import chats.domain.model.Chat
|
|
import chats.domain.model.Message
|
|
import chats.domain.model.MediaType
|
|
import chats.domain.repository.ChatRepository
|
|
import core.network.ServerConfig
|
|
import chats.data.remote.signalr.ReadMessagesRequest
|
|
import core.security.TokenManager
|
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|
import okhttp3.MultipartBody
|
|
import okhttp3.RequestBody.Companion.asRequestBody
|
|
import javax.inject.Inject
|
|
import kotlinx.coroutines.flow.map
|
|
|
|
class ChatRepositoryImpl @Inject constructor(
|
|
private val api: ChatApi,
|
|
private val tokenManager: TokenManager,
|
|
private val serverConfig: ServerConfig,
|
|
private val messageDao: core.database.data.MessageDao,
|
|
private val hubClient: chats.data.remote.signalr.ChatHubClient
|
|
) : ChatRepository {
|
|
private val gson = com.google.gson.Gson()
|
|
|
|
override suspend fun getChats(): List<Chat> {
|
|
val currentUserId = tokenManager.getUserId() ?: ""
|
|
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
|
return api.getChats().map { it.toDomain(currentUserId, baseUrl) }
|
|
}
|
|
|
|
override fun getMessagesFlow(chatId: String): kotlinx.coroutines.flow.Flow<List<Message>> {
|
|
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
|
return messageDao.getMessages(chatId).map { entities: List<core.database.data.MessageEntity> ->
|
|
entities.map { it.toDomain(baseUrl, gson) }
|
|
}
|
|
}
|
|
|
|
override suspend fun getMessages(chatId: String, cursor: String?, pivot: Long?, limit: Int?): List<Message> {
|
|
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
|
val currentUserId = tokenManager.getUserId() ?: ""
|
|
return try {
|
|
android.util.Log.d("ChatRepo", "FETCH: chatId=$chatId, cursor=$cursor, limit=$limit")
|
|
val messages = api.getMessages(chatId, cursor = cursor, limit = limit)
|
|
|
|
if (messages.isNotEmpty()) {
|
|
android.util.Log.d("ChatRepo", "Received ${messages.size} messages. TopSeq: ${messages.first().sequenceId}, BottomSeq: ${messages.last().sequenceId}")
|
|
}
|
|
|
|
// Мапим в доменные модели. По умолчанию считаем прочитанными,
|
|
// так как unreadCount нам тут не критичен для истории.
|
|
messages.map { msg ->
|
|
msg.toDomain(currentUserId, baseUrl).copy(isRead = true)
|
|
}
|
|
} catch (e: Exception) {
|
|
android.util.Log.e("ChatRepo", "Fetch messages failed", e)
|
|
emptyList()
|
|
}
|
|
}
|
|
|
|
override suspend fun sendMessage(
|
|
chatId: String,
|
|
content: String?,
|
|
type: String,
|
|
attachments: List<chats.data.remote.api.AttachmentRequest>?,
|
|
replyToId: String?
|
|
): Message {
|
|
val request = SendMessageRequest(
|
|
content = content,
|
|
type = type,
|
|
attachments = attachments,
|
|
replyToId = replyToId
|
|
)
|
|
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
|
val userId = tokenManager.getUserId() ?: ""
|
|
return api.sendMessage(chatId, request).toDomain(userId, baseUrl)
|
|
}
|
|
|
|
override suspend fun addReaction(messageId: String, emoji: String) {
|
|
api.addReaction(messageId, emoji)
|
|
}
|
|
|
|
override suspend fun sendTypingStatus(chatId: String) {
|
|
api.sendTypingStatus(chatId)
|
|
}
|
|
|
|
override suspend fun markMessagesAsRead(chatId: String, lastMessageId: String, lastReadSequenceId: Int) {
|
|
try {
|
|
android.util.Log.d("ChatRepoImpl", "markMessagesAsRead CALLED FOR $chatId. Caller stack: ${android.util.Log.getStackTraceString(Throwable())}")
|
|
hubClient.readMessages(ReadMessagesRequest(chatId, lastMessageId, lastReadSequenceId))
|
|
} catch (e: Exception) {
|
|
android.util.Log.e("ChatRepo", "Error marking messages as read", e)
|
|
}
|
|
// Обновляем локальную БД
|
|
messageDao.markMessagesAsRead(chatId, lastReadSequenceId)
|
|
}
|
|
|
|
override suspend fun saveMessage(message: Message) {
|
|
android.util.Log.d("ChatRepo", "DB cache disabled, skipping save: ${message.id}")
|
|
}
|
|
|
|
override suspend fun deleteLocalMessage(messageId: String) {
|
|
messageDao.deleteMessage(messageId)
|
|
}
|
|
|
|
override suspend fun uploadMedia(file: java.io.File): String {
|
|
val mimeType = when (file.extension.lowercase()) {
|
|
"jpg", "jpeg" -> "image/jpeg"
|
|
"png" -> "image/png"
|
|
"webp" -> "image/webp"
|
|
"mp4" -> "video/mp4"
|
|
"mp3", "m4a", "wav" -> "audio/mpeg"
|
|
else -> "application/octet-stream"
|
|
}
|
|
val requestFile = file.asRequestBody(mimeType.toMediaTypeOrNull())
|
|
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
|
|
return api.uploadFile(body).url
|
|
}
|
|
|
|
override suspend fun getTrendingGifs(page: Int): List<chats.data.remote.api.KlipyGifDto> {
|
|
return api.getTrendingGifs(page).data.data
|
|
}
|
|
|
|
override suspend fun searchGifs(query: String, page: Int): List<chats.data.remote.api.KlipyGifDto> {
|
|
return api.searchGifs(query, page).data.data
|
|
}
|
|
|
|
override suspend fun getGifCategories(): List<chats.data.remote.api.GifCategoryDto> {
|
|
return api.getGifCategories().data.categories
|
|
}
|
|
|
|
override suspend fun createPersonalChat(userId: String): Chat {
|
|
val currentUserId = tokenManager.getUserId() ?: ""
|
|
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
|
val request = chats.data.remote.api.CreatePersonalChatRequest(userId)
|
|
return api.createPersonalChat(request).toDomain(currentUserId, baseUrl)
|
|
}
|
|
}
|