fix(#130): fix compilation errors in scroll-to-bottom FAB (#166)

* fix(#130): fix compilation errors in scroll-to-bottom FAB

* fix(#130): add missing R import, context, and string resources

* fix(#130): use stringResource() instead of context.getString() for Compose lint

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-06-20 16:45:05 +03:00
1 parent 03cfcf8504
commit ff4649b601
2 files changed
+33 -13

No files matched your search

@@ -80,6 +80,7 @@ import androidx.compose.runtime.derivedStateOf
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.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -90,6 +91,7 @@ import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@@ -98,11 +100,13 @@ import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.m57.hermescontrol.R
import com.m57.hermescontrol.data.ws.ConnectionStatus import com.m57.hermescontrol.data.ws.ConnectionStatus
import com.m57.hermescontrol.notification.NotificationHelper import com.m57.hermescontrol.notification.NotificationHelper
import com.m57.hermescontrol.theme.StatusRed import com.m57.hermescontrol.theme.StatusRed
import com.m57.hermescontrol.ui.common.EmptyState import com.m57.hermescontrol.ui.common.EmptyState
import com.m57.hermescontrol.ui.common.HermesScaffold import com.m57.hermescontrol.ui.common.HermesScaffold
import kotlinx.coroutines.launch
@Composable @Composable
fun ChatScreen( fun ChatScreen(
@@ -118,6 +122,7 @@ fun ChatScreen(
state.messages.isNotEmpty() && listState.canScrollForward state.messages.isNotEmpty() && listState.canScrollForward
} }
} }
val scrollScope = rememberCoroutineScope()
var inputText by rememberSaveable { mutableStateOf("") } var inputText by rememberSaveable { mutableStateOf("") }
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
@@ -533,7 +538,7 @@ fun ChatScreen(
} }
// Scroll-to-bottom FAB // Scroll-to-bottom FAB
AnimatedVisibility( androidx.compose.animation.AnimatedVisibility(
visible = showScrollToBottom, visible = showScrollToBottom,
enter = fadeIn() + scaleIn(), enter = fadeIn() + scaleIn(),
exit = fadeOut() + scaleOut(), exit = fadeOut() + scaleOut(),
@@ -544,7 +549,9 @@ fun ChatScreen(
) { ) {
FloatingActionButton( FloatingActionButton(
onClick = { onClick = {
listState.animateScrollToItem(state.messages.lastIndex) scrollScope.launch {
listState.animateScrollToItem(state.messages.lastIndex)
}
}, },
modifier = Modifier.size(40.dp), modifier = Modifier.size(40.dp),
containerColor = MaterialTheme.colorScheme.surfaceContainer, containerColor = MaterialTheme.colorScheme.surfaceContainer,
@@ -808,7 +815,7 @@ private fun ChatInputBar(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.Send, imageVector = Icons.AutoMirrored.Filled.Send,
contentDescription = "Send", contentDescription = stringResource(R.string.chat_send_desc),
) )
} }
} }
@@ -828,7 +835,7 @@ private fun ClarifyDialog(
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text("Clarification Needed") }, title = { Text(stringResource(R.string.chat_clarify_title)) },
text = { text = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text(text = clarify.text) Text(text = clarify.text)
@@ -836,7 +843,7 @@ private fun ClarifyDialog(
if (clarify.options.isNotEmpty()) { if (clarify.options.isNotEmpty()) {
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text( Text(
text = "Tap an option to copy to input, or long-press to send directly.", text = stringResource(R.string.chat_clarify_hint),
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
) )
@@ -863,7 +870,7 @@ private fun ClarifyDialog(
OutlinedTextField( OutlinedTextField(
value = typedText, value = typedText,
onValueChange = { typedText = it }, onValueChange = { typedText = it },
label = { Text("Response") }, label = { Text(stringResource(R.string.chat_clarify_response)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
singleLine = true, singleLine = true,
) )
@@ -878,12 +885,12 @@ private fun ClarifyDialog(
}, },
enabled = typedText.isNotBlank(), enabled = typedText.isNotBlank(),
) { ) {
Text("Send") Text(stringResource(R.string.chat_send))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismiss) { TextButton(onClick = onDismiss) {
Text("Dismiss") Text(stringResource(R.string.chat_dismiss))
} }
}, },
) )
@@ -931,7 +938,7 @@ private fun CompactSearchInput(
Box(modifier = Modifier.weight(1f)) { Box(modifier = Modifier.weight(1f)) {
if (value.isEmpty()) { if (value.isEmpty()) {
Text( Text(
text = "Search messages…", text = stringResource(R.string.chat_search_placeholder),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f), color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
) )
@@ -945,7 +952,7 @@ private fun CompactSearchInput(
) { ) {
Icon( Icon(
imageVector = Icons.Filled.Close, imageVector = Icons.Filled.Close,
contentDescription = "Clear", contentDescription = stringResource(R.string.chat_clear_search_desc),
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
) )
} }
@@ -1008,7 +1015,7 @@ private fun SearchBarRow(
) { ) {
Icon( Icon(
Icons.Filled.KeyboardArrowUp, Icons.Filled.KeyboardArrowUp,
contentDescription = "Previous match", contentDescription = stringResource(R.string.chat_prev_match_desc),
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
) )
} }
@@ -1019,14 +1026,14 @@ private fun SearchBarRow(
) { ) {
Icon( Icon(
Icons.Filled.KeyboardArrowDown, Icons.Filled.KeyboardArrowDown,
contentDescription = "Next match", contentDescription = stringResource(R.string.chat_next_match_desc),
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
) )
} }
IconButton(onClick = onClose, modifier = Modifier.size(36.dp)) { IconButton(onClick = onClose, modifier = Modifier.size(36.dp)) {
Icon( Icon(
Icons.Filled.Close, Icons.Filled.Close,
contentDescription = "Close search", contentDescription = stringResource(R.string.chat_close_search_desc),
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
) )
} }
+13
View File
@@ -1,3 +1,16 @@
<resources> <resources>
<string name="app_name">HermesControl</string> <string name="app_name">HermesControl</string>
<!-- Chat -->
<string name="chat_send_desc">Send</string>
<string name="chat_clarify_title">Clarification Needed</string>
<string name="chat_clarify_hint">Tap an option to copy to input, or long-press to send directly.</string>
<string name="chat_clarify_response">Response</string>
<string name="chat_send">Send</string>
<string name="chat_dismiss">Dismiss</string>
<string name="chat_search_placeholder">Search messages\u2026</string>
<string name="chat_clear_search_desc">Clear</string>
<string name="chat_prev_match_desc">Previous match</string>
<string name="chat_next_match_desc">Next match</string>
<string name="chat_close_search_desc">Close search</string>
</resources> </resources>