diff --git a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt index ad792f1..5bd0646 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt @@ -569,48 +569,45 @@ fun ChatScreen( } } - // Scroll buttons - val showScrollUp by remember { derivedStateOf { listState.firstVisibleItemIndex > 2 } } - val showScrollDown by remember { derivedStateOf { - val info = listState.layoutInfo - info.visibleItemsInfo.lastOrNull()?.index != info.totalItemsCount - 1 - }} + if (!isStreaming) { + val atTop by remember { derivedStateOf { listState.firstVisibleItemIndex <= 1 } } + val atBottom by remember { derivedStateOf { + val info = listState.layoutInfo + info.visibleItemsInfo.lastOrNull()?.index == info.totalItemsCount - 1 + }} + val canScrollUp by remember { derivedStateOf { listState.canScrollBackward } } + val canScrollDown by remember { derivedStateOf { listState.canScrollForward } } - if (showScrollUp || showScrollDown) { - Column( - modifier = Modifier - .align(Alignment.CenterEnd) - .padding(end = 8.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - if (showScrollUp) { - GlassSurface( - shape = KaizenShapes.circle, - tintAlpha = GlassTiers.pill(isSystemInDarkTheme()), - shadowStack = KaizenShadows.level1, - cornerRadius = 18.dp, - modifier = Modifier - .size(36.dp) - .clickable { scope.launch { listState.animateScrollToItem(0) } }, - ) { - Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Icon(Icons.Rounded.KeyboardArrowUp, null, tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.size(20.dp)) - } + if (!atTop && canScrollUp) { + GlassSurface( + shape = KaizenShapes.circle, + tintAlpha = GlassTiers.pill(isSystemInDarkTheme()), + shadowStack = KaizenShadows.level1, + cornerRadius = 18.dp, + modifier = Modifier + .align(Alignment.CenterEnd) + .padding(end = 8.dp, bottom = 24.dp) + .size(36.dp) + .clickable { scope.launch { listState.animateScrollToItem(0) } }, + ) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon(Icons.Rounded.KeyboardArrowUp, null, tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.size(20.dp)) } } - if (showScrollDown) { - GlassSurface( - shape = KaizenShapes.circle, - tintAlpha = GlassTiers.pill(isSystemInDarkTheme()), - shadowStack = KaizenShadows.level1, - cornerRadius = 18.dp, - modifier = Modifier - .size(36.dp) - .clickable { scope.launch { listState.animateScrollToItem(messages.size - 1) } }, - ) { - Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Icon(Icons.Rounded.KeyboardArrowDown, null, tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.size(20.dp)) - } + } else if (!atBottom && canScrollDown) { + GlassSurface( + shape = KaizenShapes.circle, + tintAlpha = GlassTiers.pill(isSystemInDarkTheme()), + shadowStack = KaizenShadows.level1, + cornerRadius = 18.dp, + modifier = Modifier + .align(Alignment.CenterEnd) + .padding(end = 8.dp, top = 24.dp) + .size(36.dp) + .clickable { scope.launch { listState.animateScrollToItem(messages.size - 1) } }, + ) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon(Icons.Rounded.KeyboardArrowDown, null, tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.size(20.dp)) } } } diff --git a/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt b/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt index 32fd04c..3cca414 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt @@ -34,8 +34,7 @@ import androidx.compose.material.icons.rounded.Search import androidx.compose.material.icons.rounded.Settings import androidx.compose.material.icons.rounded.Star import androidx.compose.material3.AlertDialog -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -423,48 +422,38 @@ private fun HistoryItemRow( } } - DropdownMenu( + androidx.compose.material3.DropdownMenu( expanded = showMenu, onDismissRequest = { showMenu = false }, + containerColor = if (isDark) Color(0xFF1A2030) else Color(0xFFF8F9FB), + shadowElevation = 12.dp, + shape = KaizenShapes.md, ) { if (!item.locked) { - DropdownMenuItem( - text = { Text(stringResource(R.string.sidebar_rename), fontSize = 14.sp) }, - onClick = { showMenu = false; onRename() }, - leadingIcon = { Icon(Icons.Rounded.Edit, null, modifier = Modifier.size(18.dp)) }, - ) + MenuRow(Icons.Rounded.Edit, stringResource(R.string.sidebar_rename), cs.onBackground) { showMenu = false; onRename() } } - DropdownMenuItem( - text = { - Text( - stringResource(if (item.pinned) R.string.sidebar_unpin else R.string.sidebar_pin), - fontSize = 14.sp, - ) - }, - onClick = { showMenu = false; onTogglePin() }, - leadingIcon = { Icon(Icons.Rounded.PushPin, null, modifier = Modifier.size(18.dp)) }, - ) - DropdownMenuItem( - text = { - Text( - stringResource(if (item.locked) R.string.sidebar_unlock else R.string.sidebar_lock), - fontSize = 14.sp, - ) - }, - onClick = { showMenu = false; onToggleLock() }, - leadingIcon = { - Icon( - if (item.locked) Icons.Rounded.LockOpen else Icons.Rounded.Lock, - null, - modifier = Modifier.size(18.dp), - ) - }, - ) - DropdownMenuItem( - text = { Text(stringResource(R.string.sidebar_delete), fontSize = 14.sp, color = Color(0xFFEF4444)) }, - onClick = { showMenu = false; onDelete() }, - leadingIcon = { Icon(Icons.Rounded.Delete, null, tint = Color(0xFFEF4444), modifier = Modifier.size(18.dp)) }, - ) + MenuRow(Icons.Rounded.PushPin, stringResource(if (item.pinned) R.string.sidebar_unpin else R.string.sidebar_pin), cs.onBackground) { showMenu = false; onTogglePin() } + MenuRow( + if (item.locked) Icons.Rounded.LockOpen else Icons.Rounded.Lock, + stringResource(if (item.locked) R.string.sidebar_unlock else R.string.sidebar_lock), + cs.onBackground, + ) { showMenu = false; onToggleLock() } + MenuRow(Icons.Rounded.Delete, stringResource(R.string.sidebar_delete), Color(0xFFEF4444)) { showMenu = false; onDelete() } } } } + +@Composable +private fun MenuRow(icon: ImageVector, label: String, tint: Color, onClick: () -> Unit) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon(icon, null, tint = tint.copy(alpha = 0.7f), modifier = Modifier.size(18.dp)) + Spacer(Modifier.width(12.dp)) + Text(label, color = tint, fontSize = 14.sp, fontWeight = FontWeight.Medium) + } +}