feat: Enhance FileAttachment component with timestamp and message status display

This commit is contained in:
k1ngsterr1
2026-01-26 13:07:01 +05:00
parent 87932c5fab
commit 99a1156e96

View File

@@ -28,6 +28,7 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -40,6 +41,7 @@ import com.rosetta.messenger.crypto.MessageCrypto
import com.rosetta.messenger.network.AttachmentType import com.rosetta.messenger.network.AttachmentType
import com.rosetta.messenger.network.MessageAttachment import com.rosetta.messenger.network.MessageAttachment
import com.rosetta.messenger.network.TransportManager import com.rosetta.messenger.network.TransportManager
import com.rosetta.messenger.R
import com.rosetta.messenger.repository.AvatarRepository import com.rosetta.messenger.repository.AvatarRepository
import com.rosetta.messenger.ui.chats.models.MessageStatus import com.rosetta.messenger.ui.chats.models.MessageStatus
import com.rosetta.messenger.ui.onboarding.PrimaryBlue import com.rosetta.messenger.ui.onboarding.PrimaryBlue
@@ -104,7 +106,9 @@ fun MessageAttachments(
chachaKey = chachaKey, chachaKey = chachaKey,
privateKey = privateKey, privateKey = privateKey,
isOutgoing = isOutgoing, isOutgoing = isOutgoing,
isDarkTheme = isDarkTheme isDarkTheme = isDarkTheme,
timestamp = timestamp,
messageStatus = messageStatus
) )
} }
AttachmentType.AVATAR -> { AttachmentType.AVATAR -> {
@@ -490,7 +494,9 @@ fun FileAttachment(
chachaKey: String, chachaKey: String,
privateKey: String, privateKey: String,
isOutgoing: Boolean, isOutgoing: Boolean,
isDarkTheme: Boolean isDarkTheme: Boolean,
timestamp: java.util.Date,
messageStatus: MessageStatus = MessageStatus.READ
) { ) {
val context = LocalContext.current val context = LocalContext.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@@ -556,98 +562,101 @@ fun FileAttachment(
} }
// Telegram-style файл - как в desktop: без внутреннего фона, просто иконка + текст // Telegram-style файл - как в desktop: без внутреннего фона, просто иконка + текст
Row( Box(
modifier = Modifier modifier = Modifier.fillMaxWidth()
.fillMaxWidth()
.clickable(enabled = downloadStatus == DownloadStatus.NOT_DOWNLOADED || downloadStatus == DownloadStatus.ERROR) {
download()
}
.padding(vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically
) { ) {
// File icon с индикатором прогресса - круглая иконка как в desktop Row(
Box( modifier = Modifier
modifier = Modifier.size(40.dp), .fillMaxWidth()
contentAlignment = Alignment.Center .clickable(enabled = downloadStatus == DownloadStatus.NOT_DOWNLOADED || downloadStatus == DownloadStatus.ERROR) {
download()
}
.padding(vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically
) { ) {
// Круглый фон иконки // File icon с индикатором прогресса - круглая иконка как в desktop
Box( Box(
modifier = Modifier modifier = Modifier.size(40.dp),
.fillMaxSize()
.clip(CircleShape)
.background(
if (downloadStatus == DownloadStatus.ERROR) Color(0xFFE53935)
else PrimaryBlue
),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
when (downloadStatus) { // Круглый фон иконки
DownloadStatus.DOWNLOADING, DownloadStatus.DECRYPTING -> { Box(
CircularProgressIndicator( modifier = Modifier
modifier = Modifier.size(24.dp), .fillMaxSize()
color = Color.White, .clip(CircleShape)
strokeWidth = 2.dp .background(
) if (downloadStatus == DownloadStatus.ERROR) Color(0xFFE53935)
} else PrimaryBlue
DownloadStatus.NOT_DOWNLOADED -> { ),
Icon( contentAlignment = Alignment.Center
Icons.Default.ArrowDownward, ) {
contentDescription = "Download", when (downloadStatus) {
tint = Color.White, DownloadStatus.DOWNLOADING, DownloadStatus.DECRYPTING -> {
modifier = Modifier.size(20.dp) CircularProgressIndicator(
) modifier = Modifier.size(24.dp),
} color = Color.White,
DownloadStatus.DOWNLOADED -> { strokeWidth = 2.dp
Icon( )
Icons.Default.InsertDriveFile, }
contentDescription = null, DownloadStatus.NOT_DOWNLOADED -> {
tint = Color.White, Icon(
modifier = Modifier.size(20.dp) Icons.Default.ArrowDownward,
) contentDescription = "Download",
} tint = Color.White,
DownloadStatus.ERROR -> { modifier = Modifier.size(20.dp)
Icon( )
Icons.Default.Close, }
contentDescription = "Error", DownloadStatus.DOWNLOADED -> {
tint = Color.White, Icon(
modifier = Modifier.size(20.dp) Icons.Default.InsertDriveFile,
) contentDescription = null,
} tint = Color.White,
else -> { modifier = Modifier.size(20.dp)
Icon( )
Icons.Default.InsertDriveFile, }
contentDescription = null, DownloadStatus.ERROR -> {
tint = Color.White, Icon(
modifier = Modifier.size(20.dp) Icons.Default.Close,
) contentDescription = "Error",
tint = Color.White,
modifier = Modifier.size(20.dp)
)
}
else -> {
Icon(
Icons.Default.InsertDriveFile,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(20.dp)
)
}
} }
} }
} }
}
Spacer(modifier = Modifier.width(10.dp))
// File info
Column(modifier = Modifier.weight(1f)) {
Text(
text = fileName,
fontSize = 14.sp,
fontWeight = FontWeight.Normal,
color = if (isOutgoing) Color.White else (if (isDarkTheme) Color.White else Color.Black),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.height(2.dp))
// Размер файла и тип Spacer(modifier = Modifier.width(10.dp))
val fileExtension = fileName.substringAfterLast('.', "").uppercase()
Text( // File info
text = when (downloadStatus) { Column(modifier = Modifier.weight(1f)) {
DownloadStatus.DOWNLOADING -> "Downloading..." Text(
DownloadStatus.DECRYPTING -> "Decrypting..." text = fileName,
DownloadStatus.ERROR -> "File expired" fontSize = 14.sp,
else -> "${formatFileSize(fileSize)} $fileExtension" fontWeight = FontWeight.Normal,
}, color = if (isOutgoing) Color.White else (if (isDarkTheme) Color.White else Color.Black),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.height(2.dp))
// Размер файла и тип
val fileExtension = fileName.substringAfterLast('.', "").uppercase()
Text(
text = when (downloadStatus) {
DownloadStatus.DOWNLOADING -> "Downloading..."
DownloadStatus.DECRYPTING -> "Decrypting..."
DownloadStatus.ERROR -> "File expired"
else -> "${formatFileSize(fileSize)} $fileExtension"
},
fontSize = 12.sp, fontSize = 12.sp,
color = if (downloadStatus == DownloadStatus.ERROR) { color = if (downloadStatus == DownloadStatus.ERROR) {
Color(0xFFE53935) Color(0xFFE53935)
@@ -659,11 +668,69 @@ fun FileAttachment(
) )
} }
} }
// Time and checkmarks (bottom-right overlay) for outgoing files
if (isOutgoing) {
Row(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(bottom = 6.dp, end = 4.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
) {
// Time
Text(
text = android.text.format.DateFormat.format("HH:mm", timestamp).toString(),
fontSize = 11.sp,
color = Color.White.copy(alpha = 0.7f)
)
Spacer(modifier = Modifier.width(4.dp))
// Checkmarks
when (messageStatus) {
MessageStatus.SENDING -> {
Icon(
compose.icons.TablerIcons.Clock,
contentDescription = null,
tint = Color.White.copy(alpha = 0.7f),
modifier = Modifier.size(14.dp)
)
}
MessageStatus.SENT -> {
Icon(
compose.icons.TablerIcons.Check,
contentDescription = null,
tint = Color.White.copy(alpha = 0.7f),
modifier = Modifier.size(14.dp)
)
}
MessageStatus.DELIVERED, MessageStatus.READ -> {
Icon(
compose.icons.TablerIcons.Checks,
contentDescription = null,
tint = if (messageStatus == MessageStatus.READ) {
Color(0xFF4FC3F7)
} else {
Color.White.copy(alpha = 0.7f)
},
modifier = Modifier.size(14.dp)
)
}
MessageStatus.ERROR -> {
Icon(
Icons.Default.Error,
contentDescription = null,
tint = Color(0xFFE53935),
modifier = Modifier.size(14.dp)
)
}
}
}
}
}
} }
/**
* Avatar attachment - Telegram style
*/
@Composable @Composable
fun AvatarAttachment( fun AvatarAttachment(
attachment: MessageAttachment, attachment: MessageAttachment,