# Руководство по интеграции ## Быстрый старт ### 1. Добавление зависимостей В `app/build.gradle.kts` уже добавлены: ```kotlin // Paging 3 implementation("androidx.paging:paging-runtime-ktx:3.2.1") implementation("androidx.paging:paging-compose:3.2.1") // WorkManager + Hilt implementation("androidx.work:work-runtime-ktx:2.9.0") implementation("androidx.hilt:hilt-work:1.1.0") kapt("androidx.hilt:hilt-compiler:1.1.0") ``` ### 2. Обновление Application класса `MainApplication.kt` уже обновлён: ```kotlin @HiltAndroidApp class MainApplication : Application(), ImageLoaderFactory, Configuration.Provider { @Inject lateinit var workerFactory: WorkerFactory override val workManagerConfiguration: Configuration get() = Configuration.Builder() .setWorkerFactory(workerFactory) .setMinimumLoggingLevel(android.util.Log.INFO) .build() } ``` ### 3. Миграция базы данных База данных автоматически обновится при первом запуске благодаря `MIGRATION_1_2`. ## Использование в ViewModel ### Вариант 1: Paging 3 (рекомендуется для больших чатов) ```kotlin @HiltViewModel class ChatViewModel @Inject constructor( private val repository: ChatRepository, savedStateHandle: SavedStateHandle ) : ViewModel() { private val chatId: String = savedStateHandle["chatId"] ?: "" val messages: Flow> = repository .getMessagesPaging(chatId) .cachedIn(viewModelScope) fun sendMessage(content: String) { viewModelScope.launch { repository.sendMessage(chatId, content, "text") } } fun deleteMessage(messageId: String) { viewModelScope.launch { repository.deleteLocalMessage(messageId) } } } ``` ### Вариант 2: Простой Flow (для небольших чатов) ```kotlin @HiltViewModel class ChatViewModel @Inject constructor( private val repository: ChatRepository, savedStateHandle: SavedStateHandle ) : ViewModel() { private val chatId: String = savedStateHandle["chatId"] ?: "" val messages: Flow> = repository .getMessagesFlow(chatId) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) } ``` ## Использование в UI (Compose) ### С Paging 3 ```kotlin @Composable fun ChatScreen(viewModel: ChatViewModel = hiltViewModel()) { val messages by viewModel.messages.collectAsLazyPagingItems() LazyColumn( reverseLayout = true, // Сообщения снизу вверх modifier = Modifier.fillMaxSize() ) { items( count = messages.itemCount, key = messages.key ) { index -> messages[index]?.let { message -> MessageItem(message = message) } } // Индикатор загрузки when { messages.loadState.refresh is LoadState.Loading -> { item { LoadingIndicator() } } messages.loadState.append is LoadState.Loading -> { item { LoadingIndicator() } } } // Ошибки messages.loadState.append.let { loadState -> if (loadState is LoadState.Error) { item { Text("Ошибка: ${loadState.error.message}") Button(onClick = { messages.retry() }) { Text("Повторить") } } } } } } ``` ### С простым Flow ```kotlin @Composable fun ChatScreen(viewModel: ChatViewModel = hiltViewModel()) { val messages by viewModel.messages.collectAsState() LazyColumn(reverseLayout = true) { items(messages) { message -> MessageItem(message = message) } } } ``` ## Отправка сообщения ```kotlin // Мгновенное отображение в UI viewModel.sendMessage("Привет!") // Сообщение сохраняется локально и появляется в UI сразу // WorkManager отправит его на сервер в фоне ``` ## Удаление сообщения ```kotlin // Мягкое удаление (через WorkManager) viewModel.deleteMessage(messageId) // Или немедленное удаление viewModelScope.launch { repository.deleteMessage(messageId, forEveryone = false) } ``` ## Редактирование сообщения ```kotlin viewModelScope.launch { repository.editLocalMessage(messageId, "Новый текст") } ``` ## Мониторинг синхронизации ```kotlin // В ViewModel val syncStatus: Flow> = messageDao .getPendingSyncMessagesFlow() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList()) // В UI val pendingMessages by syncStatus.collectAsState() if (pendingMessages.isNotEmpty()) { Text("${pendingMessages.size} сообщений ожидают отправки") } ``` ## Обработка офлайн-режима ```kotlin @Composable fun MessageItem(message: Message) { val isPending = message.id.startsWith("local_") Row(modifier = Modifier.fillMaxWidth()) { Text( text = message.content ?: "", modifier = Modifier.weight(1f) ) // Индикатор отправки if (isPending) { CircularProgressIndicator( modifier = Modifier.size(16.dp), strokeWidth = 2.dp ) } // Статус прочтения Icon( imageVector = if (message.isRead) Icons.Default.DoneAll else Icons.Default.Done, contentDescription = null ) } } ``` ## Проверка сборки ```bash cd client-mobile ./gradlew assembleDebug ``` ## Возможные проблемы и решения ### 1. Ошибка: "WorkerFactory not found" **Решение:** Убедитесь, что `MainApplication` реализует `Configuration.Provider` ### 2. Ошибка: "Table messages has no column named syncStatus" **Решение:** Проверьте, что миграция `MIGRATION_1_2` добавлена в `DatabaseModule` ### 3. Paging не загружает данные **Решение:** Проверьте логи `MessageRemoteMediator` - возможны проблемы с API ### 4. Сообщения не синхронизируются **Решение:** Проверьте WorkManager логи и наличие сетевого подключения ### 5. SignalR не подключается **Решение:** Проверьте `ChatHubClient.connect()` - должен вызываться после авторизации ## Тестирование ### Юнит-тесты ```kotlin @Test fun `message saved locally should have SYNCING status`() = runTest { val message = MessageEntity( id = "test", chatId = "chat1", // ... syncStatus = SyncStatus.SYNCING ) dao.insertMessage(message) val saved = dao.getMessageById("test") assertEquals(SyncStatus.SYNCING, saved?.syncStatus) } ``` ### Интеграционные тесты ```kotlin @Test fun `sending message should save locally and sync to server`() = runTest { // Arrange val repository = ChatRepositoryImpl(...) // Act val message = repository.sendMessage("chat1", "Hello", "text") // Assert assertTrue(message.id.startsWith("local_")) // Wait for sync delay(5000) val synced = dao.getMessageById(message.id) assertEquals(SyncStatus.SYNCED, synced?.syncStatus) } ``` ## Дополнительные ресурсы - [Paging 3 Documentation](https://developer.android.com/topic/libraries/architecture/paging/v3-overview) - [WorkManager Documentation](https://developer.android.com/topic/libraries/architecture/workmanager) - [Room Documentation](https://developer.android.com/training/data-storage/room) - [ARCHITECTURE.md](ARCHITECTURE.md) - детальное описание архитектуры - [USAGE_EXAMPLES.md](USAGE_EXAMPLES.md) - больше примеров использования