Офлайн режим, начало

This commit is contained in:
Халимов Рустам
2026-04-20 01:00:35 +03:00
parent 7c66e1c0c0
commit 38e7184a0d
18 changed files with 214 additions and 35 deletions
@@ -15,6 +15,7 @@ import chats.domain.model.Message
import chats.domain.model.MediaType
import chats.domain.repository.ChatRepository
import core.database.data.ChatDatabase
import core.database.data.ChatDao
import core.database.data.MessageDao
import core.database.data.MessageEntity
import core.database.data.SyncStatus
@@ -51,7 +52,8 @@ class ChatRepositoryImpl @Inject constructor(
private val api: ChatApi,
private val tokenManager: TokenManager,
private val serverConfig: ServerConfig,
private val dao: MessageDao,
private val messageDao: MessageDao,
private val chatDao: ChatDao,
private val database: ChatDatabase,
private val hubClient: ChatHubClient,
private val signalRHandler: MessageSignalRHandler,
@@ -68,7 +70,43 @@ class ChatRepositoryImpl @Inject constructor(
override suspend fun getChats(): List<Chat> {
val currentUserId = tokenManager.getUserId() ?: ""
return api.getChats().map { it.toDomain(currentUserId, baseUrl) }
return try {
// Пробуем загрузить из сети
val chats = api.getChats().map { it.toDomain(currentUserId, baseUrl) }
// Кэшируем в Room
val entities = chats.map { it.toEntity() }
chatDao.insertChats(entities)
// Кэшируем последние сообщения
chats.forEach { chat ->
chat.lastMessage?.let { msg ->
messageDao.upsertMessage(msg.toEntity(gson))
}
}
android.util.Log.d(TAG, "Cached ${entities.size} chats with messages")
chats
} catch (e: Exception) {
android.util.Log.d(TAG, "Network load failed, using cache")
// При ошибке - возвращаем из кэша с загрузкой последних сообщений
chatDao.getAllChats().map { entity ->
val lastMessage = entity.lastMessageId?.let { messageId ->
messageDao.getMessageById(messageId)?.toDomain(baseUrl, gson)
}
entity.toDomain(currentUserId, baseUrl, lastMessage)
}
}
}
override fun getChatsFlow(): Flow<List<Chat>> {
val currentUserId = tokenManager.getUserId() ?: ""
return chatDao.getAllChatsFlow().map { entities ->
entities.map { entity ->
// Загружаем последнее сообщение из базы для каждого чата
val lastMessage = entity.lastMessageId?.let { messageId ->
messageDao.getMessageById(messageId)?.toDomain(baseUrl, gson)
}
entity.toDomain(currentUserId, baseUrl, lastMessage)
}
}
}
override fun getMessagesPaging(chatId: String): Flow<PagingData<Message>> {
@@ -78,15 +116,15 @@ class ChatRepositoryImpl @Inject constructor(
initialLoadSize = 50,
enablePlaceholders = false
)
return Pager(
config = pagingConfig,
pagingSourceFactory = { dao.getMessagesPagingSource(chatId) },
pagingSourceFactory = { messageDao.getMessagesPagingSource(chatId) },
remoteMediator = MessageRemoteMediator(
chatId = chatId,
api = api,
database = database,
dao = dao,
dao = messageDao,
serverConfig = serverConfig,
tokenManager = tokenManager
)
@@ -96,7 +134,7 @@ class ChatRepositoryImpl @Inject constructor(
}
override fun getMessagesFlow(chatId: String): Flow<List<Message>> {
return dao.getMessages(chatId).map { entities ->
return messageDao.getMessages(chatId).map { entities ->
entities.map { it.toDomain(baseUrl, gson) }
}
}
@@ -111,7 +149,7 @@ class ChatRepositoryImpl @Inject constructor(
if (messages.isNotEmpty()) {
val entities = messages.map { it.toEntity(baseUrl, currentUserId, gson) }
dao.upsertMessages(entities)
messageDao.upsertMessages(entities)
Log.d(TAG, "Cached ${entities.size} messages")
}
@@ -145,7 +183,7 @@ class ChatRepositoryImpl @Inject constructor(
editedContent = null, lastUpdated = currentTime
)
dao.insertMessage(localMessage)
messageDao.insertMessage(localMessage)
Log.d(TAG, "Saved local message: $localId")
MessageSyncWorker.scheduleSync(context)
@@ -191,20 +229,20 @@ class ChatRepositoryImpl @Inject constructor(
} catch (e: Exception) {
Log.e(TAG, "Error marking messages as read", e)
}
dao.markMessagesAsRead(chatId, lastReadSequenceId)
messageDao.markMessagesAsRead(chatId, lastReadSequenceId)
}
override suspend fun saveMessage(message: Message) {
dao.insertMessage(message.toEntity(gson))
messageDao.insertMessage(message.toEntity(gson))
}
override suspend fun deleteLocalMessage(messageId: String) {
dao.markAsDeletedLocally(messageId)
messageDao.markAsDeletedLocally(messageId)
MessageSyncWorker.scheduleSync(context)
}
override suspend fun editLocalMessage(messageId: String, newContent: String) {
dao.markAsEditedLocally(messageId, newContent)
messageDao.markAsEditedLocally(messageId, newContent)
MessageSyncWorker.scheduleSync(context)
}
@@ -239,14 +277,14 @@ class ChatRepositoryImpl @Inject constructor(
override suspend fun deleteMessage(messageId: String, forEveryone: Boolean) {
api.deleteMessage(messageId, forEveryone)
dao.deleteMessage(messageId)
messageDao.deleteMessage(messageId)
}
override suspend fun editMessage(messageId: String, content: String): Message {
val request = SendMessageRequest(content = content)
val currentUserId = tokenManager.getUserId() ?: ""
val response = api.editMessage(messageId, request)
dao.insertMessage(response.toEntity(baseUrl, currentUserId, gson))
messageDao.insertMessage(response.toEntity(baseUrl, currentUserId, gson))
return response.toDomain(currentUserId, baseUrl)
}