feat: Add VerifiedBadge and online status to user profile header

This commit is contained in:
k1ngsterr1
2026-01-25 18:43:40 +05:00
parent efd666ee41
commit 37acbfeef6
3 changed files with 74 additions and 14 deletions

View File

@@ -613,6 +613,22 @@ class MessageRepository private constructor(private val context: Context) {
} }
/**
* Наблюдать за онлайн статусом пользователя
*/
fun observeUserOnlineStatus(publicKey: String): Flow<Pair<Boolean, Long>> {
val account = currentAccount ?: return flowOf(false to 0L)
return dialogDao.observeOnlineStatus(account, publicKey)
.map { info ->
if (info != null) {
(info.isOnline == 1) to info.lastSeen
} else {
false to 0L
}
}
}
/** /**
* Обновить информацию о пользователе в диалоге (имя, username, verified) * Обновить информацию о пользователе в диалоге (имя, username, verified)
* Вызывается когда приходит ответ на PacketSearch * Вызывается когда приходит ответ на PacketSearch

View File

@@ -478,6 +478,22 @@ interface DialogDao {
""") """)
suspend fun updateOnlineStatus(account: String, opponentKey: String, isOnline: Int, lastSeen: Long) suspend fun updateOnlineStatus(account: String, opponentKey: String, isOnline: Int, lastSeen: Long)
/**
* Получить онлайн статус пользователя
*/
@Query("""
SELECT is_online, last_seen
FROM dialogs
WHERE account = :account AND opponent_key = :opponentKey
LIMIT 1
""")
fun observeOnlineStatus(account: String, opponentKey: String): Flow<OnlineStatusInfo?>
data class OnlineStatusInfo(
@ColumnInfo(name = "is_online") val isOnline: Int,
@ColumnInfo(name = "last_seen") val lastSeen: Long
)
/** /**
* Удалить диалог * Удалить диалог
*/ */

View File

@@ -15,7 +15,9 @@ import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.outlined.Block import androidx.compose.material.icons.outlined.Block
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import com.rosetta.messenger.data.MessageRepository
import com.rosetta.messenger.ui.onboarding.PrimaryBlue import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.components.VerifiedBadge
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@@ -60,6 +62,13 @@ fun OtherProfileScreen(
val avatarColors = getAvatarColor(user.publicKey, isDarkTheme) val avatarColors = getAvatarColor(user.publicKey, isDarkTheme)
val context = LocalContext.current val context = LocalContext.current
// 🟢 Наблюдаем за онлайн статусом пользователя в реальном времени
val messageRepository = remember { MessageRepository.getInstance(context) }
val onlineStatus by messageRepository.observeUserOnlineStatus(user.publicKey)
.collectAsState(initial = false to 0L)
val isOnline = onlineStatus.first
val lastSeen = onlineStatus.second
// Scroll state for collapsing header animation // Scroll state for collapsing header animation
val density = LocalDensity.current val density = LocalDensity.current
val statusBarHeight = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() val statusBarHeight = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
@@ -153,6 +162,9 @@ fun OtherProfileScreen(
name = user.title.ifEmpty { "Unknown User" }, name = user.title.ifEmpty { "Unknown User" },
username = user.username, username = user.username,
publicKey = user.publicKey, publicKey = user.publicKey,
verified = user.verified,
isOnline = isOnline,
lastSeen = lastSeen,
avatarColors = avatarColors, avatarColors = avatarColors,
collapseProgress = collapseProgress, collapseProgress = collapseProgress,
onBack = onBack, onBack = onBack,
@@ -172,6 +184,9 @@ private fun CollapsingOtherProfileHeader(
name: String, name: String,
username: String, username: String,
publicKey: String, publicKey: String,
verified: Int,
isOnline: Boolean,
lastSeen: Long,
avatarColors: AvatarColors, avatarColors: AvatarColors,
collapseProgress: Float, collapseProgress: Float,
onBack: () -> Unit, onBack: () -> Unit,
@@ -309,7 +324,7 @@ private fun CollapsingOtherProfileHeader(
} }
// ═══════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════
// 📝 TEXT BLOCK - Name + Online, always centered // 📝 TEXT BLOCK - Name + Verified + Online, always centered
// ═══════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════
Column( Column(
modifier = Modifier modifier = Modifier
@@ -323,24 +338,37 @@ private fun CollapsingOtherProfileHeader(
}, },
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text( // Name + Verified Badge
text = name, Row(
fontSize = nameFontSize, verticalAlignment = Alignment.CenterVertically,
fontWeight = FontWeight.SemiBold, horizontalArrangement = Arrangement.Center
color = Color.White, ) {
maxLines = 1, Text(
overflow = TextOverflow.Ellipsis, text = name,
modifier = Modifier.widthIn(max = 220.dp), fontSize = nameFontSize,
textAlign = TextAlign.Center fontWeight = FontWeight.SemiBold,
) color = Color.White,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)
if (verified > 0) {
Spacer(modifier = Modifier.width(4.dp))
VerifiedBadge(
verified = verified,
size = (nameFontSize.value * 0.8f).toInt()
)
}
}
Spacer(modifier = Modifier.height(2.dp)) Spacer(modifier = Modifier.height(2.dp))
// Online text - always centered // Online/Offline status
Text( Text(
text = "online", text = if (isOnline) "online" else "offline",
fontSize = onlineFontSize, fontSize = onlineFontSize,
color = Color(0xFF4CAF50) color = if (isOnline) Color(0xFF4CAF50) else Color.White.copy(alpha = 0.6f)
) )
} }
} }