android: use saved chat endpoint in chats menu
Some checks failed
Android CI / android (push) Has started running
Android Release / release (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
Codex
2026-03-09 22:31:00 +03:00
parent c040ebf059
commit bd1229fe5a
7 changed files with 38 additions and 11 deletions

View File

@@ -634,3 +634,8 @@
- Improved `chat_updated` handling in realtime flow:
- now refreshes both active and archived chats lists to sync user-scoped flags (`pinned`, `archived`) immediately.
- Added parser fallback for realtime chat events to support payloads with either `chat_id` or `id`.
### Step 99 - Saved chat API parity
- Added Android support for `GET /api/v1/chats/saved`.
- Wired chats overflow `Saved` action to real backend request (instead of local title heuristic).
- Saved chat is now upserted into local Room cache and opened via normal navigation flow.

View File

@@ -31,6 +31,9 @@ interface ChatApiService {
@Path("chat_id") chatId: Long,
): ChatReadDto
@GET("/api/v1/chats/saved")
suspend fun getSavedChat(): ChatReadDto
@POST("/api/v1/chats/{chat_id}/invite-link")
suspend fun createInviteLink(
@Path("chat_id") chatId: Long,

View File

@@ -87,6 +87,18 @@ class NetworkChatRepository @Inject constructor(
}
}
override suspend fun getSavedChat(): AppResult<ChatItem> = withContext(ioDispatcher) {
try {
val chat = chatApiService.getSavedChat()
chatDao.upsertUsers(chat.toUserShortEntityOrNull()?.let(::listOf).orEmpty())
val entity = chat.toChatEntity()
chatDao.upsertChats(listOf(entity))
AppResult.Success(entity.toDomain())
} catch (error: Throwable) {
AppResult.Error(error.toAppError())
}
}
override suspend fun createInviteLink(chatId: Long): AppResult<ChatInviteLink> = withContext(ioDispatcher) {
try {
AppResult.Success(chatApiService.createInviteLink(chatId = chatId).toDomain())

View File

@@ -14,6 +14,7 @@ interface ChatRepository {
fun observeChat(chatId: Long): Flow<ChatItem?>
suspend fun refreshChats(archived: Boolean): AppResult<Unit>
suspend fun refreshChat(chatId: Long): AppResult<Unit>
suspend fun getSavedChat(): AppResult<ChatItem>
suspend fun createInviteLink(chatId: Long): AppResult<ChatInviteLink>
suspend fun joinByInvite(token: String): AppResult<ChatItem>
suspend fun createChat(

View File

@@ -118,6 +118,7 @@ fun ChatListRoute(
onClearSearchHistory = viewModel::clearSearchHistory,
onRefresh = viewModel::onPullToRefresh,
onOpenChat = onOpenChat,
onOpenSaved = viewModel::openSavedChat,
isMainBarVisible = isMainBarVisible,
onMainBarVisibilityChanged = onMainBarVisibilityChanged,
onCreateGroup = viewModel::createGroup,
@@ -154,6 +155,7 @@ fun ChatListScreen(
onClearSearchHistory: () -> Unit,
onRefresh: () -> Unit,
onOpenChat: (Long) -> Unit,
onOpenSaved: () -> Unit,
isMainBarVisible: Boolean,
onMainBarVisibilityChanged: (Boolean) -> Unit,
onCreateGroup: (String, List<Long>) -> Unit,
@@ -414,15 +416,7 @@ fun ChatListScreen(
leadingIcon = { Icon(Icons.Filled.Inventory2, contentDescription = null) },
onClick = {
showDefaultMenu = false
val saved = state.chats.firstOrNull {
val title = it.displayTitle.lowercase()
title.contains("saved") || title.contains("избран")
}
if (saved != null) {
onOpenChat(saved.id)
} else {
Toast.makeText(context, "Saved chat not found.", Toast.LENGTH_SHORT).show()
}
onOpenSaved()
},
)
DropdownMenuItem(

View File

@@ -150,6 +150,19 @@ class ChatListViewModel @Inject constructor(
}
}
fun openSavedChat() {
viewModelScope.launch {
when (val result = chatRepository.getSavedChat()) {
is AppResult.Success -> {
_uiState.update { it.copy(pendingOpenChatId = result.data.id) }
}
is AppResult.Error -> _uiState.update {
it.copy(errorMessage = result.reason.toUiMessage())
}
}
}
}
fun onManagementChatSelected(chatId: Long?) {
_uiState.update { it.copy(selectedManageChatId = chatId) }
if (chatId != null) {