Browse Source

Open Android web links from shared channel and PM message UI

master
evgeny 5 days ago
parent
commit
2e41610693
  1. 38
      tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationMessages.kt

38
tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationMessages.kt

@ -2,8 +2,14 @@ package com.utun.chat.ui.components
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.*
import android.content.Intent
import android.content.ActivityNotFoundException
import android.net.Uri
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Offset
@ -14,11 +20,13 @@ import androidx.compose.ui.graphics.ShaderBrush
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.utun.chat.R
import com.utun.chat.data.ConversationTarget
import com.utun.chat.data.LogManager
import com.utun.chat.data.Message
import com.utun.chat.data.MessageLinks
import com.utun.chat.viewmodel.ChatViewModel
/** Общий список; направление включено в ключ, поскольку PM имеет два потока seq. */
@ -29,6 +37,30 @@ fun ConversationMessages(target: ConversationTarget, messages: List<Message>, st
onOpenFile: (Message) -> Unit, onPlayVideo: (Message) -> Unit,
onDownloadFile: (Message) -> Unit = {}, onOpenImage: (Message) -> Unit = {},
onInviteLink: (String) -> Unit = {}) {
val context = LocalContext.current
var openFailed by remember { mutableStateOf(false) }
val onLink: (String) -> Unit = { link ->
if (link.startsWith("utun://")) onInviteLink(link)
else if (!MessageLinks.isWebUrl(link)) {
LogManager.addLog("ERROR", "LINK", "invalid external message link: bytes=${link.length}")
openFailed = true
} else {
val uri = Uri.parse(link)
try {
context.startActivity(Intent(Intent.ACTION_VIEW, uri))
LogManager.addLog("INFO", "LINK", "external open requested: scheme=${uri.scheme} host=${uri.host}")
} catch (e: ActivityNotFoundException) {
LogManager.addLog("ERROR", "LINK", "no URL handler: scheme=${uri.scheme} host=${uri.host} error=${e.message}")
openFailed = true
} catch (e: SecurityException) {
LogManager.addLog("ERROR", "LINK", "URL handler denied: scheme=${uri.scheme} host=${uri.host} error=${e.message}")
openFailed = true
}
}
}
if (openFailed) AlertDialog(onDismissRequest = { openFailed = false },
text = { Text(stringResource(R.string.link_open_failed)) },
confirmButton = { TextButton(onClick = { openFailed = false }) { Text(stringResource(R.string.close)) } })
val background = ImageBitmap.imageResource(R.drawable.chat_background)
LaunchedEffect(background) {
LogManager.addLog("DEBUG", "UI", "Chat background ready: desktop bg.png tile=${background.width}x${background.height}")
@ -45,7 +77,7 @@ fun ConversationMessages(target: ConversationTarget, messages: List<Message>, st
LazyColumn(modifier = modifier.then(backgroundModifier), state = state, reverseLayout = true) {
item { Spacer(Modifier.height(8.dp)) }
items(messages.reversed(), key = { "${target.nativeId}:${it.isOutgoing}:${it.id}" }) { message ->
MessageBubble(message, playbackState, onPlayVoice, onSeekVoice, onDownloadFile, onOpenFile, onOpenImage, onPlayVideo, onInviteLink)
MessageBubble(message, playbackState, onPlayVoice, onSeekVoice, onDownloadFile, onOpenFile, onOpenImage, onPlayVideo, onLink)
}
}
}

Loading…
Cancel
Save