From 172ca7e4d2ec10d6079d3242f8ed820909e589e4 Mon Sep 17 00:00:00 2001 From: ASHMIT <52139594+ashmitvoid@users.noreply.github.com> Date: Mon, 7 Sep 2026 00:53:40 +0530 Subject: [PATCH 1/7] ux: smooth filter reveal and interaction feedback --- qml/components/FolderFilterBar.qml | 132 +++++++++++++---------------- 1 file changed, 60 insertions(+), 72 deletions(-) diff --git a/qml/components/FolderFilterBar.qml b/qml/components/FolderFilterBar.qml index 127f4b5..a1ba3c6 100644 --- a/qml/components/FolderFilterBar.qml +++ b/qml/components/FolderFilterBar.qml @@ -18,9 +18,14 @@ Item { signal focusReturnRequested() height: active ? 42 * uiScale : 0 - visible: height > 0 + visible: height > 0.5 clip: true + Behavior on height { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(140); easing.type: Easing.OutCubic } + } + function returnFocus() { Qt.callLater(function() { if (root.parent && root.parent.focusView) @@ -31,8 +36,7 @@ Item { } function open() { - if (!files) - return + if (!files) return expanded = true field.text = files.filterQuery Qt.callLater(function() { @@ -42,10 +46,8 @@ Item { } function clearAndClose() { - if (files && files.filterQuery !== "") - files.filterQuery = "" - if (session) - session.clearSelection() + if (files && files.filterQuery !== "") files.filterQuery = "" + if (session) session.clearSelection() field.text = "" field.focus = false expanded = false @@ -53,17 +55,10 @@ Item { } onDeepSearchRequested: function(query) { - if (root.remote) - return - deepPanel.open(query, query && query.trim() !== "") - } - - Shortcut { - sequence: "Ctrl+F" - enabled: root.paneActive - onActivated: root.open() + if (!root.remote) deepPanel.open(query, query && query.trim() !== "") } + Shortcut { sequence: "Ctrl+F"; enabled: root.paneActive; onActivated: root.open() } Shortcut { sequence: "Ctrl+Shift+F" enabled: root.paneActive && !root.remote @@ -79,7 +74,7 @@ Item { anchors.right: parent.right anchors.bottom: parent.bottom height: 1 - color: Ryoku.line + color: Ryoku.lineSoft } Rectangle { @@ -89,10 +84,15 @@ Item { anchors.rightMargin: 8 * root.uiScale anchors.verticalCenter: parent.verticalCenter height: 30 * root.uiScale - radius: 6 * root.uiScale - color: "transparent" - border.width: field.activeFocus ? 2 : 1 - border.color: field.activeFocus ? Ryoku.ink : Ryoku.line + radius: 7 * root.uiScale + color: field.activeFocus ? Ryoku.paperLift : Ryoku.tint5 + border.width: field.activeFocus ? 1 : 0 + border.color: Ryoku.lineStrong + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(110) } + } Text { anchors.left: parent.left @@ -100,7 +100,7 @@ Item { anchors.verticalCenter: parent.verticalCenter text: "⌕" color: Ryoku.inkMuted - font.family: Ryoku.monoFont + font.family: Ryoku.uiFont font.pixelSize: 13 * root.uiScale } @@ -122,18 +122,14 @@ Item { clip: true onTextEdited: { - if (!root.files) - return + if (!root.files) return root.files.filterQuery = text - if (root.session) - root.session.clearSelection() + if (root.session) root.session.clearSelection() } - Keys.onEscapePressed: function(event) { root.clearAndClose() event.accepted = true } - Keys.onReturnPressed: function(event) { focus = false root.returnFocus() @@ -146,9 +142,9 @@ Item { anchors.right: parent.right anchors.rightMargin: 9 * root.uiScale anchors.verticalCenter: parent.verticalCenter - text: root.files ? root.files.count + " MATCH" + (root.files.count === 1 ? "" : "ES") : "" + text: root.files ? root.files.count + " match" + (root.files.count === 1 ? "" : "es") : "" color: Ryoku.inkFaint - font.family: Ryoku.monoFont + font.family: Ryoku.uiFont font.pixelSize: 8 * root.uiScale } } @@ -156,52 +152,51 @@ Item { Rectangle { id: deepButton anchors.right: closeButton.left - anchors.rightMargin: 8 * root.uiScale + anchors.rightMargin: 7 * root.uiScale anchors.verticalCenter: parent.verticalCenter - width: 52 * root.uiScale + width: 48 * root.uiScale height: 28 * root.uiScale - radius: 6 * root.uiScale - opacity: root.remote ? 0.4 : 1.0 - color: deepHover.hovered && !root.remote ? Ryoku.tint10 : "transparent" - border.width: 1 - border.color: root.remote ? Ryoku.lineSoft : Ryoku.line + radius: 7 * root.uiScale + opacity: root.remote ? 0.38 : 1.0 + color: deepTap.pressed + ? Ryoku.tint10 + : (deepHover.hovered && !root.remote ? Ryoku.tint5 : "transparent") + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(90) } + } Text { anchors.centerIn: parent - text: "DEEP" + text: "Deep" color: Ryoku.inkDim font.family: Ryoku.uiFont - font.pixelSize: 8 * root.uiScale + font.pixelSize: 8.5 * root.uiScale font.weight: Font.Medium - font.letterSpacing: 0.8 - } - - HoverHandler { - id: deepHover - enabled: !root.remote - cursorShape: Qt.PointingHandCursor - } - TapHandler { - enabled: !root.remote - onTapped: root.deepSearchRequested(field.text) } + HoverHandler { id: deepHover; enabled: !root.remote; cursorShape: Qt.PointingHandCursor } + TapHandler { id: deepTap; enabled: !root.remote; onTapped: root.deepSearchRequested(field.text) } } - Text { + Rectangle { id: closeButton anchors.right: parent.right - anchors.rightMargin: 5 * root.uiScale + anchors.rightMargin: 4 * root.uiScale anchors.verticalCenter: parent.verticalCenter - text: "×" - color: closeHover.hovered ? Ryoku.ink : Ryoku.inkMuted - font.family: Ryoku.uiFont - font.pixelSize: 16 * root.uiScale - - HoverHandler { - id: closeHover - cursorShape: Qt.PointingHandCursor + width: 28 * root.uiScale + height: 28 * root.uiScale + radius: 7 * root.uiScale + color: closeTap.pressed ? Ryoku.tint10 : (closeHover.hovered ? Ryoku.tint5 : "transparent") + Text { + anchors.centerIn: parent + text: "×" + color: Ryoku.inkMuted + font.family: Ryoku.uiFont + font.pixelSize: 15 * root.uiScale } - TapHandler { onTapped: root.clearAndClose() } + HoverHandler { id: closeHover; cursorShape: Qt.PointingHandCursor } + TapHandler { id: closeTap; onTapped: root.clearAndClose() } } } @@ -217,24 +212,17 @@ Item { Connections { target: root.files - function onFilterQueryChanged() { - if (!root.files) - return - - if (field.text !== root.files.filterQuery) - field.text = root.files.filterQuery - - if (root.files.filterQuery === "" && !field.activeFocus) - root.expanded = false + if (!root.files) return + if (field.text !== root.files.filterQuery) field.text = root.files.filterQuery + if (root.files.filterQuery === "" && !field.activeFocus) root.expanded = false } } Connections { target: root.session function onLocationKindChanged() { - if (root.session && root.session.remote) - deepPanel.close() + if (root.session && root.session.remote) deepPanel.close() } } } From 541c2342cf7baa0dc35972ac48de3b4e3153c47b Mon Sep 17 00:00:00 2001 From: ASHMIT <52139594+ashmitvoid@users.noreply.github.com> Date: Mon, 7 Sep 2026 00:54:05 +0530 Subject: [PATCH 2/7] ux: add restrained tab pressed and focus feedback --- qml/components/TabStrip.qml | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/qml/components/TabStrip.qml b/qml/components/TabStrip.qml index d2da058..4b84e55 100644 --- a/qml/components/TabStrip.qml +++ b/qml/components/TabStrip.qml @@ -40,7 +40,6 @@ Item { delegate: Item { id: tab - required property int index required property string title required property string path @@ -59,13 +58,13 @@ Item { anchors.bottom: parent.bottom anchors.bottomMargin: 3 * root.uiScale radius: 7 * root.uiScale - color: tab.active - ? Ryoku.paperLift - : (tabHover.hovered ? Ryoku.tint5 : "transparent") + color: tabTap.pressed + ? Ryoku.tint10 + : (tab.active ? Ryoku.paperLift : (tabHover.hovered ? Ryoku.tint5 : "transparent")) Behavior on color { enabled: !Ryoku.reduceMotion - ColorAnimation { duration: Ryoku.duration(120) } + ColorAnimation { duration: Ryoku.duration(100) } } } @@ -78,7 +77,6 @@ Item { height: tab.active ? 2 * root.uiScale : 0 radius: 1 * root.uiScale color: Ryoku.sun - Behavior on height { enabled: !Ryoku.reduceMotion NumberAnimation { duration: Ryoku.duration(120); easing.type: Easing.OutCubic } @@ -111,9 +109,10 @@ Item { Rectangle { anchors.fill: parent radius: 6 * root.uiScale - color: closeHover.hovered ? Ryoku.tint10 : "transparent" + color: closeTap.pressed + ? Ryoku.tint10 + : (closeHover.hovered ? Ryoku.tint5 : "transparent") } - Text { anchors.centerIn: parent text: "×" @@ -121,9 +120,9 @@ Item { font.family: Ryoku.uiFont font.pixelSize: 14 * root.uiScale } - HoverHandler { id: closeHover; cursorShape: Qt.PointingHandCursor } TapHandler { + id: closeTap acceptedButtons: Qt.LeftButton onTapped: root.tabs.closeTab(tab.index) } @@ -131,6 +130,7 @@ Item { HoverHandler { id: tabHover; cursorShape: Qt.PointingHandCursor } TapHandler { + id: tabTap acceptedButtons: Qt.LeftButton onTapped: root.tabs.currentIndex = tab.index } @@ -146,8 +146,11 @@ Item { width: 28 * root.uiScale height: 28 * root.uiScale radius: 7 * root.uiScale - color: addHover.hovered ? Ryoku.tint10 : "transparent" - + color: addTap.pressed ? Ryoku.tint10 : (addHover.hovered ? Ryoku.tint5 : "transparent") + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(90) } + } Text { anchors.centerIn: parent text: "+" @@ -156,9 +159,9 @@ Item { font.pixelSize: 17 * root.uiScale } } - HoverHandler { id: addHover; cursorShape: Qt.PointingHandCursor } TapHandler { + id: addTap acceptedButtons: Qt.LeftButton onTapped: root.tabs.newTab("") } From 67212354dcaf4fb6cf79d699c8291d1f18b8fcfc Mon Sep 17 00:00:00 2001 From: ASHMIT <52139594+ashmitvoid@users.noreply.github.com> Date: Mon, 7 Sep 2026 00:55:48 +0530 Subject: [PATCH 3/7] ux: refine split divider and focus handoff feedback --- qml/components/SplitPaneContainer.qml | 60 +++++++++++---------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/qml/components/SplitPaneContainer.qml b/qml/components/SplitPaneContainer.qml index f8769d0..df277da 100644 --- a/qml/components/SplitPaneContainer.qml +++ b/qml/components/SplitPaneContainer.qml @@ -15,12 +15,9 @@ Item { readonly property real minimumPaneWidth: 240 * root.uiScale function focusActivePane() { - if (!root.tabs) - return - if (root.tabs.split && root.tabs.activePane === 1) - secondaryPane.focusView() - else - primaryPane.focusView() + if (!root.tabs) return + if (root.tabs.split && root.tabs.activePane === 1) secondaryPane.focusView() + else primaryPane.focusView() } function restoreFocusIfUnclaimed() { @@ -31,15 +28,13 @@ Item { } function activatePane(index) { - if (!root.tabs) - return + if (!root.tabs) return root.tabs.activePane = index Qt.callLater(root.focusActivePane) } function clampRatio(value) { - if (!root.tabs || !root.tabs.split || root.width <= 0) - return 1.0 + if (!root.tabs || !root.tabs.split || root.width <= 0) return 1.0 var available = Math.max(1, root.width - root.dividerWidth) var minimumRatio = Math.min(0.45, root.minimumPaneWidth / available) var maximumRatio = 1.0 - minimumRatio @@ -58,7 +53,6 @@ Item { uiScale: root.uiScale paneIndex: 0 paneActive: !root.tabs || root.tabs.activePane === 0 - onActivated: index => root.activatePane(index) onContextRequested: function(sceneX, sceneY, path, isDirectory, paneIndex) { root.activatePane(paneIndex) @@ -77,11 +71,20 @@ Item { Rectangle { anchors.centerIn: parent - width: 1 + width: dividerMouse.containsMouse || dividerMouse.drag.active ? 2 * root.uiScale : 1 height: parent.height + radius: width / 2 color: dividerMouse.containsMouse || dividerMouse.drag.active - ? Ryoku.lineStrong - : Ryoku.line + ? Ryoku.lineStrong : Ryoku.lineSoft + + Behavior on width { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(100); easing.type: Easing.OutCubic } + } + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(100) } + } } MouseArea { @@ -89,7 +92,6 @@ Item { anchors.fill: parent hoverEnabled: true cursorShape: Qt.SizeHorCursor - property real pressSceneX: 0 property real pressRatio: 0.5 @@ -97,10 +99,8 @@ Item { pressSceneX = mapToItem(root, mouse.x, mouse.y).x pressRatio = root.splitRatio } - onPositionChanged: function(mouse) { - if (!pressed || root.width <= root.dividerWidth) - return + if (!pressed || root.width <= root.dividerWidth) return var sceneX = mapToItem(root, mouse.x, mouse.y).x var delta = sceneX - pressSceneX var available = root.width - root.dividerWidth @@ -120,7 +120,6 @@ Item { uiScale: root.uiScale paneIndex: 1 paneActive: root.tabs && root.tabs.activePane === 1 - onActivated: index => root.activatePane(index) onContextRequested: function(sceneX, sceneY, path, isDirectory, paneIndex) { root.activatePane(paneIndex) @@ -144,32 +143,21 @@ Item { Connections { target: root.tabs function onSplitChanged() { - if (root.tabs && root.tabs.split) - root.splitRatio = root.clampRatio(root.splitRatio) - else - root.splitRatio = 0.5 - Qt.callLater(root.focusActivePane) - } - function onActivePaneChanged() { - Qt.callLater(root.focusActivePane) - } - function onCurrentSessionChanged() { + if (root.tabs && root.tabs.split) root.splitRatio = root.clampRatio(root.splitRatio) + else root.splitRatio = 0.5 Qt.callLater(root.focusActivePane) } + function onActivePaneChanged() { Qt.callLater(root.focusActivePane) } + function onCurrentSessionChanged() { Qt.callLater(root.focusActivePane) } } Connections { target: root.Window.window function onActiveFocusItemChanged() { - if (target && !target.activeFocusItem) - Qt.callLater(root.restoreFocusIfUnclaimed) + if (target && !target.activeFocusItem) Qt.callLater(root.restoreFocusIfUnclaimed) } } - onWidthChanged: { - if (root.tabs && root.tabs.split) - root.splitRatio = root.clampRatio(root.splitRatio) - } - + onWidthChanged: if (root.tabs && root.tabs.split) root.splitRatio = root.clampRatio(root.splitRatio) Component.onCompleted: Qt.callLater(root.focusActivePane) } From 1b57f9c659894f2b9e3025e95500508dcf646e4a Mon Sep 17 00:00:00 2001 From: ASHMIT <52139594+ashmitvoid@users.noreply.github.com> Date: Mon, 7 Sep 2026 01:01:49 +0530 Subject: [PATCH 4/7] UX reset 4/4: polish list interaction and preview reveal --- qml/components/FileListView.qml | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/qml/components/FileListView.qml b/qml/components/FileListView.qml index ea6abcf..df30604 100644 --- a/qml/components/FileListView.qml +++ b/qml/components/FileListView.qml @@ -137,6 +137,11 @@ Item { font.family: Ryoku.uiFont font.pixelSize: 11 * root.uiScale font.weight: Font.Medium + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(110) } + } } Rectangle { @@ -159,18 +164,26 @@ Item { height: 26 * root.uiScale visible: !root.remote && !root.previewOpen radius: 6 * root.uiScale - color: previewHover.hovered ? Ryoku.tint10 : "transparent" + color: previewTap.pressed + ? Ryoku.tint10 + : (previewHover.hovered ? Ryoku.tint5 : "transparent") + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(90) } + } Text { anchors.centerIn: parent text: "Preview" - color: previewHover.hovered ? Ryoku.ink : Ryoku.inkMuted + color: previewHover.hovered || previewTap.pressed ? Ryoku.ink : Ryoku.inkMuted font.family: Ryoku.uiFont font.pixelSize: 10 * root.uiScale } HoverHandler { id: previewHover; cursorShape: Qt.PointingHandCursor } TapHandler { + id: previewTap onTapped: { root.paneActivated() if (root.session && !root.remote) @@ -302,6 +315,12 @@ Item { width: view.width height: root.rowHeight + opacity: mouse.pressed ? 0.82 : 1.0 + + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(70) } + } Rectangle { anchors.fill: parent @@ -471,11 +490,21 @@ Item { anchors.right: parent.right anchors.bottom: parent.bottom width: root.previewOpen ? root.previewWidth : 0 - visible: root.previewOpen + visible: width > 0.5 + opacity: root.previewOpen ? 1.0 : 0.0 session: root.session desktop: Desktop thumbnails: Thumbnails uiScale: root.uiScale + + Behavior on width { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(150); easing.type: Easing.OutCubic } + } + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(110) } + } } Connections { From 522615ec5be8afaf9ae08237b460e4548c8ec717 Mon Sep 17 00:00:00 2001 From: ASHMIT <52139594+ashmitvoid@users.noreply.github.com> Date: Mon, 7 Sep 2026 01:02:32 +0530 Subject: [PATCH 5/7] UX reset 4/4: polish grid feedback and async thumbnail reveal --- qml/components/FileGridView.qml | 47 ++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/qml/components/FileGridView.qml b/qml/components/FileGridView.qml index ea3694b..6e198af 100644 --- a/qml/components/FileGridView.qml +++ b/qml/components/FileGridView.qml @@ -103,6 +103,11 @@ Item { font.family: Ryoku.uiFont font.pixelSize: 11 * root.uiScale font.weight: Font.Medium + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(110) } + } } Rectangle { @@ -125,17 +130,25 @@ Item { height: 26 * root.uiScale visible: !root.remote && !root.previewOpen radius: 6 * root.uiScale - color: previewHover.hovered ? Ryoku.tint10 : "transparent" + color: previewTap.pressed + ? Ryoku.tint10 + : (previewHover.hovered ? Ryoku.tint5 : "transparent") + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(90) } + } Text { anchors.centerIn: parent text: "Preview" - color: previewHover.hovered ? Ryoku.ink : Ryoku.inkMuted + color: previewHover.hovered || previewTap.pressed ? Ryoku.ink : Ryoku.inkMuted font.family: Ryoku.uiFont font.pixelSize: 10 * root.uiScale } HoverHandler { id: previewHover; cursorShape: Qt.PointingHandCursor } TapHandler { + id: previewTap onTapped: { root.paneActivated() if (root.session && !root.remote) @@ -200,6 +213,12 @@ Item { width: view.cellWidth height: view.cellHeight + opacity: mouse.pressed ? 0.82 : 1.0 + + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(70) } + } Rectangle { anchors.fill: parent @@ -248,6 +267,12 @@ Item { cache: true asynchronous: true smooth: true + opacity: status === Image.Ready ? 1.0 : 0.0 + + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(130); easing.type: Easing.OutCubic } + } } Item { @@ -255,6 +280,12 @@ Item { width: 64 * root.uiScale height: 54 * root.uiScale visible: !thumbnail.visible || thumbnail.status !== Image.Ready + opacity: thumbnail.status === Image.Ready ? 0.0 : 1.0 + + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(100) } + } Rectangle { anchors.left: parent.left @@ -381,11 +412,21 @@ Item { anchors.right: parent.right anchors.bottom: parent.bottom width: root.previewOpen ? root.previewWidth : 0 - visible: root.previewOpen + visible: width > 0.5 + opacity: root.previewOpen ? 1.0 : 0.0 session: root.session desktop: Desktop thumbnails: Thumbnails uiScale: root.uiScale + + Behavior on width { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(150); easing.type: Easing.OutCubic } + } + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(110) } + } } Connections { From b6eaf485d5689ad10d4d7beecaf8b7a8c0546cee Mon Sep 17 00:00:00 2001 From: ASHMIT <52139594+ashmitvoid@users.noreply.github.com> Date: Mon, 7 Sep 2026 01:03:12 +0530 Subject: [PATCH 6/7] UX reset 4/4: add progressive media and font preview feedback --- qml/components/MediaPreviewBlock.qml | 57 ++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/qml/components/MediaPreviewBlock.qml b/qml/components/MediaPreviewBlock.qml index 461abc6..6c563f3 100644 --- a/qml/components/MediaPreviewBlock.qml +++ b/qml/components/MediaPreviewBlock.qml @@ -55,6 +55,7 @@ Item { } Image { + id: posterImage anchors.fill: parent anchors.margins: 10 * root.uiScale visible: root.active @@ -66,6 +67,12 @@ Item { cache: true asynchronous: true smooth: true + opacity: status === Image.Ready ? 1.0 : 0.0 + + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(140); easing.type: Easing.OutCubic } + } } VideoOutput { @@ -81,6 +88,7 @@ Item { } Image { + id: fontSampleImage anchors.fill: parent anchors.leftMargin: 10 * root.uiScale anchors.rightMargin: 10 * root.uiScale @@ -95,6 +103,12 @@ Item { cache: true asynchronous: true smooth: true + opacity: status === Image.Ready ? 1.0 : 0.0 + + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(140); easing.type: Easing.OutCubic } + } } Item { @@ -102,6 +116,12 @@ Item { width: Math.min(parent.width - 28 * root.uiScale, 230 * root.uiScale) height: 86 * root.uiScale visible: root.active && root.loading + opacity: visible ? 1.0 : 0.0 + + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(100) } + } Column { anchors.centerIn: parent @@ -202,7 +222,15 @@ Item { width: 30 * root.uiScale height: parent.height radius: 6 * root.uiScale - color: playHover.hovered ? Ryoku.tint10 : Ryoku.tint5 + color: playTap.pressed + ? Ryoku.tint10 + : (playHover.hovered ? Ryoku.tint5 : "transparent") + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(90) } + } + Text { anchors.centerIn: parent text: mediaPlayback.playing ? "Ⅱ" : "▶" @@ -212,6 +240,7 @@ Item { } HoverHandler { id: playHover; cursorShape: Qt.PointingHandCursor } TapHandler { + id: playTap onTapped: { if (mediaPlayback.playing) mediaPlayback.pause() else mediaPlayback.play() @@ -223,8 +252,20 @@ Item { width: 30 * root.uiScale height: parent.height radius: 6 * root.uiScale - color: stopHover.hovered && mediaPlayback.prepared ? Ryoku.tint10 : Ryoku.tint5 + color: stopTap.pressed + ? Ryoku.tint10 + : (stopHover.hovered && mediaPlayback.prepared ? Ryoku.tint5 : "transparent") opacity: mediaPlayback.prepared ? 1.0 : 0.38 + + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(90) } + } + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(90) } + } + Text { anchors.centerIn: parent text: "■" @@ -232,8 +273,16 @@ Item { font.family: Ryoku.uiFont font.pixelSize: 8 * root.uiScale } - HoverHandler { id: stopHover; cursorShape: Qt.PointingHandCursor } - TapHandler { enabled: mediaPlayback.prepared; onTapped: mediaPlayback.stop() } + HoverHandler { + id: stopHover + enabled: mediaPlayback.prepared + cursorShape: Qt.PointingHandCursor + } + TapHandler { + id: stopTap + enabled: mediaPlayback.prepared + onTapped: mediaPlayback.stop() + } } Text { From 3a4af4ad2b242a703f06bfb422f44321a46c50f3 Mon Sep 17 00:00:00 2001 From: ASHMIT <52139594+ashmitvoid@users.noreply.github.com> Date: Mon, 7 Sep 2026 01:05:23 +0530 Subject: [PATCH 7/7] UX reset 4/4: animate command palette and command feedback --- qml/components/CommandPalette.qml | 46 +++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/qml/components/CommandPalette.qml b/qml/components/CommandPalette.qml index 98241d9..f7d8548 100644 --- a/qml/components/CommandPalette.qml +++ b/qml/components/CommandPalette.qml @@ -9,14 +9,25 @@ Item { property var commands: [] property string query: "" property int selectedIndex: -1 + property bool shown: false readonly property var matches: root.filteredCommands() signal commandTriggered(string commandId) visible: false + opacity: root.shown ? 1.0 : 0.0 anchors.fill: parent z: 1100 + Behavior on opacity { + enabled: !Ryoku.reduceMotion + NumberAnimation { + duration: Ryoku.duration(130) + easing.type: Easing.OutCubic + onStopped: if (!root.shown) root.visible = false + } + } + function normalized(value) { return (value || "").toString().toLowerCase() } @@ -133,6 +144,7 @@ Item { function open() { root.query = "" root.visible = true + root.shown = true field.text = "" root.selectedIndex = root.firstEnabledIndex() Qt.callLater(function() { @@ -143,13 +155,21 @@ Item { function close() { field.focus = false - root.visible = false + root.shown = false root.query = "" root.selectedIndex = -1 + if (Ryoku.reduceMotion) + root.visible = false } onMatchesChanged: root.normalizeSelection() + Rectangle { + anchors.fill: parent + color: Ryoku.paper + opacity: 0.52 + } + MouseArea { anchors.fill: parent acceptedButtons: Qt.AllButtons @@ -167,11 +187,17 @@ Item { 76 * root.uiScale + Math.max(42 * root.uiScale, root.matches.length * 42 * root.uiScale) + 34 * root.uiScale) - radius: 6 * root.uiScale + radius: 8 * root.uiScale color: Ryoku.paperLift border.width: 1 border.color: Ryoku.lineStrong clip: true + scale: root.shown ? 1.0 : 0.985 + + Behavior on scale { + enabled: !Ryoku.reduceMotion + NumberAnimation { duration: Ryoku.duration(140); easing.type: Easing.OutCubic } + } MouseArea { anchors.fill: parent @@ -296,12 +322,19 @@ Item { width: ListView.view.width height: 42 * root.uiScale - radius: 5 * root.uiScale - color: root.selectedIndex === row.index - ? (row.modelData.enabled ? Ryoku.bone : Ryoku.tint5) - : (rowHover.hovered && row.modelData.enabled ? Ryoku.tint5 : "transparent") + radius: 6 * root.uiScale + color: rowTap.pressed && row.modelData.enabled + ? (root.selectedIndex === row.index ? Ryoku.bone : Ryoku.tint10) + : (root.selectedIndex === row.index + ? (row.modelData.enabled ? Ryoku.bone : Ryoku.tint5) + : (rowHover.hovered && row.modelData.enabled ? Ryoku.tint5 : "transparent")) opacity: row.modelData.enabled ? 1.0 : 0.42 + Behavior on color { + enabled: !Ryoku.reduceMotion + ColorAnimation { duration: Ryoku.duration(90) } + } + Text { anchors.left: parent.left anchors.leftMargin: 10 * root.uiScale @@ -373,6 +406,7 @@ Item { } TapHandler { + id: rowTap enabled: row.modelData.enabled onTapped: { root.selectedIndex = row.index