mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-07-24 08:08:41 +08:00
1729 lines
81 KiB
Plaintext
1729 lines
81 KiB
Plaintext
import { LineEdit, ScrollView } from "std-widgets.slint";
|
|
import { FontAwesomeIcons, IconButton, CompactComboBox, ImGuiCheckBox, MiniToggleSwitch, CompactButton, PrimaryButton, SecondaryButton, ToggleSwitch, SectionTitle, DialogSurface, ImGuiLineStyle, ImGuiFontStyle } from "common.slint";
|
|
|
|
export struct RecentConnection {
|
|
remote-id: string,
|
|
display-name: string,
|
|
host-name: string,
|
|
online: bool,
|
|
thumbnail: image,
|
|
}
|
|
|
|
export struct ReleaseNoteBlock {
|
|
content: styled-text,
|
|
section-gap: bool,
|
|
}
|
|
|
|
export global UiStrings {
|
|
in-out property <string> local-desktop: "Local Desktop";
|
|
in-out property <string> remote-desktop: "Remote Desktop";
|
|
in-out property <string> recent-connections: "Recent Connections";
|
|
in-out property <string> local-id: "Local ID";
|
|
in-out property <string> device-name: "Device Name";
|
|
in-out property <string> remote-id: "Remote ID";
|
|
in-out property <string> online: "Online";
|
|
in-out property <string> offline: "Offline";
|
|
in-out property <string> password: "Password";
|
|
in-out property <string> copied: "Local ID copied to clipboard";
|
|
in-out property <string> connect: "Connect";
|
|
in-out property <string> settings: "Settings";
|
|
in-out property <string> about: "About";
|
|
in-out property <string> ok: "OK";
|
|
in-out property <string> cancel: "Cancel";
|
|
in-out property <string> save: "Save";
|
|
in-out property <string> new-password: "New password (6 characters)";
|
|
in-out property <string> invalid-password: "Password must contain exactly 6 characters";
|
|
in-out property <string> edit-alias: "Connection alias";
|
|
in-out property <string> delete-connection: "Delete connection";
|
|
in-out property <string> confirm-delete: "Delete this recent connection?";
|
|
in-out property <string> language: "Language";
|
|
in-out property <string> video-quality: "Video quality";
|
|
in-out property <string> frame-rate: "Frame rate";
|
|
in-out property <string> codec: "Video codec";
|
|
in-out property <string> hardware-codec: "Hardware video codec";
|
|
in-out property <string> turn-relay: "TURN relay";
|
|
in-out property <string> srtp: "SRTP encryption";
|
|
in-out property <string> self-hosted: "Self-hosted server";
|
|
in-out property <string> autostart: "Start with system";
|
|
in-out property <string> daemon: "Run in background";
|
|
in-out property <string> minimize-to-tray: "Minimize to tray";
|
|
in-out property <string> file-save-path: "File save path";
|
|
in-out property <string> default-desktop: "Desktop";
|
|
in-out property <string> server-host: "Server host";
|
|
in-out property <string> server-port: "Signal port";
|
|
in-out property <string> coturn-port: "TURN port";
|
|
in-out property <string> version: "Version";
|
|
in-out property <string> copyright: "© 2026 by JUNKUN DI. All right reserved.";
|
|
in-out property <string> license: "Licensed under GNU GPL v3.";
|
|
in-out property <string> signal-connected: "Signal server connected";
|
|
in-out property <string> signal-disconnected: "Signal server disconnected";
|
|
in-out property <string> tls-error: "Signal server TLS certificate error";
|
|
in-out property <string> update-available: "A new version is available";
|
|
in-out property <string> release-notes: "Release notes";
|
|
in-out property <string> later: "Later";
|
|
in-out property <string> download: "Download";
|
|
in-out property <string> input-password: "Input password";
|
|
in-out property <string> reinput-password: "Incorrect password, please try again";
|
|
in-out property <string> remember-password: "Remember password";
|
|
in-out property <string> validate-password: "Validating password";
|
|
in-out property <string> request-permissions: "Request permissions";
|
|
in-out property <string> permission-required: "The application requires the following permissions:";
|
|
in-out property <string> screen-recording-permission: "Screen recording permission";
|
|
in-out property <string> accessibility-permission: "Accessibility permission";
|
|
in-out property <string> service-setup-title: "Install CrossDesk Service";
|
|
in-out property <string> service-setup-message: "Administrator permission is required to control this device while it is locked.";
|
|
in-out property <string> service-settings-label: "Lock Screen Service:";
|
|
in-out property <string> install-service: "Install";
|
|
in-out property <string> service-installed: "Installed";
|
|
in-out property <string> do-not-remind: "Do not remind again";
|
|
in-out property <string> notification: "Notification";
|
|
in-out property <string> service-suppressed-message: "You will not be reminded again. You can install the service later in Settings.";
|
|
in-out property <string> quality-low: "Low";
|
|
in-out property <string> quality-medium: "Medium";
|
|
in-out property <string> quality-high: "High";
|
|
in-out property <string> codec-h264: "H.264";
|
|
in-out property <string> codec-av1: "AV1";
|
|
in-out property <string> self-hosted-settings: "Self-hosted server settings";
|
|
in-out property <string> access-website: "Website: ";
|
|
in-out property <string> release-date-label: "Release Date: ";
|
|
}
|
|
|
|
// Fluent LineEdit draws a blue 2px focus underline. The ImGui-style field
|
|
// already has its own border, so cover that underline and restore its bottom
|
|
// edge without changing the editor's focus, selection, or clear-button logic.
|
|
component LineEditFocusUnderlineMask inherits Rectangle {
|
|
height: 3px;
|
|
background: white;
|
|
z: 2;
|
|
|
|
Rectangle {
|
|
y: parent.height - 1px;
|
|
height: 1px;
|
|
background: ImGuiLineStyle.border;
|
|
}
|
|
}
|
|
|
|
// Prompt copy in modal dialogs sits slightly low in the legacy ImGui layout.
|
|
// Offset only the rendered text so input fields and action buttons keep their
|
|
// established geometry.
|
|
component DialogPromptText inherits Rectangle {
|
|
in property <string> prompt;
|
|
in property <color> text-color: #30343b;
|
|
in property <length> text-size: ImGuiFontStyle.base;
|
|
in property <int> text-weight: 400;
|
|
|
|
// Mirror Text's intrinsic layout constraints exactly. This makes the
|
|
// wrapper invisible to VerticalLayout: siblings retain the same geometry
|
|
// they had when the Text item was a direct child.
|
|
min-height: prompt-label.min-height;
|
|
preferred-height: prompt-label.preferred-height;
|
|
max-height: prompt-label.max-height;
|
|
vertical-stretch: prompt-label.vertical-stretch;
|
|
|
|
prompt-label := Text {
|
|
y: 10px;
|
|
width: parent.width;
|
|
text: root.prompt;
|
|
color: root.text-color;
|
|
font-size: root.text-size;
|
|
font-weight: root.text-weight;
|
|
wrap: word-wrap;
|
|
horizontal-alignment: center;
|
|
}
|
|
}
|
|
|
|
// Shared online-state artwork. Both the recent-connection card and the
|
|
// server status bar use the same pure green center and proportional glow.
|
|
component OnlineStatusIndicator inherits Rectangle {
|
|
in property <length> dot-diameter: 8px;
|
|
|
|
width: root.dot-diameter * 2.2;
|
|
height: self.width;
|
|
border-radius: self.width / 2;
|
|
background: @radial-gradient(
|
|
circle,
|
|
#00ff0030 0%,
|
|
#00ff0018 48%,
|
|
transparent 100%
|
|
);
|
|
|
|
Rectangle {
|
|
x: (parent.width - root.dot-diameter) / 2;
|
|
y: (parent.height - root.dot-diameter) / 2;
|
|
width: root.dot-diameter;
|
|
height: root.dot-diameter;
|
|
border-radius: root.dot-diameter / 2;
|
|
background: #00ff00;
|
|
}
|
|
}
|
|
|
|
// ImGui::Button under StyleColorsLight(), used by both actions in the legacy
|
|
// connection-password dialog. The old dialog does not distinguish primary and
|
|
// secondary actions visually.
|
|
component ConnectionDialogButton inherits Rectangle {
|
|
in property <string> text;
|
|
callback clicked;
|
|
|
|
width: max(40px, button-label.preferred-width + 8px);
|
|
height: 24px;
|
|
background: button-touch.pressed ? #0f87fa
|
|
: button-touch.has-hover ? #4296fa
|
|
: #4296fa66;
|
|
border-radius: 3px;
|
|
|
|
button-label := Text {
|
|
text: root.text;
|
|
color: #000000de;
|
|
font-size: ImGuiFontStyle.base;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
button-touch := TouchArea { clicked => { root.clicked(); } }
|
|
}
|
|
|
|
export component MainWindow inherits Window {
|
|
title: "CrossDesk";
|
|
preferred-width: 640px;
|
|
preferred-height: 450px + root.titlebar-height;
|
|
min-width: 640px;
|
|
max-width: 640px;
|
|
min-height: 450px + root.titlebar-height;
|
|
max-height: 450px + root.titlebar-height;
|
|
no-frame: root.custom-titlebar;
|
|
background: root.wayland-titlebar ? transparent : white;
|
|
default-font-size: ImGuiFontStyle.base;
|
|
|
|
in property <bool> custom-titlebar: false;
|
|
in property <bool> wayland-titlebar: false;
|
|
in property <bool> window-active: true;
|
|
private property <length> titlebar-height:
|
|
root.custom-titlebar ? (root.wayland-titlebar ? 32px : 31px) : 0px;
|
|
private property <length> wayland-corner-radius: 12px;
|
|
in property <string> local-id: "";
|
|
in property <string> local-password: "";
|
|
in-out property <string> remote-id-input: "";
|
|
in property <bool> password-visible: true;
|
|
in property <bool> signal-connected: false;
|
|
in property <bool> signal-tls-error: false;
|
|
in property <[RecentConnection]> recent-connections;
|
|
in property <bool> update-available: false;
|
|
in property <string> current-version: "";
|
|
in property <string> latest-version: "";
|
|
in property <string> release-name: "";
|
|
in property <[ReleaseNoteBlock]> release-note-blocks;
|
|
in property <string> release-date: "";
|
|
in-out property <string> offline-warning: "";
|
|
in property <bool> connection-dialog-open: false;
|
|
in property <string> connection-status-text: "";
|
|
in property <bool> connection-pending: false;
|
|
in property <bool> connection-password-required: false;
|
|
in property <bool> connection-validating: false;
|
|
in-out property <string> connection-password: "";
|
|
in-out property <bool> connection-remember-password: false;
|
|
in property <bool> permission-dialog-open: false;
|
|
in property <bool> screen-recording-granted: true;
|
|
in property <bool> accessibility-granted: true;
|
|
in property <bool> portable-service-settings-visible: false;
|
|
in property <bool> portable-service-dialog-open: false;
|
|
in property <bool> portable-service-suppressed-notice-open: false;
|
|
in property <bool> portable-service-installed: false;
|
|
in property <bool> portable-service-installing: false;
|
|
in property <bool> portable-service-succeeded: false;
|
|
in property <string> portable-service-status: "";
|
|
in-out property <bool> portable-service-do-not-remind: false;
|
|
|
|
in-out property <int> language-index: 0;
|
|
in-out property <int> video-quality-index: 2;
|
|
in-out property <int> frame-rate-index: 1;
|
|
in-out property <int> codec-index: 0;
|
|
in-out property <bool> hardware-codec-enabled: true;
|
|
in-out property <bool> turn-enabled: true;
|
|
in-out property <bool> srtp-enabled: false;
|
|
in-out property <bool> self-hosted-enabled: false;
|
|
in-out property <bool> autostart-enabled: false;
|
|
in-out property <bool> daemon-enabled: false;
|
|
in-out property <bool> minimize-to-tray-enabled: false;
|
|
in-out property <string> file-save-path: "";
|
|
in-out property <string> server-host: "";
|
|
in-out property <string> server-port: "";
|
|
in-out property <string> coturn-port: "";
|
|
in property <bool> settings-session-active: false;
|
|
// Keep the setting visible on every platform. Unsupported builds expose it
|
|
// as disabled so the fixed settings layout never turns into a blank row.
|
|
in property <bool> hardware-codec-available: true;
|
|
|
|
callback copy-local-id;
|
|
callback toggle-password-visibility;
|
|
callback reset-password(string) -> bool;
|
|
callback format-remote-id(string) -> string;
|
|
callback connect-requested(string);
|
|
callback recent-connect(string);
|
|
callback recent-edit-alias(string, string);
|
|
callback recent-delete(string);
|
|
callback save-settings;
|
|
callback cancel-settings;
|
|
callback save-self-hosted-settings;
|
|
callback cancel-self-hosted-settings;
|
|
callback browse-save-path;
|
|
callback open-download;
|
|
callback connection-cancel;
|
|
callback connection-acknowledge;
|
|
callback connection-submit-password(string, bool);
|
|
callback reset-remote-id;
|
|
callback request-screen-recording-permission;
|
|
callback request-accessibility-permission;
|
|
callback install-portable-service;
|
|
callback cancel-portable-service;
|
|
callback acknowledge-portable-service;
|
|
callback acknowledge-portable-service-suppressed;
|
|
callback main-title-drag(int, length, length);
|
|
callback minimize-main-window;
|
|
callback close-main-window;
|
|
|
|
private property <bool> menu-open: false;
|
|
in-out property <bool> settings-open: false;
|
|
in-out property <bool> self-host-settings-open: false;
|
|
in-out property <bool> about-open: false;
|
|
in-out property <bool> update-open: root.update-available;
|
|
in-out property <bool> reset-password-open: false;
|
|
in-out property <bool> reset-password-invalid: false;
|
|
in-out property <string> new-password-input: "";
|
|
in-out property <bool> alias-open: false;
|
|
private property <string> alias-remote-id: "";
|
|
in-out property <string> alias-input: "";
|
|
in-out property <bool> delete-open: false;
|
|
private property <string> delete-remote-id: "";
|
|
private property <bool> copy-toast: false;
|
|
private property <bool> compact-language: root.language-index == 0;
|
|
private property <bool> update-icon-blink-on:
|
|
root.update-available && mod(animation-tick(), 2s) < 1s;
|
|
private property <bool> recent-tooltip-visible: false;
|
|
private property <string> recent-tooltip-name: "";
|
|
private property <string> recent-tooltip-host: "";
|
|
private property <string> recent-tooltip-id: "";
|
|
private property <bool> recent-tooltip-online: false;
|
|
private property <length> recent-tooltip-pointer-x: 0px;
|
|
private property <length> recent-tooltip-pointer-y: 0px;
|
|
private property <length> recent-tooltip-width: 260px;
|
|
private property <length> recent-tooltip-height:
|
|
root.recent-tooltip-host != "" && root.recent-tooltip-host != root.recent-tooltip-name
|
|
? 80px : 64px;
|
|
private property <length> recent-tooltip-x: min(
|
|
root.width - root.recent-tooltip-width - 8px,
|
|
max(8px,
|
|
root.recent-tooltip-pointer-x > root.width * 0.7
|
|
? root.recent-tooltip-pointer-x - root.recent-tooltip-width - 12px
|
|
: root.recent-tooltip-pointer-x + 12px));
|
|
private property <length> recent-tooltip-y: min(
|
|
root.height - root.titlebar-height - root.recent-tooltip-height - 8px,
|
|
max(8px, root.recent-tooltip-pointer-y - root.recent-tooltip-height - 8px));
|
|
|
|
reset-remote-id => {
|
|
root.remote-id-input = "";
|
|
remote-id-editor.focus();
|
|
}
|
|
|
|
window-surface := Rectangle {
|
|
width: root.width;
|
|
height: root.height;
|
|
background: root.wayland-titlebar ? #f6f5f4 : transparent;
|
|
border-radius:
|
|
root.wayland-titlebar ? root.wayland-corner-radius : 0px;
|
|
clip: root.wayland-titlebar;
|
|
|
|
if root.custom-titlebar && root.wayland-titlebar: Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: parent.width;
|
|
height: root.titlebar-height;
|
|
background: #f6f5f4;
|
|
z: 100;
|
|
|
|
Text {
|
|
x: 80px;
|
|
width: parent.width - 160px;
|
|
height: parent.height;
|
|
text: "CrossDesk";
|
|
color: root.window-active ? #3d3d3d : #747474;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
overflow: elide;
|
|
}
|
|
wayland-title-drag := TouchArea {
|
|
width: parent.width - 80px;
|
|
property <int> phase: self.pressed ? 1 : 0;
|
|
changed phase => {
|
|
root.main-title-drag(phase, self.mouse-x, self.mouse-y);
|
|
}
|
|
moved => {
|
|
if (self.pressed) {
|
|
root.main-title-drag(2, self.mouse-x, self.mouse-y);
|
|
}
|
|
}
|
|
}
|
|
wayland-minimize-button := Rectangle {
|
|
x: parent.width - 74px;
|
|
y: 4px;
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 12px;
|
|
background: wayland-minimize-touch.pressed ? #c0bfbc
|
|
: wayland-minimize-touch.has-hover ? #deddda
|
|
: root.window-active ? #e6e6e6
|
|
: transparent;
|
|
accessible-role: button;
|
|
accessible-label: "Minimize";
|
|
accessible-action-default => { wayland-minimize-touch.clicked(); }
|
|
Rectangle {
|
|
x: 8px;
|
|
y: 13px;
|
|
width: 8px;
|
|
height: 0.75px;
|
|
background: root.window-active
|
|
|| wayland-minimize-touch.has-hover
|
|
|| wayland-minimize-touch.pressed ? #454545 : #898989;
|
|
}
|
|
wayland-minimize-touch := TouchArea {
|
|
clicked => { root.minimize-main-window(); }
|
|
}
|
|
}
|
|
wayland-close-button := Rectangle {
|
|
x: parent.width - 34px;
|
|
y: 4px;
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 12px;
|
|
background: wayland-close-touch.pressed ? #b2161d
|
|
: wayland-close-touch.has-hover ? #e01b24
|
|
: root.window-active ? #e6e6e6
|
|
: transparent;
|
|
accessible-role: button;
|
|
accessible-label: "Close";
|
|
accessible-action-default => { wayland-close-touch.clicked(); }
|
|
Path {
|
|
width: parent.width;
|
|
height: parent.height;
|
|
viewbox-width: 24;
|
|
viewbox-height: 24;
|
|
commands: "M 14.75 14.75 L 8.25 8.25 M 14.75 8.25 L 8.25 14.75";
|
|
stroke: wayland-close-touch.has-hover
|
|
|| wayland-close-touch.pressed ? white
|
|
: root.window-active ? #454545 : #898989;
|
|
stroke-width: 1px;
|
|
}
|
|
wayland-close-touch := TouchArea {
|
|
clicked => { root.close-main-window(); }
|
|
}
|
|
}
|
|
Rectangle {
|
|
y: parent.height - 1px;
|
|
height: 1px;
|
|
background: #d5d3d0;
|
|
}
|
|
}
|
|
|
|
if root.custom-titlebar && !root.wayland-titlebar: Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: root.width;
|
|
height: 31px;
|
|
background: #f9f9f9;
|
|
z: 100;
|
|
|
|
Image {
|
|
x: 8px;
|
|
y: 7px;
|
|
width: 16px;
|
|
height: 16px;
|
|
source: @image-url("../../../icons/linux/crossdesk_16x16.png");
|
|
image-fit: contain;
|
|
}
|
|
Text {
|
|
x: 30px;
|
|
width: parent.width - 122px;
|
|
height: parent.height;
|
|
text: "CrossDesk";
|
|
color: #202124;
|
|
font-size: 12px;
|
|
vertical-alignment: center;
|
|
overflow: elide;
|
|
}
|
|
title-drag := TouchArea {
|
|
x: 0px;
|
|
width: parent.width - 92px;
|
|
property <int> phase: self.pressed ? 1 : 0;
|
|
changed phase => { root.main-title-drag(phase, self.mouse-x, self.mouse-y); }
|
|
moved => { if (self.pressed) { root.main-title-drag(2, self.mouse-x, self.mouse-y); } }
|
|
}
|
|
minimize-button := Rectangle {
|
|
x: parent.width - 92px;
|
|
width: 46px;
|
|
height: parent.height;
|
|
background: minimize-touch.pressed ? #c7c7c7
|
|
: minimize-touch.has-hover ? #e5e5e5
|
|
: transparent;
|
|
accessible-role: button;
|
|
accessible-label: "Minimize";
|
|
accessible-action-default => { minimize-touch.clicked(); }
|
|
Text {
|
|
text: FontAwesomeIcons.minus;
|
|
color: #202124;
|
|
font-family: "Font Awesome 6 Free";
|
|
font-weight: 900;
|
|
font-size: 10px;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
accessible-role: none;
|
|
}
|
|
minimize-touch := TouchArea { clicked => { root.minimize-main-window(); } }
|
|
}
|
|
close-button := Rectangle {
|
|
x: parent.width - 46px;
|
|
width: 46px;
|
|
height: parent.height;
|
|
background: close-touch.pressed ? #b3251b
|
|
: close-touch.has-hover ? #c42b1c
|
|
: transparent;
|
|
accessible-role: button;
|
|
accessible-label: "Close";
|
|
accessible-action-default => { close-touch.clicked(); }
|
|
Text {
|
|
text: FontAwesomeIcons.xmark;
|
|
color: close-touch.has-hover || close-touch.pressed ? white : #202124;
|
|
font-family: "Font Awesome 6 Free";
|
|
font-weight: 900;
|
|
font-size: 12px;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
accessible-role: none;
|
|
}
|
|
close-touch := TouchArea { clicked => { root.close-main-window(); } }
|
|
}
|
|
Rectangle {
|
|
y: parent.height - 1px;
|
|
height: 1px;
|
|
background: #d4d4d4;
|
|
}
|
|
}
|
|
|
|
content-layer := Rectangle {
|
|
x: 0px;
|
|
y: root.titlebar-height;
|
|
width: root.width;
|
|
height: root.height - self.y;
|
|
clip: true;
|
|
|
|
Rectangle {
|
|
width: parent.width;
|
|
height: parent.height;
|
|
background: white;
|
|
border-width: 0px;
|
|
border-radius: 0px;
|
|
|
|
focus-sink := FocusScope { x: 0px; y: 0px; width: 0px; height: 0px; }
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
|
|
// Slint owns the client area below the native macOS title bar. Draw
|
|
// the boundary here because AppKit's titlebar separator is not shown
|
|
// reliably when winit creates a window without an NSToolbar.
|
|
Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: parent.width;
|
|
height: 1px;
|
|
background: ImGuiLineStyle.control-separator;
|
|
z: 7;
|
|
}
|
|
|
|
// App actions live in the content header; window controls and dragging
|
|
// remain in the native or Windows-specific title bar above it.
|
|
menu-button := IconButton {
|
|
x: parent.width - 40px;
|
|
y: 4px;
|
|
width: 32px;
|
|
height: 32px;
|
|
icon: FontAwesomeIcons.bars;
|
|
icon-size: 14px;
|
|
hover-background: #e1e5eb;
|
|
pressed-background: #cbd1d9;
|
|
z: 8;
|
|
clicked => { root.menu-open = !root.menu-open; }
|
|
}
|
|
if root.update-available && !root.menu-open && root.update-icon-blink-on: Text {
|
|
x: menu-button.x + 16px;
|
|
y: menu-button.y + 1px;
|
|
width: 16px;
|
|
height: 16px;
|
|
text: FontAwesomeIcons.circle-arrow-up;
|
|
color: #24272d;
|
|
font-family: "Font Awesome 6 Free";
|
|
font-weight: 900;
|
|
font-size: 13px;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
z: 9;
|
|
}
|
|
|
|
// Local and remote desktop panels.
|
|
Rectangle {
|
|
y: 0px;
|
|
height: 234px;
|
|
background: white;
|
|
|
|
SectionTitle { x: 29px; y: 9px; width: 256px; height: 31px; text: UiStrings.local-desktop; }
|
|
Rectangle {
|
|
x: 29px;
|
|
y: 42px;
|
|
width: 256px;
|
|
height: 183px;
|
|
background: #eff0f2;
|
|
border-radius: 9px;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
|
|
Text { x: 8px; y: 10px; width: 160px; height: 26px; text: UiStrings.local-id; color: #111111; font-size: ImGuiFontStyle.panel-label; }
|
|
Rectangle {
|
|
x: 8px;
|
|
y: 42px;
|
|
width: 160px;
|
|
height: 38px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
Text {
|
|
x: 8px;
|
|
// Compensate for the font's ascender-heavy
|
|
// metrics so digits sit at the optical center.
|
|
y: 4px;
|
|
width: parent.width - 16px;
|
|
height: parent.height - 4px;
|
|
text: root.local-id;
|
|
color: #20242a;
|
|
font-size: ImGuiFontStyle.field-value;
|
|
letter-spacing: 1px;
|
|
horizontal-alignment: left;
|
|
vertical-alignment: center;
|
|
}
|
|
}
|
|
IconButton {
|
|
x: 174px;
|
|
y: 46px;
|
|
width: 29px;
|
|
height: 30px;
|
|
icon: FontAwesomeIcons.copy;
|
|
icon-size: 16px;
|
|
tooltip: UiStrings.copied;
|
|
clicked => {
|
|
root.copy-local-id();
|
|
root.copy-toast = true;
|
|
copy-timer.restart();
|
|
}
|
|
}
|
|
Rectangle { x: 8px; y: 88px; width: 240px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
Text { x: 8px; y: 101px; width: 160px; height: 26px; text: UiStrings.password; color: #111111; font-size: ImGuiFontStyle.panel-label; }
|
|
Rectangle {
|
|
x: 8px;
|
|
y: 129px;
|
|
width: 160px;
|
|
height: 39px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
Text {
|
|
x: 8px;
|
|
y: 4px;
|
|
width: parent.width - 16px;
|
|
height: parent.height - 4px;
|
|
text: root.password-visible ? root.local-password : "••••••";
|
|
color: #20242a;
|
|
font-size: ImGuiFontStyle.field-value;
|
|
letter-spacing: 2px;
|
|
horizontal-alignment: left;
|
|
vertical-alignment: center;
|
|
}
|
|
}
|
|
IconButton {
|
|
x: 174px;
|
|
y: 133px;
|
|
width: 29px;
|
|
height: 30px;
|
|
icon: root.password-visible ? FontAwesomeIcons.eye : FontAwesomeIcons.eye-slash;
|
|
icon-size: 17px;
|
|
clicked => { root.toggle-password-visibility(); }
|
|
}
|
|
IconButton {
|
|
x: 214px;
|
|
y: 133px;
|
|
width: 29px;
|
|
height: 30px;
|
|
icon: FontAwesomeIcons.pen;
|
|
icon-size: 15px;
|
|
clicked => { root.reset-password-open = true; }
|
|
}
|
|
}
|
|
|
|
Rectangle { x: parent.width / 2; y: 18px; width: 1px; height: 206px; background: ImGuiLineStyle.divider; }
|
|
|
|
SectionTitle { x: 356px; y: 9px; width: 256px; height: 31px; text: UiStrings.remote-desktop; }
|
|
Rectangle {
|
|
x: 356px;
|
|
y: 42px;
|
|
width: 256px;
|
|
height: 183px;
|
|
background: #eff0f2;
|
|
border-radius: 9px;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
|
|
Text { x: 8px; y: 10px; width: 160px; height: 26px; text: UiStrings.remote-id; color: #111111; font-size: ImGuiFontStyle.panel-label; }
|
|
Rectangle {
|
|
x: 8px;
|
|
y: 42px;
|
|
width: 160px;
|
|
height: 38px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
remote-id-editor := TextInput {
|
|
x: 10px;
|
|
y: 1.5px;
|
|
width: parent.width - 20px;
|
|
height: parent.height - 3px;
|
|
text <=> root.remote-id-input;
|
|
font-size: ImGuiFontStyle.field-value;
|
|
input-type: InputType.number;
|
|
color: #202124;
|
|
vertical-alignment: center;
|
|
selection-foreground-color: white;
|
|
selection-background-color: #2463c7;
|
|
// Run formatting after the input event has
|
|
// finished so the caret state isn't reset by
|
|
// a synchronous two-way binding rewrite.
|
|
edited => { remote-id-format-timer.restart(); }
|
|
accepted => { root.connect-requested(root.remote-id-input); }
|
|
}
|
|
}
|
|
IconButton {
|
|
x: 175px;
|
|
y: 42px;
|
|
width: 64px;
|
|
height: 38px;
|
|
normal-background: #a7cefc;
|
|
hover-background: #b8d8fc;
|
|
pressed-background: #76aeea;
|
|
border-radius: 4px;
|
|
icon: FontAwesomeIcons.arrow-right-long;
|
|
icon-size: 25px;
|
|
clicked => { root.connect-requested(root.remote-id-input); }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recent connections: horizontal cards with thumbnail, state and actions.
|
|
recent-panel := Rectangle {
|
|
y: 234px;
|
|
height: 192px;
|
|
background: white;
|
|
border-width: 0px;
|
|
border-color: ImGuiLineStyle.border;
|
|
|
|
Rectangle { y: 0px; height: 1px; background: ImGuiLineStyle.border; }
|
|
|
|
SectionTitle { x: 29px; y: 7px; height: 28px; text: UiStrings.recent-connections; }
|
|
|
|
recent-list := Rectangle {
|
|
x: 29px;
|
|
y: 42px;
|
|
width: parent.width - 58px;
|
|
height: 139px;
|
|
background: #eff0f2;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 10px;
|
|
clip: true;
|
|
|
|
recent-scroll := ScrollView {
|
|
width: parent.width;
|
|
height: parent.height;
|
|
horizontal-stretch: 1;
|
|
|
|
HorizontalLayout {
|
|
padding-left: 8px;
|
|
padding-top: 8px;
|
|
padding-bottom: 14px;
|
|
spacing: 24px;
|
|
alignment: start;
|
|
for connection[index] in root.recent-connections: connection-card := Rectangle {
|
|
width: 178px;
|
|
height: 117px;
|
|
background: transparent;
|
|
private property <length> content-width: self.width - 30px;
|
|
private property <length> toolbar-width: 79px;
|
|
private property <length> toolbar-right-padding: 3px;
|
|
|
|
Image {
|
|
x: 7px;
|
|
y: 7px;
|
|
width: connection-card.content-width;
|
|
height: 84px;
|
|
source: connection.thumbnail;
|
|
image-fit: cover;
|
|
}
|
|
Rectangle {
|
|
x: 7px;
|
|
y: 91px;
|
|
width: connection-card.content-width;
|
|
height: 25px;
|
|
background: #00000018;
|
|
border-radius: 3px;
|
|
Text {
|
|
x: 4px;
|
|
y: 1px;
|
|
height: parent.height - self.y;
|
|
width: max(0px, parent.width - self.x - 4px
|
|
- (card-touch.has-hover
|
|
? connection-card.toolbar-width + connection-card.toolbar-right-padding
|
|
: 0px));
|
|
text: connection.display-name;
|
|
color: #30343b;
|
|
// The ImGui card footer uses its own 0.52 font
|
|
// scale and renders slightly larger than the
|
|
// compact body text used in dialogs.
|
|
font-size: ImGuiFontStyle.base;
|
|
overflow: elide;
|
|
vertical-alignment: center;
|
|
}
|
|
}
|
|
if connection.online: OnlineStatusIndicator {
|
|
x: 16px - self.width / 2;
|
|
y: 16px - self.height / 2;
|
|
dot-diameter: 9px;
|
|
}
|
|
if !connection.online: Rectangle {
|
|
x: 11.5px;
|
|
y: 11.5px;
|
|
width: 9px;
|
|
height: 9px;
|
|
border-radius: 4.5px;
|
|
background: #9ca3af;
|
|
}
|
|
card-touch := TouchArea {
|
|
x: 7px;
|
|
y: 7px;
|
|
width: connection-card.content-width;
|
|
height: 109px;
|
|
clicked => { root.recent-connect(connection.remote-id); }
|
|
image-touch := TouchArea {
|
|
width: parent.width;
|
|
height: 84px;
|
|
clicked => { root.recent-connect(connection.remote-id); }
|
|
changed has-hover => {
|
|
if self.has-hover {
|
|
root.recent-tooltip-name = connection.display-name;
|
|
root.recent-tooltip-host = connection.host-name;
|
|
root.recent-tooltip-id = connection.remote-id;
|
|
root.recent-tooltip-online = connection.online;
|
|
root.recent-tooltip-pointer-x = recent-panel.x + recent-list.x
|
|
+ recent-scroll.x + recent-scroll.viewport-x
|
|
+ connection-card.x + card-touch.x + self.mouse-x;
|
|
root.recent-tooltip-pointer-y = recent-panel.y + recent-list.y
|
|
+ recent-scroll.y + recent-scroll.viewport-y
|
|
+ connection-card.y + card-touch.y + self.mouse-y;
|
|
root.recent-tooltip-visible = true;
|
|
} else if root.recent-tooltip-id == connection.remote-id {
|
|
root.recent-tooltip-visible = false;
|
|
}
|
|
}
|
|
moved => {
|
|
if self.has-hover {
|
|
root.recent-tooltip-pointer-x = recent-panel.x + recent-list.x
|
|
+ recent-scroll.x + recent-scroll.viewport-x
|
|
+ connection-card.x + card-touch.x + self.mouse-x;
|
|
root.recent-tooltip-pointer-y = recent-panel.y + recent-list.y
|
|
+ recent-scroll.y + recent-scroll.viewport-y
|
|
+ connection-card.y + card-touch.y + self.mouse-y;
|
|
}
|
|
}
|
|
}
|
|
if card-touch.has-hover: Rectangle {
|
|
x: parent.width - self.width - connection-card.toolbar-right-padding;
|
|
y: 85px;
|
|
width: connection-card.toolbar-width;
|
|
height: 23px;
|
|
background: #4a4e55dc;
|
|
border-radius: 5px;
|
|
HorizontalLayout {
|
|
spacing: 0px;
|
|
IconButton {
|
|
width: 26px; height: 23px; icon: FontAwesomeIcons.pen; icon-size: 12px; icon-color: white;
|
|
hover-background: #ffffff2e;
|
|
pressed-background: #598cf273;
|
|
clicked => {
|
|
root.alias-remote-id = connection.remote-id;
|
|
root.alias-input = connection.display-name;
|
|
root.alias-open = true;
|
|
}
|
|
}
|
|
IconButton {
|
|
width: 26px; height: 23px; icon: FontAwesomeIcons.trash-can; icon-size: 12px; icon-color: white;
|
|
hover-background: #ffffff2e;
|
|
pressed-background: #598cf273;
|
|
clicked => {
|
|
root.delete-remote-id = connection.remote-id;
|
|
root.delete-open = true;
|
|
}
|
|
}
|
|
IconButton {
|
|
width: 27px; height: 23px; icon: FontAwesomeIcons.arrow-right-long; icon-size: 13px; icon-color: white;
|
|
hover-background: #ffffff2e;
|
|
pressed-background: #598cf273;
|
|
clicked => { root.recent-connect(connection.remote-id); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if index < root.recent-connections.length - 1: Rectangle {
|
|
x: 183px;
|
|
y: 7px;
|
|
width: 1px;
|
|
height: 109px;
|
|
background: #0000007a;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Status bar.
|
|
Rectangle {
|
|
y: 426px;
|
|
height: 24px;
|
|
background: #fafbfc;
|
|
Rectangle {
|
|
y: 0px;
|
|
height: 1px;
|
|
background: ImGuiLineStyle.border;
|
|
}
|
|
if root.signal-connected && !root.signal-tls-error: OnlineStatusIndicator {
|
|
x: 15px - self.width / 2;
|
|
y: 12px - self.height / 2;
|
|
dot-diameter: 8px;
|
|
}
|
|
if !root.signal-connected || root.signal-tls-error: Rectangle {
|
|
x: 11px;
|
|
y: 8px;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 4px;
|
|
background: root.signal-tls-error ? #f59e0b : #ef4444;
|
|
}
|
|
Text {
|
|
x: 28px;
|
|
y: 3px;
|
|
height: 18px;
|
|
text: root.signal-tls-error ? UiStrings.tls-error
|
|
: root.signal-connected ? UiStrings.signal-connected
|
|
: UiStrings.signal-disconnected;
|
|
color: #343941;
|
|
font-size: ImGuiFontStyle.base;
|
|
vertical-alignment: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Match the ImGui recent-connection tooltip while keeping it outside the
|
|
// clipped ScrollView. It is deliberately limited to the thumbnail area.
|
|
if root.recent-tooltip-visible: Rectangle {
|
|
x: root.recent-tooltip-x;
|
|
y: root.recent-tooltip-y;
|
|
width: root.recent-tooltip-width;
|
|
height: root.recent-tooltip-height;
|
|
background: #22252bf2;
|
|
border-width: 1px;
|
|
border-color: #ffffff38;
|
|
border-radius: 5px;
|
|
z: 50;
|
|
|
|
VerticalLayout {
|
|
padding: 8px;
|
|
spacing: 2px;
|
|
Text {
|
|
text: UiStrings.device-name + ": " + root.recent-tooltip-name;
|
|
color: white;
|
|
font-size: ImGuiFontStyle.small;
|
|
overflow: elide;
|
|
}
|
|
if root.recent-tooltip-host != "" && root.recent-tooltip-host != root.recent-tooltip-name: Text {
|
|
text: root.recent-tooltip-host;
|
|
color: #e1e4e8;
|
|
font-size: ImGuiFontStyle.small;
|
|
overflow: elide;
|
|
}
|
|
Text {
|
|
text: UiStrings.remote-id + ": " + root.recent-tooltip-id;
|
|
color: #e1e4e8;
|
|
font-size: ImGuiFontStyle.small;
|
|
overflow: elide;
|
|
}
|
|
Text {
|
|
text: root.recent-tooltip-online ? UiStrings.online : UiStrings.offline;
|
|
color: root.recent-tooltip-online ? #62d98b : #d1d5db;
|
|
font-size: ImGuiFontStyle.small;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dismiss the title menu when clicking anywhere outside of it.
|
|
if root.menu-open: TouchArea {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: parent.width;
|
|
height: parent.height;
|
|
z: 9;
|
|
clicked => {
|
|
root.menu-open = false;
|
|
focus-sink.focus();
|
|
}
|
|
}
|
|
|
|
// Title menu.
|
|
if root.menu-open: Rectangle {
|
|
x: menu-button.x + menu-button.width - self.width;
|
|
y: menu-button.y + menu-button.height + 2px;
|
|
width: min(118px, max(menu-settings-label.preferred-width,
|
|
menu-about-label.preferred-width + (root.update-available ? 25px : 0px)) + 28px);
|
|
height: 64px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 5px;
|
|
z: 10;
|
|
TouchArea { }
|
|
VerticalLayout {
|
|
padding: 4px;
|
|
spacing: 2px;
|
|
menu-settings := Rectangle {
|
|
height: 27px;
|
|
background: settings-touch.pressed ? #d8dadd
|
|
: settings-touch.has-hover ? #f0f1f2
|
|
: white;
|
|
border-width: 0px;
|
|
border-radius: 3px;
|
|
accessible-role: button;
|
|
accessible-label: UiStrings.settings;
|
|
accessible-action-default => { settings-touch.clicked(); }
|
|
menu-settings-label := Text {
|
|
x: 9px;
|
|
height: parent.height;
|
|
text: UiStrings.settings;
|
|
color: #2d3138;
|
|
vertical-alignment: center;
|
|
accessible-role: none;
|
|
}
|
|
settings-touch := TouchArea {
|
|
mouse-cursor: pointer;
|
|
clicked => { root.menu-open = false; root.settings-open = true; }
|
|
}
|
|
}
|
|
menu-about := Rectangle {
|
|
height: 27px;
|
|
background: about-touch.pressed ? #d8dadd
|
|
: about-touch.has-hover ? #f0f1f2
|
|
: white;
|
|
border-width: 0px;
|
|
border-radius: 3px;
|
|
accessible-role: button;
|
|
accessible-label: UiStrings.about;
|
|
accessible-action-default => { about-touch.clicked(); }
|
|
menu-about-label := Text {
|
|
x: 9px;
|
|
height: parent.height;
|
|
text: UiStrings.about;
|
|
color: #2d3138;
|
|
vertical-alignment: center;
|
|
accessible-role: none;
|
|
}
|
|
if root.update-available && root.update-icon-blink-on: Text {
|
|
x: menu-about-label.x + menu-about-label.preferred-width + 7px;
|
|
width: 18px;
|
|
height: parent.height;
|
|
text: FontAwesomeIcons.circle-arrow-up;
|
|
color: #2d3138;
|
|
font-family: "Font Awesome 6 Free";
|
|
font-weight: 900;
|
|
font-size: 16px;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
accessible-role: none;
|
|
}
|
|
about-touch := TouchArea {
|
|
mouse-cursor: pointer;
|
|
clicked => { root.menu-open = false; root.about-open = true; }
|
|
}
|
|
}
|
|
}
|
|
Rectangle {
|
|
x: 4px;
|
|
y: 31.5px;
|
|
width: parent.width - 8px;
|
|
height: 1px;
|
|
background: ImGuiLineStyle.separator;
|
|
z: 1;
|
|
}
|
|
}
|
|
|
|
copy-timer := Timer {
|
|
interval: 1000ms;
|
|
triggered => { root.copy-toast = false; }
|
|
}
|
|
remote-id-format-timer := Timer {
|
|
interval: 1ms;
|
|
triggered => {
|
|
let formatted = root.format-remote-id(root.remote-id-input);
|
|
root.remote-id-input = formatted;
|
|
// IDs are ASCII-only, so character-count is also the UTF-8 offset
|
|
// expected by set-selection-offsets().
|
|
remote-id-editor.set-selection-offsets(
|
|
formatted.character-count, formatted.character-count);
|
|
}
|
|
}
|
|
if root.copy-toast: Rectangle {
|
|
x: 180px; y: 170px; width: 280px; height: 68px;
|
|
background: #fffffff2;
|
|
border-radius: 8px;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
z: 30;
|
|
Text { text: UiStrings.copied; color: #333840; horizontal-alignment: center; vertical-alignment: center; }
|
|
}
|
|
|
|
// Reset password modal.
|
|
if root.reset-password-open: Rectangle {
|
|
background: #00000042;
|
|
z: 40;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: root.compact-language ? 205px : 160px;
|
|
y: 140px;
|
|
width: root.compact-language ? 230px : 320px;
|
|
height: 170px;
|
|
VerticalLayout {
|
|
padding: 20px;
|
|
spacing: 12px;
|
|
DialogPromptText { prompt: UiStrings.new-password; }
|
|
Rectangle {
|
|
height: 28px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
|
|
LineEdit {
|
|
x: 1px;
|
|
y: 1.5px;
|
|
width: parent.width - 2px;
|
|
height: parent.height - 2px;
|
|
text <=> root.new-password-input;
|
|
input-type: InputType.password;
|
|
}
|
|
LineEditFocusUnderlineMask {
|
|
x: 5px;
|
|
y: parent.height - 3px;
|
|
width: parent.width - 10px;
|
|
}
|
|
}
|
|
Text { height: root.reset-password-invalid ? 18px : 0px; visible: root.reset-password-invalid; text: UiStrings.invalid-password; color: #d92d20; font-size: ImGuiFontStyle.small; horizontal-alignment: center; }
|
|
HorizontalLayout {
|
|
alignment: center; spacing: 8px;
|
|
PrimaryButton {
|
|
text: UiStrings.ok;
|
|
clicked => {
|
|
if (root.reset-password(root.new-password-input)) {
|
|
root.new-password-input = "";
|
|
root.reset-password-invalid = false;
|
|
root.reset-password-open = false;
|
|
} else { root.reset-password-invalid = true; }
|
|
}
|
|
}
|
|
SecondaryButton { text: UiStrings.cancel; clicked => { root.new-password-input = ""; root.reset-password-invalid = false; root.reset-password-open = false; } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recent connection alias modal.
|
|
if root.alias-open: Rectangle {
|
|
background: #00000042;
|
|
z: 40;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: root.compact-language ? 205px : 160px;
|
|
y: 145px;
|
|
width: root.compact-language ? 230px : 320px;
|
|
height: 160px;
|
|
VerticalLayout {
|
|
padding: 20px; spacing: 14px;
|
|
DialogPromptText { prompt: UiStrings.edit-alias; }
|
|
Rectangle {
|
|
height: 28px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
|
|
LineEdit {
|
|
x: 1px;
|
|
y: 1.5px;
|
|
width: parent.width - 2px;
|
|
height: parent.height - 2px;
|
|
text <=> root.alias-input;
|
|
accepted => {
|
|
root.recent-edit-alias(root.alias-remote-id, root.alias-input);
|
|
root.alias-open = false;
|
|
}
|
|
}
|
|
LineEditFocusUnderlineMask {
|
|
x: 5px;
|
|
y: parent.height - 3px;
|
|
width: parent.width - 10px;
|
|
}
|
|
}
|
|
HorizontalLayout {
|
|
alignment: center; spacing: 8px;
|
|
PrimaryButton { text: UiStrings.ok; clicked => { root.recent-edit-alias(root.alias-remote-id, root.alias-input); root.alias-open = false; } }
|
|
SecondaryButton { text: UiStrings.cancel; clicked => { root.alias-open = false; } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Delete confirmation modal.
|
|
if root.delete-open: Rectangle {
|
|
background: #00000042;
|
|
z: 40;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: root.compact-language ? 205px : 160px;
|
|
y: 155px;
|
|
width: root.compact-language ? 230px : 320px;
|
|
height: 140px;
|
|
VerticalLayout {
|
|
padding: 20px; spacing: 18px;
|
|
DialogPromptText { prompt: UiStrings.confirm-delete; }
|
|
HorizontalLayout {
|
|
alignment: center; spacing: 8px;
|
|
PrimaryButton { text: UiStrings.ok; clicked => { root.recent-delete(root.delete-remote-id); root.delete-open = false; } }
|
|
SecondaryButton { text: UiStrings.cancel; clicked => { root.delete-open = false; } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Offline/error warning modal.
|
|
if root.offline-warning != "": Rectangle {
|
|
background: #00000042;
|
|
z: 39;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: 185px; y: 150px; width: 270px; height: 150px;
|
|
VerticalLayout {
|
|
padding: 20px; spacing: 18px;
|
|
DialogPromptText { prompt: root.offline-warning; }
|
|
PrimaryButton { text: UiStrings.ok; clicked => { root.offline-warning = ""; } }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Connection progress and password retry modal from the ImGui client.
|
|
if root.connection-dialog-open: Rectangle {
|
|
background: #00000042;
|
|
z: 48;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: root.connection-password-required ? 211px : 190px;
|
|
y: root.connection-password-required ? 143px : 130px;
|
|
width: root.connection-password-required ? 211px : 260px;
|
|
height: root.connection-password-required ? 158px : 145px;
|
|
|
|
if root.connection-password-required: Rectangle {
|
|
Text {
|
|
y: 38px;
|
|
height: 22px;
|
|
text: root.connection-status-text;
|
|
color: #30343b;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
|
|
if !root.connection-validating: Rectangle {
|
|
x: 71px; y: 63px; width: 70px; height: 23px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 3px;
|
|
connection-password-editor := TextInput {
|
|
x: 5px; y: 1px; width: parent.width - 10px; height: parent.height - 2px;
|
|
text <=> root.connection-password;
|
|
// The legacy ImGui field uses CharsNoBlank without the
|
|
// Password flag, so entered text remains visible.
|
|
input-type: InputType.text;
|
|
color: #202124;
|
|
font-size: ImGuiFontStyle.base;
|
|
vertical-alignment: center;
|
|
selection-foreground-color: white;
|
|
selection-background-color: #2463c7;
|
|
accepted => { root.connection-submit-password(root.connection-password, root.connection-remember-password); }
|
|
}
|
|
Timer {
|
|
interval: 1ms;
|
|
running: true;
|
|
triggered => { connection-password-editor.focus(); }
|
|
}
|
|
}
|
|
|
|
if !root.connection-validating: Rectangle {
|
|
x: 72px; y: 89px; width: 120px; height: 21px;
|
|
ImGuiCheckBox {
|
|
x: 0px; y: 0px;
|
|
checked <=> root.connection-remember-password;
|
|
}
|
|
Text {
|
|
x: 27px; y: 0px;
|
|
width: parent.width - 27px; height: parent.height;
|
|
text: UiStrings.remember-password;
|
|
color: #30343b;
|
|
font-size: ImGuiFontStyle.body;
|
|
vertical-alignment: center;
|
|
}
|
|
TouchArea {
|
|
x: 27px; y: 0px;
|
|
width: parent.width - 27px; height: parent.height;
|
|
clicked => { root.connection-remember-password = !root.connection-remember-password; }
|
|
}
|
|
}
|
|
|
|
if !root.connection-validating: ConnectionDialogButton {
|
|
x: 69px; y: 118px;
|
|
text: UiStrings.ok;
|
|
clicked => { root.connection-submit-password(root.connection-password, root.connection-remember-password); }
|
|
}
|
|
if !root.connection-validating: ConnectionDialogButton {
|
|
x: 117px;
|
|
y: 118px;
|
|
text: UiStrings.cancel;
|
|
clicked => { root.connection-cancel(); }
|
|
}
|
|
}
|
|
|
|
if !root.connection-password-required: VerticalLayout {
|
|
padding: 20px; spacing: 13px;
|
|
DialogPromptText { prompt: root.connection-status-text; }
|
|
HorizontalLayout {
|
|
alignment: center; spacing: 8px;
|
|
if root.connection-pending: SecondaryButton {
|
|
text: UiStrings.cancel;
|
|
clicked => { root.connection-cancel(); }
|
|
}
|
|
if !root.connection-pending: PrimaryButton {
|
|
text: UiStrings.ok;
|
|
clicked => { root.connection-acknowledge(); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// macOS permission gate. On other platforms this remains hidden.
|
|
if root.permission-dialog-open: Rectangle {
|
|
background: transparent;
|
|
z: 50;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: root.compact-language ? 255px : 190px;
|
|
y: 162px;
|
|
width: root.compact-language ? 130px : 260px;
|
|
height: 125px;
|
|
border-radius: 7px;
|
|
Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: parent.width;
|
|
height: 21px;
|
|
background: #d3d3d3;
|
|
border-radius: 7px;
|
|
z: 5;
|
|
Rectangle { y: parent.height - 7px; height: 7px; background: #d3d3d3; }
|
|
Text { x: 6px; text: UiStrings.request-permissions; font-size: ImGuiFontStyle.base; font-weight: 600; color: #202124; vertical-alignment: center; }
|
|
}
|
|
Text { x: 10px; y: 32px; width: root.compact-language ? 110px : 240px; height: 24px; text: UiStrings.permission-required; color: #202124; font-size: 8px; wrap: word-wrap; }
|
|
Text { x: 10px; y: 61px; width: root.compact-language ? 78px : 198px; height: 18px; text: "1. " + UiStrings.accessibility-permission + ":"; color: #202124; font-size: 8px; overflow: elide; vertical-alignment: center; }
|
|
MiniToggleSwitch {
|
|
x: root.compact-language ? 90px : 210px;
|
|
y: 61px;
|
|
checked: root.accessibility-granted;
|
|
enabled: !root.accessibility-granted;
|
|
toggled(value) => { if (value) { root.request-accessibility-permission(); } }
|
|
}
|
|
Text { x: 10px; y: 85px; width: root.compact-language ? 78px : 198px; height: 18px; text: "2. " + UiStrings.screen-recording-permission + ":"; color: #202124; font-size: 8px; overflow: elide; vertical-alignment: center; }
|
|
MiniToggleSwitch {
|
|
x: root.compact-language ? 90px : 210px;
|
|
y: 85px;
|
|
checked: root.screen-recording-granted;
|
|
enabled: !root.screen-recording-granted;
|
|
toggled(value) => { if (value) { root.request-screen-recording-permission(); } }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Settings modal.
|
|
if root.settings-open: Rectangle {
|
|
background: transparent;
|
|
z: 45;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: root.compact-language ? 219px : 190px;
|
|
y: 9px;
|
|
width: root.compact-language ? 202px : 269px;
|
|
height: 432px;
|
|
border-radius: 7px;
|
|
|
|
Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: parent.width;
|
|
height: 21px;
|
|
background: #d3d3d3;
|
|
border-radius: 7px;
|
|
z: 5;
|
|
Rectangle { y: parent.height - 7px; height: 7px; background: #d3d3d3; }
|
|
Text { x: 6px; text: UiStrings.settings; font-size: ImGuiFontStyle.base; font-weight: 600; color: #202124; vertical-alignment: center; }
|
|
}
|
|
|
|
Text { x: 8px; y: 31px; width: root.compact-language ? 108px : 176px; height: 24px; text: UiStrings.language; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
CompactComboBox { x: root.compact-language ? 120px : 188px; y: 30px; model: ["中文", "English", "Русский"]; current-index <=> root.language-index; }
|
|
Rectangle { x: 7px; y: 57px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 61px; width: root.compact-language ? 108px : 176px; height: 24px; text: UiStrings.video-quality; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
CompactComboBox { x: root.compact-language ? 120px : 188px; y: 60px; enabled: !root.settings-session-active; model: [UiStrings.quality-low, UiStrings.quality-medium, UiStrings.quality-high]; current-index <=> root.video-quality-index; }
|
|
Rectangle { x: 7px; y: 87px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 91px; width: root.compact-language ? 108px : 176px; height: 24px; text: UiStrings.frame-rate; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
CompactComboBox { x: root.compact-language ? 120px : 188px; y: 90px; enabled: !root.settings-session-active; model: ["30 fps", "60 fps"]; current-index <=> root.frame-rate-index; }
|
|
Rectangle { x: 7px; y: 117px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 121px; width: root.compact-language ? 108px : 176px; height: 24px; text: UiStrings.codec; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
CompactComboBox { x: root.compact-language ? 120px : 188px; y: 120px; enabled: !root.settings-session-active; model: [UiStrings.codec-h264, UiStrings.codec-av1]; current-index <=> root.codec-index; }
|
|
Rectangle { x: 7px; y: 147px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 151px; width: root.compact-language ? 155px : 225px; height: 24px; text: UiStrings.hardware-codec; color: root.hardware-codec-available ? #202124 : #8b8f95; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
ImGuiCheckBox { x: root.compact-language ? 171px : 238px; y: 151px; checked <=> root.hardware-codec-enabled; enabled: root.hardware-codec-available && !root.settings-session-active; }
|
|
Rectangle { x: 7px; y: 177px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 181px; width: root.compact-language ? 155px : 225px; height: 24px; text: UiStrings.turn-relay; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
ImGuiCheckBox { x: root.compact-language ? 171px : 238px; y: 181px; checked <=> root.turn-enabled; enabled: !root.settings-session-active; }
|
|
Rectangle { x: 7px; y: 207px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 211px; width: root.compact-language ? 155px : 225px; height: 24px; text: UiStrings.srtp; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
ImGuiCheckBox { x: root.compact-language ? 171px : 238px; y: 211px; checked <=> root.srtp-enabled; enabled: !root.settings-session-active; }
|
|
Rectangle { x: 7px; y: 237px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
CompactButton { x: 8px; y: 241px; width: root.compact-language ? 70px : 220px; text: UiStrings.self-hosted; enabled: !root.settings-session-active; clicked => { root.self-host-settings-open = true; } }
|
|
ImGuiCheckBox { x: root.compact-language ? 171px : 238px; y: 241px; checked <=> root.self-hosted-enabled; enabled: !root.settings-session-active; }
|
|
Rectangle { x: 7px; y: 267px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 271px; width: root.compact-language ? 155px : 225px; height: 24px; text: UiStrings.autostart; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
ImGuiCheckBox { x: root.compact-language ? 171px : 238px; y: 271px; checked <=> root.autostart-enabled; enabled: !root.settings-session-active; }
|
|
Rectangle { x: 7px; y: 297px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 301px; width: root.compact-language ? 155px : 225px; height: 24px; text: UiStrings.daemon; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
ImGuiCheckBox { x: root.compact-language ? 171px : 238px; y: 301px; checked <=> root.daemon-enabled; enabled: !root.settings-session-active; }
|
|
Rectangle { x: 7px; y: 327px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 331px; width: root.compact-language ? 155px : 225px; height: 24px; text: UiStrings.minimize-to-tray; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
ImGuiCheckBox { x: root.compact-language ? 171px : 238px; y: 331px; checked <=> root.minimize-to-tray-enabled; enabled: !root.settings-session-active; }
|
|
Rectangle { x: 7px; y: 357px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
|
|
Text { x: 8px; y: 361px; width: root.compact-language ? 108px : 168px; height: 24px; text: UiStrings.file-save-path; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
CompactButton { x: root.compact-language ? 120px : 180px; y: 361px; width: root.compact-language ? 73px : 80px; text: root.file-save-path == "" ? UiStrings.default-desktop : root.file-save-path; enabled: !root.settings-session-active; clicked => { root.browse-save-path(); } }
|
|
|
|
CompactButton { x: root.compact-language ? 63px : 89px; y: 396px; primary: true; text: UiStrings.ok; clicked => { root.save-settings(); root.settings-open = false; root.self-host-settings-open = false; } }
|
|
CompactButton { x: root.compact-language ? 104px : 130px; y: 396px; width: root.compact-language ? 34px : 56px; text: UiStrings.cancel; clicked => { root.cancel-settings(); root.settings-open = false; root.self-host-settings-open = false; } }
|
|
}
|
|
}
|
|
|
|
if root.self-host-settings-open: Rectangle {
|
|
background: transparent;
|
|
z: 49;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: root.compact-language ? 190px : 140px;
|
|
y: 105px;
|
|
width: root.compact-language ? 260px : 360px;
|
|
height: 168px;
|
|
border-radius: 7px;
|
|
|
|
Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: parent.width;
|
|
height: 21px;
|
|
background: #d3d3d3;
|
|
border-radius: 7px;
|
|
z: 5;
|
|
Rectangle { y: parent.height - 7px; height: 7px; background: #d3d3d3; }
|
|
Text { x: 6px; text: UiStrings.self-hosted-settings; font-size: ImGuiFontStyle.base; font-weight: 600; color: #202124; vertical-alignment: center; }
|
|
}
|
|
Text { x: 8px; y: 31px; width: root.compact-language ? 88px : 165px; height: 24px; text: UiStrings.server-host; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
Rectangle {
|
|
x: root.compact-language ? 100px : 173px;
|
|
y: 30px;
|
|
width: root.compact-language ? 152px : 179px;
|
|
height: 24px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
LineEdit { x: 1px; y: 1.5px; width: parent.width - 2px; height: parent.height - 2px; text <=> root.server-host; font-size: ImGuiFontStyle.body; }
|
|
LineEditFocusUnderlineMask { x: 5px; y: parent.height - 3px; width: parent.width - 10px; }
|
|
}
|
|
Rectangle { x: 7px; y: 57px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
Text { x: 8px; y: 61px; width: root.compact-language ? 88px : 165px; height: 24px; text: UiStrings.server-port; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
Rectangle {
|
|
x: root.compact-language ? 100px : 173px;
|
|
y: 60px;
|
|
width: root.compact-language ? 152px : 179px;
|
|
height: 24px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
LineEdit { x: 1px; y: 1.5px; width: parent.width - 2px; height: parent.height - 2px; text <=> root.server-port; input-type: InputType.number; font-size: ImGuiFontStyle.body; }
|
|
LineEditFocusUnderlineMask { x: 5px; y: parent.height - 3px; width: parent.width - 10px; }
|
|
}
|
|
Rectangle { x: 7px; y: 87px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
Text { x: 8px; y: 91px; width: root.compact-language ? 88px : 165px; height: 24px; text: UiStrings.coturn-port; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
|
Rectangle {
|
|
x: root.compact-language ? 100px : 173px;
|
|
y: 90px;
|
|
width: root.compact-language ? 152px : 179px;
|
|
height: 24px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: ImGuiLineStyle.border;
|
|
border-radius: 4px;
|
|
LineEdit { x: 1px; y: 1.5px; width: parent.width - 2px; height: parent.height - 2px; text <=> root.coturn-port; input-type: InputType.number; font-size: ImGuiFontStyle.body; }
|
|
LineEditFocusUnderlineMask { x: 5px; y: parent.height - 3px; width: parent.width - 10px; }
|
|
}
|
|
Rectangle { x: 7px; y: 117px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
|
CompactButton { x: root.compact-language ? 93px : 135px; y: 130px; primary: true; text: UiStrings.ok; clicked => { root.save-self-hosted-settings(); root.self-host-settings-open = false; } }
|
|
CompactButton { x: root.compact-language ? 134px : 176px; y: 130px; width: root.compact-language ? 34px : 56px; text: UiStrings.cancel; clicked => { root.cancel-self-hosted-settings(); root.self-host-settings-open = false; } }
|
|
}
|
|
}
|
|
|
|
// About modal.
|
|
if root.about-open: Rectangle {
|
|
background: transparent;
|
|
z: 46;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: 170px;
|
|
y: 127px;
|
|
width: 300px;
|
|
height: 196px;
|
|
border-radius: 7px;
|
|
|
|
Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: parent.width;
|
|
height: 21px;
|
|
background: #d3d3d3;
|
|
border-radius: 7px;
|
|
z: 5;
|
|
Rectangle { y: parent.height - 7px; height: 7px; background: #d3d3d3; }
|
|
Text { x: 6px; text: UiStrings.about; font-size: ImGuiFontStyle.base; font-weight: 600; color: #202124; vertical-alignment: center; }
|
|
}
|
|
Text { x: 30px; y: 40px; width: 240px; height: 20px; text: UiStrings.version + ": CrossDesk " + root.current-version; color: #202124; font-size: ImGuiFontStyle.body; vertical-alignment: center; }
|
|
if root.update-available: Text { x: 30px; y: 60px; width: 240px; height: 20px; text: UiStrings.update-available + ":"; color: #202124; font-size: ImGuiFontStyle.body; vertical-alignment: center; }
|
|
if root.update-available: Rectangle {
|
|
x: 30px;
|
|
y: 60px;
|
|
width: 240px;
|
|
height: 20px;
|
|
version-link := Text { text: root.latest-version; color: version-touch.has-hover ? #174ea6 : #334fd1; font-size: ImGuiFontStyle.body; horizontal-alignment: center; vertical-alignment: center; }
|
|
version-touch := TouchArea { mouse-cursor: pointer; clicked => { root.open-download(); } }
|
|
}
|
|
Text { x: 30px; y: 85px; width: 240px; height: 20px; text: UiStrings.copyright; color: #202124; font-size: ImGuiFontStyle.body; vertical-alignment: center; }
|
|
Text { x: 30px; y: 105px; width: 240px; height: 20px; text: UiStrings.license; color: #202124; font-size: ImGuiFontStyle.body; vertical-alignment: center; }
|
|
CompactButton { x: 133px; y: 145px; primary: true; text: UiStrings.ok; clicked => { root.about-open = false; } }
|
|
}
|
|
}
|
|
|
|
// Update notification modal.
|
|
if root.update-open && root.update-available: Rectangle {
|
|
background: transparent;
|
|
z: 47;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: 120px;
|
|
y: 52px;
|
|
width: 400px;
|
|
height: 346px;
|
|
border-radius: 7px;
|
|
Text { x: 30px; y: 22px; width: 320px; height: 24px; text: UiStrings.update-available + ": " + root.latest-version; color: #202124; font-size: ImGuiFontStyle.prominent; vertical-alignment: center; }
|
|
Rectangle {
|
|
x: 30px;
|
|
y: 47px;
|
|
width: 320px;
|
|
height: 22px;
|
|
Text {
|
|
x: 0px;
|
|
width: parent.width;
|
|
height: parent.height;
|
|
text: UiStrings.access-website + "https://crossdesk.cn";
|
|
color: website-touch.has-hover ? #174ea6 : #334fd1;
|
|
font-size: ImGuiFontStyle.body;
|
|
horizontal-alignment: left;
|
|
vertical-alignment: center;
|
|
}
|
|
website-touch := TouchArea { mouse-cursor: pointer; clicked => { root.open-download(); } }
|
|
}
|
|
Text {
|
|
x: 30px;
|
|
y: 75px;
|
|
width: 320px;
|
|
height: 20px;
|
|
text: UiStrings.release-notes;
|
|
color: #202124;
|
|
font-size: 12px;
|
|
vertical-alignment: center;
|
|
}
|
|
Rectangle {
|
|
x: 30px;
|
|
y: 105px;
|
|
width: 360px;
|
|
height: 190px;
|
|
background: white;
|
|
border-width: 1px;
|
|
border-color: #b9bdc3;
|
|
ScrollView {
|
|
x: 1px;
|
|
y: 1px;
|
|
width: parent.width - 2px;
|
|
height: parent.height - 2px;
|
|
VerticalLayout {
|
|
width: 340px;
|
|
padding-left: 8px;
|
|
padding-right: 8px;
|
|
padding-top: 8px;
|
|
padding-bottom: 8px;
|
|
spacing: 7px;
|
|
VerticalLayout {
|
|
width: 312px;
|
|
spacing: 10px;
|
|
for block in root.release-note-blocks: VerticalLayout {
|
|
padding-top: block.section-gap ? 10px : 0px;
|
|
StyledText { width: 312px; text: block.content; default-color: #202124; default-font-size: ImGuiFontStyle.body; }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CompactButton { x: root.compact-language ? 163px : 130px; y: 309px; width: root.compact-language ? 34px : 70px; primary: true; text: UiStrings.download; clicked => { root.open-download(); root.update-open = false; } }
|
|
CompactButton { x: root.compact-language ? 204px : 207px; y: 309px; width: root.compact-language ? 34px : 56px; text: UiStrings.later; clicked => { root.update-open = false; } }
|
|
}
|
|
}
|
|
|
|
// Portable Windows builds prompt for the optional lock-screen service.
|
|
if root.portable-service-dialog-open: Rectangle {
|
|
background: #00000052;
|
|
z: 50;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: 80px; y: 75px; width: 480px; height: 300px;
|
|
VerticalLayout {
|
|
padding: 24px; spacing: 14px;
|
|
DialogPromptText {
|
|
prompt: UiStrings.service-setup-title;
|
|
text-color: #242832;
|
|
text-size: ImGuiFontStyle.prominent;
|
|
text-weight: 600;
|
|
}
|
|
Rectangle {
|
|
background: #f7f8fa; border-color: #d9dde4; border-width: 1px; border-radius: 6px;
|
|
Text { x: 14px; y: 22px; width: parent.width - 28px; height: parent.height - 24px; text: UiStrings.service-setup-message; color: #3d434d; wrap: word-wrap; vertical-alignment: center; }
|
|
}
|
|
if root.portable-service-status != "": Text {
|
|
text: root.portable-service-status;
|
|
color: root.portable-service-succeeded ? #25874b : root.portable-service-installing ? #68707d : #b23b3b;
|
|
horizontal-alignment: center;
|
|
wrap: word-wrap;
|
|
}
|
|
if !root.portable-service-succeeded: HorizontalLayout {
|
|
height: 26px; alignment: center; spacing: 8px;
|
|
Text { text: UiStrings.do-not-remind; vertical-alignment: center; color: #4a505a; }
|
|
ToggleSwitch { checked <=> root.portable-service-do-not-remind; enabled: !root.portable-service-installing; }
|
|
}
|
|
HorizontalLayout {
|
|
height: 34px; alignment: center; spacing: 8px;
|
|
if root.portable-service-succeeded: PrimaryButton { text: UiStrings.ok; clicked => { root.acknowledge-portable-service(); } }
|
|
if !root.portable-service-succeeded: PrimaryButton {
|
|
text: UiStrings.install-service;
|
|
enabled: !root.portable-service-installing;
|
|
clicked => { root.install-portable-service(); }
|
|
}
|
|
if !root.portable-service-succeeded: SecondaryButton {
|
|
text: UiStrings.cancel;
|
|
enabled: !root.portable-service-installing;
|
|
clicked => { root.cancel-portable-service(); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if root.portable-service-suppressed-notice-open: Rectangle {
|
|
background: #00000052;
|
|
z: 51;
|
|
TouchArea { clicked => { focus-sink.focus(); } }
|
|
DialogSurface {
|
|
x: 100px; y: 130px; width: 440px; height: 190px;
|
|
VerticalLayout {
|
|
padding: 24px; spacing: 16px;
|
|
DialogPromptText {
|
|
prompt: UiStrings.notification;
|
|
text-color: #242832;
|
|
text-size: ImGuiFontStyle.prominent;
|
|
text-weight: 600;
|
|
}
|
|
DialogPromptText {
|
|
prompt: UiStrings.service-suppressed-message;
|
|
text-color: #3d434d;
|
|
}
|
|
PrimaryButton { text: UiStrings.ok; clicked => { root.acknowledge-portable-service-suppressed(); } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if root.custom-titlebar: Rectangle {
|
|
x: 0px;
|
|
y: 0px;
|
|
width: root.width;
|
|
height: root.height;
|
|
background: transparent;
|
|
border-width: 1px;
|
|
border-color: root.wayland-titlebar ? #aaa8a6 : #8b8b8b;
|
|
border-radius:
|
|
root.wayland-titlebar ? root.wayland-corner-radius : 0px;
|
|
z: 200;
|
|
}
|
|
}
|
|
}
|