Заготовка
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
package chats.data.local.database
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import chats.data.local.dao.ChatDao
|
||||
import chats.data.local.dao.MessageDao
|
||||
import chats.data.local.dao.UserProfileDao
|
||||
|
||||
/**
|
||||
* Room Database для локального хранения данных мессенджера
|
||||
* Реализует паттерн Single Source of Truth
|
||||
*/
|
||||
@Database(
|
||||
entities = [
|
||||
MessageEntity::class,
|
||||
ChatEntity::class,
|
||||
UserProfileEntity::class
|
||||
],
|
||||
version = 1,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(MessageStatusConverter::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun messageDao(): MessageDao
|
||||
abstract fun chatDao(): ChatDao
|
||||
abstract fun userProfileDao(): UserProfileDao
|
||||
|
||||
companion object {
|
||||
const val DATABASE_NAME = "knot_messenger.db"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package chats.data.local.database
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
/**
|
||||
* Entity для хранения чатов в локальной БД Room
|
||||
*/
|
||||
@Entity(
|
||||
tableName = "chats",
|
||||
indices = [
|
||||
Index(value = ["remoteId"], unique = true)
|
||||
]
|
||||
)
|
||||
data class ChatEntity(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
val localId: String,
|
||||
|
||||
val remoteId: String?, // ID с сервера
|
||||
|
||||
val type: String, // PRIVATE, GROUP, CHANNEL
|
||||
|
||||
val name: String,
|
||||
|
||||
val avatar: String? = null,
|
||||
|
||||
val unreadCount: Int = 0,
|
||||
|
||||
val lastMessageId: String? = null,
|
||||
|
||||
val lastMessageText: String? = null,
|
||||
|
||||
val lastMessageTimestamp: String? = null,
|
||||
|
||||
val updatedAtMillis: Long = System.currentTimeMillis()
|
||||
)
|
||||
@@ -0,0 +1,66 @@
|
||||
package chats.data.local.database
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import chats.domain.model.MessageStatus
|
||||
|
||||
/**
|
||||
* Entity для хранения сообщений в локальной БД Room
|
||||
* Используется для офлайн-режима и Single Source of Truth паттерна
|
||||
*/
|
||||
@Entity(
|
||||
tableName = "messages",
|
||||
indices = [
|
||||
Index(value = ["chatId", "sequenceId"]),
|
||||
Index(value = ["localId"], unique = true),
|
||||
Index(value = ["serverId"]),
|
||||
Index(value = ["status"])
|
||||
]
|
||||
)
|
||||
data class MessageEntity(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
val localId: String, // UUID генерируется на клиенте при создании
|
||||
|
||||
val serverId: String?, // null для неотправленных сообщений
|
||||
|
||||
val idempotencyKey: String, // UUID v4 для идемпотентности
|
||||
|
||||
val chatId: String,
|
||||
|
||||
val senderId: String,
|
||||
|
||||
val senderName: String,
|
||||
|
||||
val senderAvatar: String? = null,
|
||||
|
||||
val content: String?,
|
||||
|
||||
val sequenceId: Long,
|
||||
|
||||
val createdAt: String, // ISO-8601 формат
|
||||
|
||||
val mediaType: String,
|
||||
|
||||
val mediaJson: String, // JSON список медиа (для Room)
|
||||
|
||||
val reactionsJson: String = "{}", // JSON map эмодзи -> count
|
||||
|
||||
val status: MessageStatus,
|
||||
|
||||
val isPinned: Boolean = false,
|
||||
|
||||
val isForwarded: Boolean = false,
|
||||
|
||||
val forwardedFromName: String? = null,
|
||||
|
||||
val replyToServerId: String? = null,
|
||||
|
||||
val errorMessage: String? = null,
|
||||
|
||||
val retryCount: Int = 0,
|
||||
|
||||
val createdAtMillis: Long = 0,
|
||||
|
||||
val updatedAtMillis: Long = 0
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
package chats.data.local.database
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import chats.domain.model.MessageStatus
|
||||
|
||||
/**
|
||||
* Конвертеры для Room для работы с Enum и другими типами
|
||||
*/
|
||||
class MessageStatusConverter {
|
||||
@TypeConverter
|
||||
fun fromMessageStatus(status: MessageStatus): String = status.name
|
||||
|
||||
@TypeConverter
|
||||
fun toMessageStatus(value: String): MessageStatus = runCatching {
|
||||
MessageStatus.valueOf(value)
|
||||
}.getOrDefault(MessageStatus.UNKNOWN)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package chats.data.local.database
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
/**
|
||||
* Entity для хранения профиля пользователя в локальной БД Room
|
||||
*/
|
||||
@Entity(tableName = "user_profile")
|
||||
data class UserProfileEntity(
|
||||
@PrimaryKey
|
||||
val userId: String,
|
||||
|
||||
val username: String,
|
||||
|
||||
val displayName: String,
|
||||
|
||||
val avatarUrl: String? = null,
|
||||
|
||||
val bio: String? = null,
|
||||
|
||||
val isOnline: Boolean = false,
|
||||
|
||||
val lastSeenMillis: Long = 0,
|
||||
|
||||
val updatedAtMillis: Long = System.currentTimeMillis()
|
||||
)
|
||||
Reference in New Issue
Block a user