fix(#391): resolve 5 deprecation warnings (#392)

* fix(#391): resolve deprecation warnings

- Icon: Icons.Filled.ArrowForward → Icons.AutoMirrored.Filled.ArrowForward (KanbanScreen)
- Room: fallbackToDestructiveMigration() → fallbackToDestructiveMigration(false) (HermesDatabase)
- Tab: ScrollableTabRow → PrimaryScrollableTabRow (SettingsScreen)
- Clipboard: LocalClipboardManager → LocalClipboard + coroutine-scoped setText (ChatBubble: UserBubble, AssistantBubble, ToolBubble, CopyButton)
- ClickableText: pushStringAnnotation → pushLink(LinkAnnotation.Url), ClickableText → Text with native link handling (ChatBubble: RichText)

* fix(#392): replace deprecated setText with setClipEntry for new Clipboard API

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-06-26 05:25:01 +03:00
1 parent b1fca60511
commit 8d3d8a11e8
4 files changed
+30 -27

No files matched your search

@@ -39,7 +39,7 @@ abstract class HermesDatabase : RoomDatabase() {
HermesDatabase::class.java, HermesDatabase::class.java,
"hermes_control.db", "hermes_control.db",
).openHelperFactory(factory) ).openHelperFactory(factory)
.fallbackToDestructiveMigration() .fallbackToDestructiveMigration(false)
.build() .build()
.also { instance = it } .also { instance = it }
} }
@@ -1,5 +1,6 @@
package com.m57.hermescontrol.ui.chat package com.m57.hermescontrol.ui.chat
import android.content.ClipData
import android.text.format.DateFormat import android.text.format.DateFormat
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
@@ -27,7 +28,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Build
@@ -47,6 +47,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -54,14 +55,15 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
@@ -82,6 +84,7 @@ import com.m57.hermescontrol.theme.ToolChipColor
import com.m57.hermescontrol.theme.ToolChipColorLight import com.m57.hermescontrol.theme.ToolChipColorLight
import com.m57.hermescontrol.theme.UserBubble import com.m57.hermescontrol.theme.UserBubble
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.time.Instant import java.time.Instant
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -141,7 +144,8 @@ private fun UserBubble(
isCurrentMatch: Boolean = false, isCurrentMatch: Boolean = false,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val clipboardManager = LocalClipboardManager.current val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
var showCopyButton by remember { mutableStateOf(false) } var showCopyButton by remember { mutableStateOf(false) }
// Auto-dismiss copy button after 4 seconds // Auto-dismiss copy button after 4 seconds
@@ -255,7 +259,9 @@ private fun UserBubble(
) { ) {
IconButton( IconButton(
onClick = { onClick = {
clipboardManager.setText(AnnotatedString(message.content)) scope.launch {
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(null, message.content)))
}
showCopyButton = false showCopyButton = false
}, },
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
@@ -298,7 +304,8 @@ private fun AssistantBubble(
Color(0xFFE8E6EE) Color(0xFFE8E6EE)
} }
} }
val clipboardManager = LocalClipboardManager.current val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
var showCopyButton by remember { mutableStateOf(false) } var showCopyButton by remember { mutableStateOf(false) }
// Auto-dismiss copy button after 4 seconds // Auto-dismiss copy button after 4 seconds
@@ -385,7 +392,9 @@ private fun AssistantBubble(
) { ) {
IconButton( IconButton(
onClick = { onClick = {
clipboardManager.setText(AnnotatedString(message.content)) scope.launch {
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(null, message.content)))
}
showCopyButton = false showCopyButton = false
}, },
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
@@ -706,7 +715,8 @@ private fun ToolBubble(
} }
val config = ToolSchemaRegistry.getDisplayConfig(message.toolName) val config = ToolSchemaRegistry.getDisplayConfig(message.toolName)
val clipboardManager = LocalClipboardManager.current val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
var showCopyButton by remember { mutableStateOf(false) } var showCopyButton by remember { mutableStateOf(false) }
// Auto-dismiss copy button after 4 seconds // Auto-dismiss copy button after 4 seconds
@@ -775,7 +785,6 @@ private fun ToolBubble(
CopyButton( CopyButton(
visible = showCopyButton, visible = showCopyButton,
textToCopy = message.content, textToCopy = message.content,
clipboardManager = clipboardManager,
onCopy = { showCopyButton = false }, onCopy = { showCopyButton = false },
modifier = modifier =
Modifier Modifier
@@ -806,7 +815,6 @@ private fun ToolBubble(
CopyButton( CopyButton(
visible = showCopyButton, visible = showCopyButton,
textToCopy = message.content, textToCopy = message.content,
clipboardManager = clipboardManager,
onCopy = { showCopyButton = false }, onCopy = { showCopyButton = false },
modifier = modifier =
Modifier Modifier
@@ -845,7 +853,6 @@ private fun ToolBubble(
CopyButton( CopyButton(
visible = showCopyButton, visible = showCopyButton,
textToCopy = message.content, textToCopy = message.content,
clipboardManager = clipboardManager,
onCopy = { showCopyButton = false }, onCopy = { showCopyButton = false },
modifier = modifier =
Modifier Modifier
@@ -921,10 +928,11 @@ private fun HeaderRow(
private fun CopyButton( private fun CopyButton(
visible: Boolean, visible: Boolean,
textToCopy: String, textToCopy: String,
clipboardManager: androidx.compose.ui.platform.ClipboardManager,
onCopy: () -> Unit, onCopy: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
AnimatedVisibility( AnimatedVisibility(
visible = visible, visible = visible,
enter = fadeIn() + scaleIn(), enter = fadeIn() + scaleIn(),
@@ -938,7 +946,9 @@ private fun CopyButton(
) { ) {
IconButton( IconButton(
onClick = { onClick = {
clipboardManager.setText(AnnotatedString(textToCopy)) scope.launch {
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(null, textToCopy)))
}
onCopy() onCopy()
}, },
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
@@ -964,7 +974,6 @@ private fun RichText(
searchQuery: String = "", searchQuery: String = "",
isCurrentMatch: Boolean = false, isCurrentMatch: Boolean = false,
) { ) {
val uriHandler = LocalUriHandler.current
val urlPattern = remember { Regex("""https?://[^\s)>\]\u0022\u0027]+""") } val urlPattern = remember { Regex("""https?://[^\s)>\]\u0022\u0027]+""") }
val linkColor = MaterialTheme.colorScheme.primary val linkColor = MaterialTheme.colorScheme.primary
val searchHighlightColor = if (isCurrentMatch) Color(0xFFF57C00) else Color(0xFFFFF176).copy(alpha = 0.9f) val searchHighlightColor = if (isCurrentMatch) Color(0xFFF57C00) else Color(0xFFFFF176).copy(alpha = 0.9f)
@@ -1033,7 +1042,7 @@ private fun RichText(
// URL: https://... // URL: https://...
urlPattern.matchAt(src, i) != null -> { urlPattern.matchAt(src, i) != null -> {
val match = urlPattern.matchAt(src, i)!! val match = urlPattern.matchAt(src, i)!!
pushStringAnnotation(tag = "URL", annotation = match.value) pushLink(LinkAnnotation.Url(match.value))
withStyle( withStyle(
SpanStyle( SpanStyle(
color = linkColor, color = linkColor,
@@ -1064,15 +1073,9 @@ private fun RichText(
} }
} }
ClickableText( Text(
text = annotated, text = annotated,
style = MaterialTheme.typography.bodyMedium.copy(color = textColor), style = MaterialTheme.typography.bodyMedium.copy(color = textColor),
onClick = { offset: Int ->
annotated
.getStringAnnotations("URL", offset, offset)
.firstOrNull()
?.let { uriHandler.openUri(it.item) }
},
) )
} }
@@ -17,7 +17,7 @@ import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowForward import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
@@ -253,7 +253,7 @@ fun TaskCard(
if (onMoveRight != null) { if (onMoveRight != null) {
IconButton(onClick = onMoveRight) { IconButton(onClick = onMoveRight) {
Icon( Icon(
imageVector = Icons.Filled.ArrowForward, imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = stringResource(R.string.content_desc_move_right), contentDescription = stringResource(R.string.content_desc_move_right),
) )
} }
@@ -39,7 +39,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.ScrollableTabRow import androidx.compose.material3.PrimaryScrollableTabRow
import androidx.compose.material3.SegmentedButton import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.SingleChoiceSegmentedButtonRow
@@ -101,7 +101,7 @@ fun SettingsScreen(
Modifier Modifier
.fillMaxSize(), .fillMaxSize(),
) { ) {
ScrollableTabRow( PrimaryScrollableTabRow(
selectedTabIndex = selectedTab.ordinal, selectedTabIndex = selectedTab.ordinal,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
edgePadding = 0.dp, edgePadding = 0.dp,