Files
test-app-slint/ui/app-window.slint
Attilio Greco ea1c6e0614 build easy app
2026-02-01 00:00:02 +01:00

851 lines
29 KiB
Plaintext

struct HourData {
hour: string,
temp: int,
icon-type: int,
is-now: bool,
}
// ═══ API Key Dialog ═════════════════════════════════════════
export component ApiKeyDialog inherits Window {
title: "OpenWeatherMap API Key";
preferred-width: 480px;
preferred-height: 320px;
background: @linear-gradient(180deg, #1a1a2e, #0f0f1e);
in-out property <string> api-key-input: "";
callback submit-key(string);
callback skip;
VerticalLayout {
padding: 40px;
spacing: 20px;
alignment: center;
Text {
text: "Configurazione API Key";
color: white;
font-size: 24px;
font-weight: 600;
horizontal-alignment: center;
}
Text {
text: "Inserisci la tua chiave API di OpenWeatherMap\nper visualizzare i dati meteo in tempo reale.";
color: #ffffffaa;
font-size: 13px;
horizontal-alignment: center;
wrap: word-wrap;
}
Rectangle { height: 10px; }
// Input field
Rectangle {
height: 50px;
border-radius: 12px;
background: #ffffff0a;
border-width: 1px;
border-color: #ffffff22;
HorizontalLayout {
padding: 14px;
input := TextInput {
text <=> root.api-key-input;
font-size: 14px;
color: white;
horizontal-alignment: left;
single-line: true;
accepted => {
root.submit-key(self.text);
}
}
}
}
Text {
text: "Ottieni una chiave gratuita su:\nopenweathermap.org/api";
color: #66bbff;
font-size: 11px;
horizontal-alignment: center;
}
Rectangle { vertical-stretch: 1; }
HorizontalLayout {
spacing: 12px;
Rectangle {
horizontal-stretch: 1;
height: 44px;
border-radius: 12px;
background: #ffffff12;
border-width: 1px;
border-color: #ffffff1a;
Text {
text: "Salta (usa dati fake)";
color: #ffffffaa;
font-size: 13px;
vertical-alignment: center;
horizontal-alignment: center;
}
TouchArea {
clicked => {
root.skip();
}
}
}
Rectangle {
horizontal-stretch: 1;
height: 44px;
border-radius: 12px;
background: @linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
drop-shadow-blur: 12px;
drop-shadow-color: #4facfe44;
Text {
text: "Salva e Continua";
color: white;
font-size: 13px;
font-weight: 600;
vertical-alignment: center;
horizontal-alignment: center;
}
TouchArea {
clicked => {
root.submit-key(root.api-key-input);
}
}
}
}
}
}
// ─── Decorative Cloud ────────────────────────────────────────
component CloudShape inherits Rectangle {
in property <float> tick: 0;
in property <float> speed: 0.3;
in property <float> phase: 0;
in property <float> base-opacity: 0.25;
background: transparent;
opacity: base-opacity;
property <length> bob: Math.sin((tick * speed * 0.7 + phase) * 1rad) * 6px;
Rectangle {
x: parent.width * 0.15; y: parent.height * 0.35 + parent.bob;
width: parent.width * 0.7; height: parent.height * 0.55;
border-radius: self.height / 2; background: white;
}
Rectangle {
x: parent.width * 0.30; y: parent.height * 0.05 + parent.bob;
width: parent.width * 0.4; height: parent.height * 0.55;
border-radius: self.height / 2; background: white;
}
Rectangle {
x: parent.width * 0.05; y: parent.height * 0.40 + parent.bob;
width: parent.width * 0.32; height: parent.height * 0.42;
border-radius: self.height / 2; background: white;
}
Rectangle {
x: parent.width * 0.58; y: parent.height * 0.28 + parent.bob;
width: parent.width * 0.32; height: parent.height * 0.42;
border-radius: self.height / 2; background: white;
}
}
// ─── Rain Drop ───────────────────────────────────────────────
component RainDrop inherits Rectangle {
in property <float> tick;
in property <float> speed: 3.0;
in property <float> phase: 0;
width: 2px; height: 18px;
border-radius: 1px;
background: @linear-gradient(180deg, #aaddff00, #aaddffaa);
opacity: Math.max(0, Math.sin((tick * speed + phase) * 1rad)) * 0.6;
}
// ═══ Weather Display Icons (drawn with shapes) ══════════════
// ─── Sun Display ─────────────────────────────────────────────
component SunDisplay inherits Rectangle {
in property <float> tick;
background: transparent;
// Pulsing outer ring 1
Rectangle {
width: parent.width * 0.92; height: parent.height * 0.92;
x: parent.width * 0.04; y: parent.height * 0.04;
border-radius: self.width / 2;
background: transparent;
border-width: 1.5px; border-color: #FFD70022;
opacity: 0.4 + Math.sin(tick * 1.5rad) * 0.4;
}
// Pulsing outer ring 2 (counter-phase)
Rectangle {
width: parent.width * 0.82; height: parent.height * 0.82;
x: parent.width * 0.09; y: parent.height * 0.09;
border-radius: self.width / 2;
background: transparent;
border-width: 1.5px; border-color: #FFD70033;
opacity: 0.5 + Math.sin((tick * 2.0 + 1.0) * 1rad) * 0.35;
}
// Pulsing outer ring 3
Rectangle {
width: parent.width * 0.72; height: parent.height * 0.72;
x: parent.width * 0.14; y: parent.height * 0.14;
border-radius: self.width / 2;
background: transparent;
border-width: 1px; border-color: #FFD70044;
opacity: 0.4 + Math.sin((tick * 2.5 + 2.0) * 1rad) * 0.4;
}
// Warm glow halo
Rectangle {
width: parent.width * 0.65; height: parent.height * 0.65;
x: parent.width * 0.175; y: parent.height * 0.175;
border-radius: self.width / 2;
background: #FFD70018;
drop-shadow-blur: 15px; drop-shadow-color: #FFD70033;
opacity: 0.6 + Math.sin(tick * 1.8rad) * 0.3;
}
// Main circle
Rectangle {
width: parent.width * 0.50; height: parent.height * 0.50;
x: parent.width * 0.25; y: parent.height * 0.25;
border-radius: self.width / 2;
background: @radial-gradient(circle, #FFE066 0%, #FFD700 50%, #FFA500 100%);
drop-shadow-blur: 22px; drop-shadow-color: #FFD70088;
}
// Bright core
Rectangle {
width: parent.width * 0.22; height: parent.height * 0.22;
x: parent.width * 0.39; y: parent.height * 0.39;
border-radius: self.width / 2;
background: #FFF8E1;
opacity: 0.55 + Math.sin(tick * 4rad) * 0.3;
}
}
// ─── Cloud Display ───────────────────────────────────────────
component CloudDisplay inherits Rectangle {
in property <float> tick;
background: transparent;
property <length> bob: Math.sin(tick * 0.8rad) * 3px;
Rectangle {
x: parent.width * 0.10; y: parent.height * 0.45 + parent.bob;
width: parent.width * 0.80; height: parent.height * 0.42;
border-radius: self.height / 2;
background: @linear-gradient(180deg, #ffffff, #e0e0ee);
drop-shadow-blur: 12px; drop-shadow-color: #00000015;
}
Rectangle {
x: parent.width * 0.14; y: parent.height * 0.28 + parent.bob;
width: parent.width * 0.34; height: parent.height * 0.42;
border-radius: self.height / 2; background: #ffffff;
}
Rectangle {
x: parent.width * 0.30; y: parent.height * 0.08 + parent.bob;
width: parent.width * 0.40; height: parent.height * 0.52;
border-radius: self.height / 2; background: #ffffff;
}
Rectangle {
x: parent.width * 0.52; y: parent.height * 0.22 + parent.bob;
width: parent.width * 0.34; height: parent.height * 0.42;
border-radius: self.height / 2; background: #fafaff;
}
}
// ─── Rain Display ────────────────────────────────────────────
component RainDisplay inherits Rectangle {
in property <float> tick;
background: transparent;
property <length> bob: Math.sin(tick * 0.6rad) * 2px;
// Dark cloud
Rectangle {
x: parent.width * 0.10; y: parent.height * 0.10 + bob;
width: parent.width * 0.80; height: parent.height * 0.32;
border-radius: self.height / 2; background: #8899aa;
}
Rectangle {
x: parent.width * 0.20; y: parent.height * 0.0 + bob;
width: parent.width * 0.32; height: parent.height * 0.30;
border-radius: self.height / 2; background: #8899aa;
}
Rectangle {
x: parent.width * 0.42; y: parent.height * -0.04 + bob;
width: parent.width * 0.34; height: parent.height * 0.32;
border-radius: self.height / 2; background: #8899aa;
}
// Animated drops
Rectangle {
x: parent.width * 0.22; y: parent.height * 0.50;
width: 2px; height: 14px; border-radius: 1px; background: #aaddff;
opacity: Math.max(0.0, Math.sin((tick * 3.0) * 1rad)) * 0.7;
}
Rectangle {
x: parent.width * 0.38; y: parent.height * 0.55;
width: 2px; height: 12px; border-radius: 1px; background: #aaddff;
opacity: Math.max(0.0, Math.sin((tick * 3.2 + 1.5) * 1rad)) * 0.7;
}
Rectangle {
x: parent.width * 0.54; y: parent.height * 0.48;
width: 2px; height: 14px; border-radius: 1px; background: #aaddff;
opacity: Math.max(0.0, Math.sin((tick * 2.8 + 3.0) * 1rad)) * 0.7;
}
Rectangle {
x: parent.width * 0.70; y: parent.height * 0.53;
width: 2px; height: 12px; border-radius: 1px; background: #aaddff;
opacity: Math.max(0.0, Math.sin((tick * 3.5 + 2.0) * 1rad)) * 0.6;
}
Rectangle {
x: parent.width * 0.30; y: parent.height * 0.68;
width: 2px; height: 10px; border-radius: 1px; background: #aaddff;
opacity: Math.max(0.0, Math.sin((tick * 3.1 + 4.0) * 1rad)) * 0.5;
}
Rectangle {
x: parent.width * 0.62; y: parent.height * 0.70;
width: 2px; height: 10px; border-radius: 1px; background: #aaddff;
opacity: Math.max(0.0, Math.sin((tick * 2.9 + 5.5) * 1rad)) * 0.5;
}
}
// ═══ UI Components ══════════════════════════════════════════
// ─── Forecast Card (glassmorphism) ──────────────────────────
component ForecastCard inherits Rectangle {
in property <string> hour;
in property <int> temp;
in property <int> icon-type;
in property <bool> is-now: false;
in property <float> tick;
width: 64px;
height: 110px;
border-radius: 18px;
background: is-now ? #ffffff22 : #ffffff0c;
border-width: 1px;
border-color: is-now ? #ffffff30 : #ffffff0a;
drop-shadow-blur: is-now ? 12px : 0px;
drop-shadow-color: #ffffff11;
animate background { duration: 400ms; easing: ease-in-out; }
animate border-color { duration: 400ms; easing: ease-in-out; }
animate drop-shadow-blur { duration: 400ms; easing: ease-in-out; }
VerticalLayout {
alignment: center;
spacing: 6px;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 6px;
padding-right: 6px;
Text {
text: hour;
color: is-now ? #ffffffee : #ffffff88;
font-size: 11px;
font-weight: is-now ? 600 : 400;
horizontal-alignment: center;
}
// Mini icon area
Rectangle {
height: 30px;
if icon-type == 0: Rectangle {
width: 20px; height: 20px;
x: (parent.width - self.width) / 2; y: 5px;
border-radius: 10px;
background: @radial-gradient(circle, #FFE066 0%, #FFA500 100%);
drop-shadow-blur: 6px; drop-shadow-color: #FFD70055;
}
if icon-type == 1: Rectangle {
x: (parent.width - 28px) / 2; y: 4px;
width: 28px; height: 18px; background: transparent;
Rectangle {
x: 2px; y: 8px; width: 24px; height: 10px;
border-radius: 5px; background: #ffffffbb;
}
Rectangle {
x: 6px; y: 2px; width: 14px; height: 12px;
border-radius: 6px; background: #ffffffbb;
}
}
if icon-type == 2: Rectangle {
x: (parent.width - 28px) / 2; y: 2px;
width: 28px; height: 24px; background: transparent;
Rectangle {
x: 2px; y: 4px; width: 24px; height: 10px;
border-radius: 5px; background: #8899aacc;
}
Rectangle {
x: 6px; y: 0px; width: 14px; height: 10px;
border-radius: 5px; background: #8899aacc;
}
Rectangle {
x: 8px; y: 16px; width: 1.5px; height: 6px;
border-radius: 0.75px; background: #aaddff88;
}
Rectangle {
x: 16px; y: 17px; width: 1.5px; height: 5px;
border-radius: 0.75px; background: #aaddff88;
}
}
}
Text {
text: "\{temp}°";
color: white;
font-size: 15px;
font-weight: 700;
horizontal-alignment: center;
}
}
}
// ─── Info Pill (glassmorphism + accent) ─────────────────────
component InfoPill inherits Rectangle {
in property <string> label;
in property <string> value;
in property <color> accent: #66bbff;
horizontal-stretch: 1;
height: 72px;
border-radius: 18px;
background: #ffffff0c;
border-width: 1px;
border-color: #ffffff0a;
VerticalLayout {
alignment: center;
spacing: 4px;
padding: 10px;
// Accent dot
HorizontalLayout {
alignment: center;
Rectangle {
width: 6px; height: 6px;
border-radius: 3px;
background: accent;
drop-shadow-blur: 4px; drop-shadow-color: accent;
}
}
Text {
text: value;
color: white;
font-size: 18px;
font-weight: 600;
horizontal-alignment: center;
}
Text {
text: label;
color: #ffffff55;
font-size: 9px;
horizontal-alignment: center;
letter-spacing: 1.2px;
}
}
}
// ─── Premium Slider ─────────────────────────────────────────
component PremiumSlider inherits Rectangle {
in-out property <float> value: 12;
in property <float> minimum: 0;
in property <float> maximum: 24;
height: 44px;
background: transparent;
property <float> ratio: Math.clamp((value - minimum) / (maximum - minimum), 0, 1);
// Track
Rectangle {
y: (parent.height - 4px) / 2;
width: parent.width; height: 4px;
border-radius: 2px;
background: #ffffff12;
}
// Fill
Rectangle {
y: (parent.height - 4px) / 2;
width: parent.width * ratio; height: 4px;
border-radius: 2px;
background: @linear-gradient(90deg, #ffffff20, #ffffff88);
}
// Thumb glow
Rectangle {
x: (parent.width - 28px) * ratio;
y: (parent.height - 28px) / 2;
width: 28px; height: 28px;
border-radius: 14px;
background: #ffffff08;
drop-shadow-blur: 16px; drop-shadow-color: #ffffff22;
}
// Thumb
Rectangle {
x: (parent.width - 22px) * ratio;
y: (parent.height - 22px) / 2;
width: 22px; height: 22px;
border-radius: 11px;
background: @radial-gradient(circle, #ffffff 0%, #e8e8f0 100%);
drop-shadow-blur: 8px; drop-shadow-color: #00000022;
Rectangle {
width: 6px; height: 6px;
x: 8px; y: 8px;
border-radius: 3px;
background: #888899;
}
}
// Touch
TouchArea {
clicked => {
root.value = root.minimum + (root.maximum - root.minimum) * Math.clamp(self.mouse-x / root.width, 0, 1);
}
moved => {
if self.pressed {
root.value = root.minimum + (root.maximum - root.minimum) * Math.clamp(self.mouse-x / root.width, 0, 1);
}
}
}
}
// ─── Separator ──────────────────────────────────────────────
component Separator inherits HorizontalLayout {
alignment: center;
Rectangle {
width: 40px; height: 1px;
border-radius: 0.5px;
background: @linear-gradient(90deg, #ffffff00, #ffffff22, #ffffff00);
}
}
// ═════════════════════════════════════════════════════════════
// Main Window
// ═════════════════════════════════════════════════════════════
export component MainWindow inherits Window {
title: "Meteo Milano";
preferred-width: 420px;
preferred-height: 780px;
background: black;
in-out property <float> tick: 0;
in-out property <float> time-of-day: 14.0;
in-out property <color> sky-top: #1e90ff;
in-out property <color> sky-bottom: #87CEEB;
in-out property <int> current-temp: 22;
in-out property <string> weather-desc: "Parzialmente Nuvoloso";
in-out property <string> humidity: "65%";
in-out property <string> wind: "12 km/h";
in-out property <string> feels-like: "20°";
in-out property <int> weather-type: 1;
in-out property <float> sun-y-factor: 0.3;
in-out property <[HourData]> forecast: [];
in-out property <bool> show-rain: false;
callback open-settings;
// ── Background ──
Rectangle {
width: 100%; height: 100%;
background: @linear-gradient(180deg, sky-top, sky-bottom);
}
// ── Sky Sun ──
Rectangle {
property <length> s: 90px;
x: root.width * 0.70;
y: root.height * root.sun-y-factor;
width: s; height: s;
border-radius: s / 2;
background: @radial-gradient(circle, #FFD700 0%, #FF8C0060 60%, #FF450000 100%);
opacity: weather-type == 0 ? 0.95 : weather-type == 1 ? 0.35 : 0.0;
drop-shadow-blur: 40px + Math.sin(tick * 2rad) * 10px;
drop-shadow-color: #FFD70055;
animate opacity { duration: 600ms; easing: ease-in-out; }
Rectangle {
width: parent.width * 0.35; height: parent.height * 0.35;
x: parent.width * 0.325; y: parent.height * 0.325;
border-radius: self.width / 2;
background: white;
opacity: 0.35 + Math.sin(tick * 3rad) * 0.2;
}
}
// ── Moon ──
Rectangle {
property <length> m: 48px;
x: root.width * 0.76; y: root.height * 0.10;
width: m; height: m;
border-radius: m / 2;
background: #E8E8D0;
opacity: time-of-day < 5.5 || time-of-day > 20.5 ? 0.85 : 0.0;
drop-shadow-blur: 18px; drop-shadow-color: #E8E8D044;
animate opacity { duration: 800ms; easing: ease-in-out; }
Rectangle {
width: parent.width * 0.7; height: parent.height * 0.7;
x: parent.width * 0.38; y: parent.height * 0.08;
border-radius: self.width / 2;
background: sky-top;
}
}
// ── Floating clouds ──
CloudShape {
width: 150px; height: 75px;
x: root.width * 0.02 + Math.sin((tick * 0.2) * 1rad) * 25px;
y: root.height * 0.05;
tick: root.tick; speed: 0.3; phase: 0; base-opacity: 0.20;
}
CloudShape {
width: 115px; height: 58px;
x: root.width * 0.52 + Math.sin((tick * 0.15 + 2.0) * 1rad) * 20px;
y: root.height * 0.12;
tick: root.tick; speed: 0.25; phase: 2.0; base-opacity: 0.16;
}
CloudShape {
width: 100px; height: 50px;
x: root.width * 0.25 + Math.sin((tick * 0.18 + 4.5) * 1rad) * 30px;
y: root.height * 0.19;
tick: root.tick; speed: 0.35; phase: 4.5; base-opacity: 0.13;
}
// ── Rain ──
if show-rain: Rectangle {
width: 100%; height: 100%;
RainDrop { x: root.width * 0.06; y: root.height * 0.28; tick: root.tick; speed: 3.2; phase: 0.0; }
RainDrop { x: root.width * 0.13; y: root.height * 0.40; tick: root.tick; speed: 2.8; phase: 0.7; }
RainDrop { x: root.width * 0.20; y: root.height * 0.34; tick: root.tick; speed: 3.5; phase: 1.4; }
RainDrop { x: root.width * 0.28; y: root.height * 0.48; tick: root.tick; speed: 3.0; phase: 2.1; }
RainDrop { x: root.width * 0.35; y: root.height * 0.37; tick: root.tick; speed: 3.3; phase: 2.8; }
RainDrop { x: root.width * 0.42; y: root.height * 0.44; tick: root.tick; speed: 2.9; phase: 3.5; }
RainDrop { x: root.width * 0.50; y: root.height * 0.31; tick: root.tick; speed: 3.4; phase: 4.2; }
RainDrop { x: root.width * 0.57; y: root.height * 0.46; tick: root.tick; speed: 3.1; phase: 4.9; }
RainDrop { x: root.width * 0.64; y: root.height * 0.39; tick: root.tick; speed: 2.7; phase: 5.6; }
RainDrop { x: root.width * 0.72; y: root.height * 0.50; tick: root.tick; speed: 3.6; phase: 6.3; }
RainDrop { x: root.width * 0.80; y: root.height * 0.35; tick: root.tick; speed: 3.0; phase: 7.0; }
RainDrop { x: root.width * 0.88; y: root.height * 0.42; tick: root.tick; speed: 3.3; phase: 7.7; }
RainDrop { x: root.width * 0.09; y: root.height * 0.54; tick: root.tick; speed: 2.8; phase: 8.4; }
RainDrop { x: root.width * 0.38; y: root.height * 0.57; tick: root.tick; speed: 3.1; phase: 9.8; }
RainDrop { x: root.width * 0.68; y: root.height * 0.55; tick: root.tick; speed: 3.4; phase: 11.2; }
RainDrop { x: root.width * 0.84; y: root.height * 0.60; tick: root.tick; speed: 3.2; phase: 11.9; }
RainDrop { x: root.width * 0.17; y: root.height * 0.63; tick: root.tick; speed: 2.6; phase: 1.1; }
RainDrop { x: root.width * 0.46; y: root.height * 0.66; tick: root.tick; speed: 3.7; phase: 3.3; }
RainDrop { x: root.width * 0.76; y: root.height * 0.62; tick: root.tick; speed: 2.9; phase: 5.0; }
RainDrop { x: root.width * 0.93; y: root.height * 0.52; tick: root.tick; speed: 3.1; phase: 8.8; }
}
// ── Main content ──
VerticalLayout {
padding-top: 48px;
padding-bottom: 24px;
padding-left: 30px;
padding-right: 30px;
spacing: 2px;
// City name
Text {
text: "MILANO";
color: white;
font-size: 16px;
font-weight: 600;
letter-spacing: 6px;
horizontal-alignment: center;
}
Text {
text: "Sabato 31 Gennaio";
color: #ffffff77;
font-size: 12px;
font-weight: 400;
horizontal-alignment: center;
}
Rectangle { vertical-stretch: 1; }
// Central weather icon
HorizontalLayout {
alignment: center;
if weather-type == 0: SunDisplay {
width: 100px; height: 100px;
tick: root.tick;
}
if weather-type == 1: CloudDisplay {
width: 110px; height: 70px;
tick: root.tick;
}
if weather-type == 2: RainDisplay {
width: 110px; height: 80px;
tick: root.tick;
}
}
Rectangle { height: 8px; }
// Temperature
Text {
text: "\{current-temp}°";
color: white;
font-size: 92px;
font-weight: 200;
horizontal-alignment: center;
}
Text {
text: weather-desc;
color: #ffffffbb;
font-size: 16px;
font-weight: 400;
horizontal-alignment: center;
}
Rectangle { height: 16px; }
Separator { }
Rectangle { height: 16px; }
// Info pills
HorizontalLayout {
spacing: 10px;
InfoPill { label: "UMIDITA"; value: humidity; accent: #66bbff; }
InfoPill { label: "VENTO"; value: wind; accent: #88ddaa; }
InfoPill { label: "PERCEPITA"; value: feels-like; accent: #ffaa66; }
}
Rectangle { height: 20px; }
// Forecast section
Text {
text: "PREVISIONI ORARIE";
color: #ffffff55;
font-size: 10px;
font-weight: 500;
letter-spacing: 2px;
}
Rectangle { height: 8px; }
HorizontalLayout {
spacing: 7px;
for data in forecast: ForecastCard {
hour: data.hour;
temp: data.temp;
icon-type: data.icon-type;
is-now: data.is-now;
tick: root.tick;
}
}
Rectangle { vertical-stretch: 2; }
// Time control
Text {
text: "Scorri per cambiare l'ora";
color: #ffffff33;
font-size: 10px;
font-weight: 400;
horizontal-alignment: center;
}
Rectangle { height: 4px; }
PremiumSlider {
minimum: 0;
maximum: 23.9;
value <=> root.time-of-day;
}
HorizontalLayout {
Text { text: "00:00"; color: #ffffff33; font-size: 9px; font-weight: 400; }
Rectangle { horizontal-stretch: 1; }
Text { text: "12:00"; color: #ffffff33; font-size: 9px; font-weight: 400; horizontal-alignment: center; }
Rectangle { horizontal-stretch: 1; }
Text { text: "24:00"; color: #ffffff33; font-size: 9px; font-weight: 400; horizontal-alignment: right; }
}
}
// ── Settings button (top-right) ──
Rectangle {
x: root.width - 52px;
y: 12px;
width: 40px;
height: 40px;
border-radius: 20px;
background: #ffffff12;
border-width: 1px;
border-color: #ffffff1a;
// Gear icon (simplified)
Rectangle {
width: 20px;
height: 20px;
x: 10px;
y: 10px;
Rectangle {
width: 12px; height: 12px;
x: 4px; y: 4px;
border-radius: 6px;
background: transparent;
border-width: 2px;
border-color: #ffffffaa;
}
Rectangle {
width: 3px; height: 6px;
x: 8.5px; y: 0px;
border-radius: 1.5px;
background: #ffffffaa;
}
Rectangle {
width: 3px; height: 6px;
x: 8.5px; y: 14px;
border-radius: 1.5px;
background: #ffffffaa;
}
Rectangle {
width: 6px; height: 3px;
x: 0px; y: 8.5px;
border-radius: 1.5px;
background: #ffffffaa;
}
Rectangle {
width: 6px; height: 3px;
x: 14px; y: 8.5px;
border-radius: 1.5px;
background: #ffffffaa;
}
}
TouchArea {
clicked => {
root.open-settings();
}
}
}
}