feat: Enhance account handling and message delivery status updates; improve UI feedback for saved messages

This commit is contained in:
k1ngsterr1
2026-01-18 18:12:45 +05:00
parent 61995e9286
commit b8aba7714c
4 changed files with 87 additions and 81 deletions

View File

@@ -170,6 +170,8 @@ class MainActivity : ComponentActivity() {
targetState = when { targetState = when {
showSplash -> "splash" showSplash -> "splash"
showOnboarding && hasExistingAccount == false -> "onboarding" showOnboarding && hasExistingAccount == false -> "onboarding"
// 🔥 КРИТИЧНО: если currentAccount != null - сразу на main без ожидания isLoggedIn
currentAccount != null -> "main"
isLoggedIn != true && hasExistingAccount == false -> "auth_new" isLoggedIn != true && hasExistingAccount == false -> "auth_new"
isLoggedIn != true && hasExistingAccount == true -> "auth_unlock" isLoggedIn != true && hasExistingAccount == true -> "auth_unlock"
else -> "main" else -> "main"
@@ -210,7 +212,13 @@ class MainActivity : ComponentActivity() {
currentAccount = account currentAccount = account
hasExistingAccount = true hasExistingAccount = true
// Save as last logged account // Save as last logged account
account?.let { accountManager.setLastLoggedPublicKey(it.publicKey) } account?.let {
accountManager.setLastLoggedPublicKey(it.publicKey)
// 🔥 КРИТИЧНО: Сразу устанавливаем флаг логина чтобы не было Loading экрана
scope.launch {
accountManager.setCurrentAccount(it.publicKey)
}
}
// 📤 Отправляем FCM токен на сервер после успешной аутентификации // 📤 Отправляем FCM токен на сервер после успешной аутентификации
account?.let { sendFcmTokenToServer(it) } account?.let { sendFcmTokenToServer(it) }
@@ -354,33 +362,22 @@ fun MainScreen(
onToggleTheme: () -> Unit = {}, onToggleTheme: () -> Unit = {},
onLogout: () -> Unit = {} onLogout: () -> Unit = {}
) { ) {
// 🔥 КРИТИЧНО: Если account == null, показываем загрузку вместо мокового аккаунта // 🔥 Используем моковый аккаунт если account == null (для предотвращения крашей)
if (account == null) { val effectiveAccount = account ?: DecryptedAccount(
Box( publicKey = "loading",
modifier = Modifier privateKey = "loading",
.fillMaxSize() seedPhrase = emptyList(),
.background(if (isDarkTheme) Color(0xFF1B1B1B) else Color.White), privateKeyHash = "loading",
contentAlignment = Alignment.Center name = "Loading..."
) { )
Column(horizontalAlignment = Alignment.CenterHorizontally) {
CircularProgressIndicator()
Spacer(modifier = Modifier.height(16.dp))
Text(
"Loading account...",
color = if (isDarkTheme) Color.White else Color.Black
)
}
}
return
}
val accountName = account.name val accountName = effectiveAccount.name
val accountPhone = account.publicKey.take(16).let { val accountPhone = effectiveAccount.publicKey.take(16).let {
"+${it.take(1)} ${it.substring(1, 4)} ${it.substring(4, 7)}${it.substring(7)}" "+${it.take(1)} ${it.substring(1, 4)} ${it.substring(4, 7)}${it.substring(7)}"
} }
val accountPublicKey = account.publicKey val accountPublicKey = effectiveAccount.publicKey
val accountPrivateKey = account.privateKey val accountPrivateKey = effectiveAccount.privateKey
val privateKeyHash = account.privateKeyHash val privateKeyHash = effectiveAccount.privateKeyHash
// Состояние протокола для передачи в SearchScreen // Состояние протокола для передачи в SearchScreen
val protocolState by ProtocolManager.state.collectAsState() val protocolState by ProtocolManager.state.collectAsState()

View File

@@ -368,6 +368,9 @@ class MessageRepository private constructor(private val context: Context) {
// Обновляем кэш // Обновляем кэш
val dialogKey = getDialogKey(packet.toPublicKey) val dialogKey = getDialogKey(packet.toPublicKey)
updateMessageStatus(dialogKey, packet.messageId, DeliveryStatus.DELIVERED) updateMessageStatus(dialogKey, packet.messageId, DeliveryStatus.DELIVERED)
// 🔥 КРИТИЧНО: Обновляем диалог чтобы lastMessageDelivered обновился
dialogDao.updateDialogFromMessages(account, packet.toPublicKey)
} }
/** /**
@@ -389,6 +392,9 @@ class MessageRepository private constructor(private val context: Context) {
else msg else msg
} }
} }
// 🔥 КРИТИЧНО: Обновляем диалог чтобы lastMessageRead обновился
dialogDao.updateDialogFromMessages(account, packet.fromPublicKey)
} }
/** /**

View File

@@ -549,6 +549,7 @@ interface DialogDao {
COALESCE( COALESCE(
(SELECT delivered FROM messages (SELECT delivered FROM messages
WHERE account = :account WHERE account = :account
AND from_me = 1
AND ((from_public_key = :opponentKey AND to_public_key = :account) AND ((from_public_key = :opponentKey AND to_public_key = :account)
OR (from_public_key = :account AND to_public_key = :opponentKey)) OR (from_public_key = :account AND to_public_key = :opponentKey))
ORDER BY timestamp DESC LIMIT 1), ORDER BY timestamp DESC LIMIT 1),
@@ -557,6 +558,7 @@ interface DialogDao {
COALESCE( COALESCE(
(SELECT read FROM messages (SELECT read FROM messages
WHERE account = :account WHERE account = :account
AND from_me = 1
AND ((from_public_key = :opponentKey AND to_public_key = :account) AND ((from_public_key = :opponentKey AND to_public_key = :account)
OR (from_public_key = :account AND to_public_key = :opponentKey)) OR (from_public_key = :account AND to_public_key = :opponentKey))
ORDER BY timestamp DESC LIMIT 1), ORDER BY timestamp DESC LIMIT 1),
@@ -639,22 +641,8 @@ interface DialogDao {
) AS verified, ) AS verified,
1 AS i_have_sent, 1 AS i_have_sent,
1 AS last_message_from_me, 1 AS last_message_from_me,
COALESCE( 1 AS last_message_delivered,
(SELECT delivered FROM messages 1 AS last_message_read
WHERE account = :account
AND from_public_key = :account
AND to_public_key = :account
ORDER BY timestamp DESC LIMIT 1),
0
) AS last_message_delivered,
COALESCE(
(SELECT read FROM messages
WHERE account = :account
AND from_public_key = :account
AND to_public_key = :account
ORDER BY timestamp DESC LIMIT 1),
0
) AS last_message_read
WHERE EXISTS ( WHERE EXISTS (
SELECT 1 FROM messages SELECT 1 FROM messages
WHERE account = :account WHERE account = :account

View File

@@ -1648,47 +1648,62 @@ fun DialogItemContent(
) { ) {
// Показываем статус только для исходящих сообщений // Показываем статус только для исходящих сообщений
if (dialog.lastMessageFromMe == 1) { if (dialog.lastMessageFromMe == 1) {
when (dialog.lastMessageDelivered) { // 📁 Для Saved Messages всегда синие двойные галочки (прочитано)
2 -> { if (dialog.isSavedMessages) {
// ERROR - показываем иконку ошибки Icon(
Icon( imageVector = Icons.Default.DoneAll,
imageVector = Icons.Outlined.ErrorOutline, contentDescription = null,
contentDescription = "Sending failed", tint = PrimaryBlue,
tint = Color(0xFFFF3B30), // iOS красный modifier = Modifier.size(16.dp)
modifier = Modifier.size(16.dp) )
) Spacer(modifier = Modifier.width(4.dp))
Spacer(modifier = Modifier.width(4.dp)) } else {
} // 🔥 ЛОГИКА КАК В ДЕСКТОПЕ:
1 -> { // Если delivered == DELIVERED:
// DELIVERED - две галочки // - unreadCount > 0 → одна галочка (есть непрочитанные входящие, собеседник не ответил)
val checkmarkColor = if (dialog.lastMessageRead == 1) { // - unreadCount == 0 → две галочки (нет непрочитанных, собеседник видел/ответил)
PrimaryBlue // прочитано - синие when {
} else { dialog.lastMessageDelivered == 2 -> {
secondaryTextColor.copy(alpha = 0.6f) // доставлено - серые // ERROR - показываем иконку ошибки
Icon(
imageVector = Icons.Outlined.ErrorOutline,
contentDescription = "Sending failed",
tint = Color(0xFFFF3B30), // iOS красный
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(4.dp))
}
dialog.lastMessageDelivered == 1 -> {
// DELIVERED - смотрим на unreadCount
if (dialog.unreadCount > 0) {
// Есть непрочитанные входящие → одна серая галочка
Icon(
imageVector = Icons.Default.Done,
contentDescription = null,
tint = secondaryTextColor.copy(alpha = 0.6f),
modifier = Modifier.size(16.dp)
)
} else {
// Нет непрочитанных → две синие галочки (прочитано)
Icon(
imageVector = Icons.Default.DoneAll,
contentDescription = null,
tint = PrimaryBlue,
modifier = Modifier.size(16.dp)
)
}
Spacer(modifier = Modifier.width(4.dp))
}
else -> {
// SENT/WAITING - одна серая галочка
Icon(
imageVector = Icons.Default.Done,
contentDescription = null,
tint = secondaryTextColor.copy(alpha = 0.6f),
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(4.dp))
} }
Icon(
imageVector = Icons.Default.Done,
contentDescription = null,
tint = checkmarkColor,
modifier = Modifier.size(14.dp)
)
Icon(
imageVector = Icons.Default.Done,
contentDescription = null,
tint = checkmarkColor,
modifier = Modifier.size(14.dp).offset(x = (-6).dp)
)
Spacer(modifier = Modifier.width(2.dp))
}
0 -> {
// WAITING - одна серая галочка (отправлено, ждём доставку)
Icon(
imageVector = Icons.Default.Done,
contentDescription = null,
tint = secondaryTextColor.copy(alpha = 0.6f),
modifier = Modifier.size(14.dp)
)
Spacer(modifier = Modifier.width(4.dp))
} }
} }
} }