Fade title-bar buttons in on hover, remove temp debug logger, bump to 0.1.6
- Nicklist, settings, minimize and close buttons in the channel window title bar now rest at alpha 0 and fade to full opacity on hover (graphicsLayer alpha, so they stay laid out and clickable). Resting alpha, hover alpha and fade duration are constants at the top of ChannelScreen.kt. Channel name and window dragging are unchanged. - Remove the unused temporary ircUiDebug helper now that the scrollback fix is confirmed. - Bump version to 0.1.6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
21b52477aa
commit
242d7a7c42
+2
-2
@@ -6,7 +6,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "com.tpuahsiew.wirc"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
|
||||
// No project-level repositories{} block here: settings.gradle.kts sets
|
||||
// dependencyResolutionManagement.repositoriesMode = FAIL_ON_PROJECT_REPOS and already
|
||||
@@ -38,7 +38,7 @@ compose.desktop {
|
||||
appResourcesRootDir.set(project.file("installerResources"))
|
||||
targetFormats(TargetFormat.Msi, TargetFormat.Exe)
|
||||
packageName = "wIRC"
|
||||
packageVersion = "0.1.5"
|
||||
packageVersion = "0.1.6"
|
||||
windows {
|
||||
menuGroup = "wIRC"
|
||||
upgradeUuid = "8f14e45f-ceea-4a5e-9c3b-5b1f0e8c2b7a"
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package ui
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.hoverable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||
import androidx.compose.foundation.window.WindowDraggableArea
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -27,6 +31,7 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -68,11 +73,12 @@ import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.math.floor
|
||||
|
||||
// TEMP DEBUG (see task: auto-scroll from-scratch audit) - remove once confirmed fixed.
|
||||
// label identifies which window's log line this is, so multi-window repros are legible.
|
||||
private fun ircUiDebug(label: String, msg: String) {
|
||||
println("[ui-debug][$label] $msg")
|
||||
}
|
||||
// Title-bar button fade (nicklist / settings / minimize / close). The buttons sit at
|
||||
// TITLE_BAR_BUTTON_REST_ALPHA until hovered, then animate to TITLE_BAR_BUTTON_HOVER_ALPHA
|
||||
// over TITLE_BAR_BUTTON_FADE_MS. The channel name text is not affected.
|
||||
private const val TITLE_BAR_BUTTON_REST_ALPHA = 0f
|
||||
private const val TITLE_BAR_BUTTON_HOVER_ALPHA = 1f
|
||||
private const val TITLE_BAR_BUTTON_FADE_MS = 150
|
||||
|
||||
// Single-space separator between the padded nick column and the message body. Previously
|
||||
// a 2-space trailing gap on CHAT lines (on top of the padEnd() column padding itself),
|
||||
@@ -406,6 +412,8 @@ fun WindowScope.ChannelScreen(
|
||||
// because manually accumulating dragAmount into windowState.position fights
|
||||
// with the OS's own window-move handling; WindowDraggableArea talks to that
|
||||
// directly instead of reimplementing it.
|
||||
// The four buttons on the right fade in on hover (see FadingTitleBarButton); the
|
||||
// channel name stays fully opaque.
|
||||
WindowDraggableArea(modifier = Modifier.fillMaxWidth()) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -416,20 +424,20 @@ fun WindowScope.ChannelScreen(
|
||||
) {
|
||||
Text(channelName, color = textColor, fontFamily = FontFamily.Monospace, style = MaterialTheme.typography.labelSmall)
|
||||
Row {
|
||||
IconButton(onClick = { onShowUserListChange(!displaySettings.showUserList) }, modifier = Modifier.size(28.dp)) {
|
||||
FadingTitleBarButton(onClick = { onShowUserListChange(!displaySettings.showUserList) }) {
|
||||
Icon(Icons.Default.Person, contentDescription = "Toggle user list", tint = textColor, modifier = Modifier.size(16.dp))
|
||||
}
|
||||
IconButton(onClick = { showSettings = !showSettings }, modifier = Modifier.size(28.dp)) {
|
||||
FadingTitleBarButton(onClick = { showSettings = !showSettings }) {
|
||||
Icon(Icons.Default.Settings, contentDescription = "Window settings", tint = textColor, modifier = Modifier.size(16.dp))
|
||||
}
|
||||
IconButton(onClick = { windowState.isMinimized = true }, modifier = Modifier.size(28.dp)) {
|
||||
FadingTitleBarButton(onClick = { windowState.isMinimized = true }) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(width = 10.dp, height = 2.dp)
|
||||
.background(textColor)
|
||||
)
|
||||
}
|
||||
IconButton(onClick = onCloseWindow, modifier = Modifier.size(28.dp)) {
|
||||
FadingTitleBarButton(onClick = onCloseWindow) {
|
||||
Icon(Icons.Default.Close, contentDescription = "Close window", tint = textColor, modifier = Modifier.size(16.dp))
|
||||
}
|
||||
}
|
||||
@@ -796,6 +804,31 @@ fun WindowScope.ChannelScreen(
|
||||
}
|
||||
}
|
||||
|
||||
// A 28dp title-bar IconButton that rests invisible and fades in while hovered. The fade
|
||||
// is a graphicsLayer alpha only - the button is always laid out, drawn and hit-tested, so
|
||||
// it still gets hover and clicks at alpha 0. The alpha is read inside the graphicsLayer
|
||||
// lambda so the animation only re-draws the layer instead of recomposing every frame.
|
||||
// IconButton's own hover/press state layer is drawn inside this layer, so it still shows
|
||||
// once the button has faded in.
|
||||
@Composable
|
||||
private fun FadingTitleBarButton(onClick: () -> Unit, content: @Composable () -> Unit) {
|
||||
val hoverSource = remember { MutableInteractionSource() }
|
||||
val hovered by hoverSource.collectIsHoveredAsState()
|
||||
val alpha by animateFloatAsState(
|
||||
targetValue = if (hovered) TITLE_BAR_BUTTON_HOVER_ALPHA else TITLE_BAR_BUTTON_REST_ALPHA,
|
||||
animationSpec = tween(durationMillis = TITLE_BAR_BUTTON_FADE_MS)
|
||||
)
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier
|
||||
.size(28.dp)
|
||||
.hoverable(hoverSource)
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
// In-memory LRU cache of decoded image bitmaps, keyed by URL, so scrolling a channel
|
||||
// with image previews on doesn't re-fetch/re-decode images that already loaded.
|
||||
private object ImageCache {
|
||||
|
||||
Reference in New Issue
Block a user