Skip to content

Commit 96a17e1

Browse files
Merge pull request #17112 from nextcloud/feat/copy-chat
feat(assistant): copy chat
2 parents 22bcf2f + f05ab31 commit 96a17e1

1 file changed

Lines changed: 41 additions & 2 deletions

File tree

app/src/main/java/com/nextcloud/client/assistant/chat/ChatContent.kt

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
package com.nextcloud.client.assistant.chat
1111

12+
import android.content.ClipData
1213
import androidx.compose.animation.core.LinearEasing
1314
import androidx.compose.animation.core.RepeatMode
1415
import androidx.compose.animation.core.animateFloat
@@ -17,6 +18,7 @@ import androidx.compose.animation.core.rememberInfiniteTransition
1718
import androidx.compose.animation.core.tween
1819
import androidx.compose.foundation.Image
1920
import androidx.compose.foundation.background
21+
import androidx.compose.foundation.combinedClickable
2022
import androidx.compose.foundation.layout.Arrangement
2123
import androidx.compose.foundation.layout.Box
2224
import androidx.compose.foundation.layout.Column
@@ -36,18 +38,26 @@ import androidx.compose.foundation.shape.CircleShape
3638
import androidx.compose.foundation.shape.RoundedCornerShape
3739
import androidx.compose.material3.Button
3840
import androidx.compose.material3.CircularProgressIndicator
41+
import androidx.compose.material3.DropdownMenu
42+
import androidx.compose.material3.DropdownMenuItem
3943
import androidx.compose.material3.Icon
4044
import androidx.compose.material3.MaterialTheme
4145
import androidx.compose.material3.Text
4246
import androidx.compose.runtime.Composable
4347
import androidx.compose.runtime.LaunchedEffect
4448
import androidx.compose.runtime.collectAsState
4549
import androidx.compose.runtime.getValue
50+
import androidx.compose.runtime.mutableStateOf
51+
import androidx.compose.runtime.remember
52+
import androidx.compose.runtime.rememberCoroutineScope
53+
import androidx.compose.runtime.setValue
4654
import androidx.compose.ui.Alignment
4755
import androidx.compose.ui.Modifier
4856
import androidx.compose.ui.draw.clip
4957
import androidx.compose.ui.draw.scale
5058
import androidx.compose.ui.layout.ContentScale
59+
import androidx.compose.ui.platform.LocalClipboard
60+
import androidx.compose.ui.platform.toClipEntry
5161
import androidx.compose.ui.res.colorResource
5262
import androidx.compose.ui.res.painterResource
5363
import androidx.compose.ui.res.stringResource
@@ -60,6 +70,7 @@ import com.nextcloud.utils.TimeConstants
6070
import com.nextcloud.utils.extensions.time
6171
import com.owncloud.android.R
6272
import com.owncloud.android.lib.resources.assistant.chat.model.ChatMessage
73+
import kotlinx.coroutines.launch
6374
import java.time.Instant
6475

6576
private val MIN_CHAT_HEIGHT = 60.dp
@@ -340,6 +351,32 @@ private fun TypingAnimation() {
340351
}
341352
}
342353

354+
@Composable
355+
private fun CopyableMessageBubble(text: String, modifier: Modifier = Modifier, content: @Composable () -> Unit) {
356+
var showMenu by remember { mutableStateOf(false) }
357+
val clipboard = LocalClipboard.current
358+
val scope = rememberCoroutineScope()
359+
360+
Box(
361+
modifier = modifier
362+
.combinedClickable(onClick = {}, onLongClick = { showMenu = true })
363+
) {
364+
content()
365+
DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
366+
DropdownMenuItem(
367+
text = { Text(stringResource(R.string.common_copy)) },
368+
onClick = {
369+
scope.launch {
370+
val plainText = ClipData.newPlainText(null, text).toClipEntry()
371+
clipboard.setClipEntry(plainText)
372+
}
373+
showMenu = false
374+
}
375+
)
376+
}
377+
}
378+
}
379+
343380
@Composable
344381
private fun AssistantMessageItem(message: ChatMessage) {
345382
Box(
@@ -363,7 +400,8 @@ private fun AssistantMessageItem(message: ChatMessage) {
363400
alignment = Alignment.Center
364401
)
365402
}
366-
Box(
403+
CopyableMessageBubble(
404+
text = message.content,
367405
modifier = Modifier
368406
.padding(start = 8.dp, end = 16.dp)
369407
.defaultMinSize(minHeight = MIN_CHAT_HEIGHT)
@@ -390,7 +428,8 @@ private fun UserMessageItem(message: ChatMessage) {
390428
.fillMaxWidth(),
391429
contentAlignment = Alignment.CenterEnd
392430
) {
393-
Box(
431+
CopyableMessageBubble(
432+
text = message.content,
394433
modifier = Modifier
395434
.padding(start = 16.dp, end = 8.dp)
396435
.defaultMinSize(minHeight = MIN_CHAT_HEIGHT)

0 commit comments

Comments
 (0)