From 80ea75ff787ac7e7339cbcff05d403c9fd3b8099 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Fri, 23 Oct 2026 14:19:18 +0800 Subject: [PATCH] [ui] highlight disconnect buttons and confirm session closure --- apps/desktop/src/gui/ui/main_window.slint | 109 +++++++++++++++++- .../src/gui/ui/workbench_controls.slint | 13 ++- 2 files changed, 117 insertions(+), 5 deletions(-) diff --git a/apps/desktop/src/gui/ui/main_window.slint b/apps/desktop/src/gui/ui/main_window.slint index ebc86b74..510c32a7 100644 --- a/apps/desktop/src/gui/ui/main_window.slint +++ b/apps/desktop/src/gui/ui/main_window.slint @@ -554,6 +554,7 @@ export component MainWindow inherits Window { && !(root.update-open && root.update-available) && !root.messages-open && !root.update-confirm-open && !root.reset-password-open && !root.alias-open && !root.delete-open + && !root.disconnect-open && !root.device-group-open && !root.connection-dialog-open && !root.permission-dialog-open && !root.wayland-notice-open && !root.portable-service-dialog-open @@ -577,6 +578,15 @@ export component MainWindow inherits Window { in-out property delete-open: false; private property delete-remote-id: ""; private property delete-from-gallery: false; + in-out property disconnect-open: false; + private property disconnect-remote-id: ""; + private property disconnect-device-name: ""; + function dismiss-disconnect() { + root.disconnect-open = false; + root.disconnect-remote-id = ""; + root.disconnect-device-name = ""; + focus-sink.focus(); + } private property copy-feedback: idle; private property compact-language: root.language-index == 0; private property recent-tooltip-visible: false; @@ -1383,13 +1393,18 @@ export component MainWindow inherits Window { width: 28px; height: 28px; soft: true; primary: !connection.connected; + destructive: connection.connected; icon: connection.connected ? FontAwesomeIcons.xmark : FontAwesomeIcons.arrow-right-long; tooltip: connection.connected ? GalleryStrings.tr("断开连接", "Disconnect", "Отключить") : UiStrings.connect; tooltip-above: true; clicked => { root.copy-feedback = CopyFeedback.idle; root.recent-tooltip-visible = false; - if connection.connected { root.recent-disconnect(connection.remote-id); } + if connection.connected { + root.disconnect-remote-id = connection.remote-id; + root.disconnect-device-name = connection.display-name; + root.disconnect-open = true; + } else { root.recent-connect(connection.remote-id); } } } @@ -1924,6 +1939,98 @@ export component MainWindow inherits Window { } } + // Confirm the selected recent session before disconnecting it. + if root.disconnect-open: Rectangle { + background: #14233b66; + z: 48; + TouchArea { scroll-event(event) => { accept } } + FocusScope { + width: parent.width; + height: parent.height; + key-pressed(event) => { + if event.text == Key.Escape { + root.dismiss-disconnect(); + return accept; + } + if event.text == Key.Tab { + if disconnect-cancel.has-focus { + disconnect-confirm.focus(); + } else { + disconnect-cancel.focus(); + } + return accept; + } + return reject; + } + Timer { + interval: 1ms; + running: true; + triggered => { + self.running = false; + // Defer focus until after Slint's accessibility update. + disconnect-cancel.focus(); + } + } + DialogSurface { + x: (parent.width - self.width) / 2; + y: (parent.height - self.height) / 2; + width: min(420px, parent.width - 40px); + height: disconnect-content.preferred-height; + border-color: WorkbenchStyle.border; + TouchArea { scroll-event(event) => { accept } } + disconnect-content := VerticalLayout { + padding: 24px; + spacing: 16px; + Text { + text: GalleryStrings.tr("确认断开连接?", "Disconnect this session?", "Отключить этот сеанс?"); + color: WorkbenchStyle.text; + font-size: 18px; + font-weight: 600; + wrap: word-wrap; + } + VerticalLayout { + spacing: 6px; + Text { + text: root.disconnect-device-name; + color: WorkbenchStyle.text; + font-size: 14px; + font-weight: 600; + overflow: elide; + } + Text { + text: root.disconnect-remote-id; + color: WorkbenchStyle.muted; + font-size: 12px; + } + } + Text { + text: GalleryStrings.tr("当前远程控制会话将结束。", "The current remote session will end.", "Текущий сеанс удалённого управления завершится."); + color: WorkbenchStyle.muted; + font-size: 13px; + wrap: word-wrap; + } + HorizontalLayout { + alignment: end; + spacing: 8px; + disconnect-cancel := WorkbenchButton { + text: UiStrings.cancel; + clicked => { root.dismiss-disconnect(); } + } + disconnect-confirm := WorkbenchButton { + text: GalleryStrings.tr("断开连接", "Disconnect", "Отключить"); + destructive: true; + clicked => { + let remote-id = root.disconnect-remote-id; + root.dismiss-disconnect(); + root.recent-disconnect(remote-id); + } + } + } + } + } + } + } + // Offline/error warning modal. if root.offline-warning != "": Rectangle { background: #00000042; diff --git a/apps/desktop/src/gui/ui/workbench_controls.slint b/apps/desktop/src/gui/ui/workbench_controls.slint index 4f494603..2d4aa93c 100644 --- a/apps/desktop/src/gui/ui/workbench_controls.slint +++ b/apps/desktop/src/gui/ui/workbench_controls.slint @@ -19,16 +19,17 @@ export global WorkbenchStyle { export component WorkbenchButton inherits Rectangle { in property text; in property text-size: 13px; - in property text-color: root.primary ? white : WorkbenchStyle.text; + in property text-color: root.destructive || root.primary ? white : WorkbenchStyle.text; in property normal-border-color: WorkbenchStyle.control-border; in property icon; in property tooltip; in property tooltip-above: false; in property tooltip-suppressed: false; - in property icon-color: root.primary + in property icon-color: root.destructive ? white : root.primary ? (root.soft && !touch.has-hover && !root.show-focus ? WorkbenchStyle.accent : white) : WorkbenchStyle.muted; in property primary: false; + in property destructive: false; in property soft: false; in property quiet: false; in property enabled: true; @@ -45,11 +46,15 @@ export component WorkbenchButton inherits Rectangle { height: 36px; border-radius: UiRadius.control; border-width: root.show-focus ? 2px : root.soft ? 0px : 1px; - border-color: root.show-focus ? (root.primary ? #193da0 : WorkbenchStyle.accent) + border-color: root.destructive + ? (root.show-focus ? #7a271a : touch.pressed ? #912018 : touch.has-hover ? #b42318 : #d92d20) + : root.show-focus ? (root.primary ? #193da0 : WorkbenchStyle.accent) : root.primary ? WorkbenchStyle.accent : touch.has-hover ? WorkbenchStyle.hover-border : root.quiet ? transparent : root.normal-border-color; - background: root.soft + background: root.destructive + ? (touch.pressed ? #912018 : touch.has-hover ? #b42318 : #d92d20) + : root.soft ? (root.primary ? (touch.pressed ? #254cc0 : touch.has-hover || root.show-focus ? WorkbenchStyle.accent : #edf2ff) : (touch.pressed ? WorkbenchStyle.pressed-surface : touch.has-hover ? WorkbenchStyle.hover-surface : WorkbenchStyle.field-surface))