feat(android): make chat info entries clickable and open from header
This commit is contained in:
@@ -2,12 +2,14 @@ package ru.daemonlord.messenger.ui.chat
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.media.AudioAttributes
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.media.MediaPlayer
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.widget.Toast
|
||||
import android.widget.VideoView
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -297,6 +299,7 @@ fun ChatScreen(
|
||||
onJumpInlineSearch: (Boolean) -> Unit,
|
||||
onVisibleIncomingMessageId: (Long?) -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val listState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
val allImageUrls = remember(state.messages) {
|
||||
@@ -473,6 +476,15 @@ fun ChatScreen(
|
||||
contentDescription = "Back",
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.clickable { showChatInfoSheet = true }
|
||||
.padding(vertical = 2.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
if (!state.chatAvatarUrl.isNullOrBlank()) {
|
||||
AsyncImage(
|
||||
model = state.chatAvatarUrl,
|
||||
@@ -511,6 +523,7 @@ fun ChatScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
IconButton(
|
||||
onClick = { showInlineSearch = !showInlineSearch },
|
||||
enabled = !state.isLoadingMore,
|
||||
@@ -1056,6 +1069,32 @@ fun ChatScreen(
|
||||
ChatInfoTabContent(
|
||||
tab = chatInfoTab,
|
||||
entries = chatInfoEntries,
|
||||
onEntryClick = { entry ->
|
||||
when (entry.type) {
|
||||
ChatInfoEntryType.Media -> {
|
||||
val url = entry.resourceUrl.orEmpty()
|
||||
if (url.isBlank()) return@ChatInfoTabContent
|
||||
if (entry.previewIsVideo) {
|
||||
viewerVideoUrl = url
|
||||
} else {
|
||||
val index = allImageUrls.indexOf(url)
|
||||
if (index >= 0) {
|
||||
viewerImageIndex = index
|
||||
} else {
|
||||
openUrlExternally(context, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
ChatInfoEntryType.Link -> {
|
||||
entry.resourceUrl?.let { openUrlExternally(context, it) }
|
||||
}
|
||||
ChatInfoEntryType.File,
|
||||
ChatInfoEntryType.Voice,
|
||||
-> {
|
||||
entry.resourceUrl?.let { openUrlExternally(context, it) }
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2787,6 +2826,18 @@ private fun formatBytes(value: Long): String {
|
||||
}
|
||||
}
|
||||
|
||||
private fun openUrlExternally(context: Context, url: String) {
|
||||
if (url.isBlank()) return
|
||||
runCatching {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}.onFailure {
|
||||
Toast.makeText(context, "Unable to open item", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private enum class ChatInfoTab(val title: String) {
|
||||
Media("Media"),
|
||||
Files("Files"),
|
||||
@@ -2805,6 +2856,8 @@ private data class ChatInfoEntry(
|
||||
val type: ChatInfoEntryType,
|
||||
val title: String,
|
||||
val subtitle: String,
|
||||
val resourceUrl: String? = null,
|
||||
val sourceMessageId: Long? = null,
|
||||
val previewImageUrl: String? = null,
|
||||
val previewIsVideo: Boolean = false,
|
||||
)
|
||||
@@ -2813,6 +2866,7 @@ private data class ChatInfoEntry(
|
||||
private fun ChatInfoTabContent(
|
||||
tab: ChatInfoTab,
|
||||
entries: List<ChatInfoEntry>,
|
||||
onEntryClick: (ChatInfoEntry) -> Unit,
|
||||
) {
|
||||
val filtered = remember(tab, entries) {
|
||||
entries.filter {
|
||||
@@ -2854,7 +2908,8 @@ private fun ChatInfoTabContent(
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f)),
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f))
|
||||
.clickable { onEntryClick(entry) },
|
||||
) {
|
||||
if (!entry.previewImageUrl.isNullOrBlank()) {
|
||||
AsyncImage(
|
||||
@@ -2906,6 +2961,7 @@ private fun ChatInfoTabContent(
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(MaterialTheme.colorScheme.surface.copy(alpha = 0.55f))
|
||||
.clickable { onEntryClick(entry) }
|
||||
.padding(horizontal = 10.dp, vertical = 9.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
@@ -2982,6 +3038,8 @@ private fun buildChatInfoEntries(messages: List<MessageItem>): List<ChatInfoEntr
|
||||
type = ChatInfoEntryType.Media,
|
||||
title = extractFileName(attachment.fileUrl),
|
||||
subtitle = "$time • ${attachment.fileType}",
|
||||
resourceUrl = attachment.fileUrl,
|
||||
sourceMessageId = message.id,
|
||||
previewImageUrl = if (normalized.startsWith("image/")) attachment.fileUrl else null,
|
||||
previewIsVideo = normalized.startsWith("video/"),
|
||||
)
|
||||
@@ -2992,6 +3050,8 @@ private fun buildChatInfoEntries(messages: List<MessageItem>): List<ChatInfoEntr
|
||||
type = ChatInfoEntryType.Voice,
|
||||
title = extractFileName(attachment.fileUrl),
|
||||
subtitle = "$time • ${formatBytes(attachment.fileSize)}",
|
||||
resourceUrl = attachment.fileUrl,
|
||||
sourceMessageId = message.id,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3000,6 +3060,8 @@ private fun buildChatInfoEntries(messages: List<MessageItem>): List<ChatInfoEntr
|
||||
type = ChatInfoEntryType.File,
|
||||
title = extractFileName(attachment.fileUrl),
|
||||
subtitle = "$time • ${formatBytes(attachment.fileSize)}",
|
||||
resourceUrl = attachment.fileUrl,
|
||||
sourceMessageId = message.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3009,6 +3071,8 @@ private fun buildChatInfoEntries(messages: List<MessageItem>): List<ChatInfoEntr
|
||||
type = ChatInfoEntryType.Link,
|
||||
title = match.value,
|
||||
subtitle = "${message.senderDisplayName ?: "Unknown"} • $time",
|
||||
resourceUrl = match.value,
|
||||
sourceMessageId = message.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user