-
This commit is contained in:
@@ -1,519 +1,380 @@
|
||||
import { Theme, SpacingSystem, Typography } from "../theme/theme.slint";
|
||||
import { Card } from "../components/card.slint";
|
||||
// Home Page - Dashboard with profile info and quick settings
|
||||
import { Theme, Typography, SpacingSystem } from "../theme/theme.slint";
|
||||
import { Container } from "../layouts/container.slint";
|
||||
import { Badge } from "../components/badge.slint";
|
||||
import { Button } from "../components/button.slint";
|
||||
import { Switch } from "../components/switch.slint";
|
||||
import { Label, LabelSize, LabelColor } from "../components/label.slint";
|
||||
import { Progress } from "../components/progress.slint";
|
||||
import { Profile, SettingItem } from "../types.slint";
|
||||
|
||||
export component HomePage inherits Rectangle {
|
||||
in property <Profile> current-profile;
|
||||
in property <[SettingItem]> quick-settings;
|
||||
|
||||
callback load-home-data();
|
||||
callback toggle-setting(string /* key */, bool /* value */);
|
||||
|
||||
background: Theme.colors.background;
|
||||
|
||||
export component HomePage {
|
||||
callback refresh-profile();
|
||||
callback toggle-tun-mode(bool);
|
||||
callback toggle-system-proxy(bool);
|
||||
callback open-port-settings();
|
||||
|
||||
in property <string> profile-name: "NanoCloud";
|
||||
in property <string> profile-node: "免费-日本1-Ver.7";
|
||||
in property <float> profile-usage: 1.26;
|
||||
in property <float> profile-total: 100;
|
||||
in property <string> profile-expiry: "2025-11-11";
|
||||
in property <string> profile-updated: "2025-10-12 10:05";
|
||||
|
||||
in property <string> location-ip: "47.238.198.100";
|
||||
in property <string> location-region: "日本 · 东京";
|
||||
|
||||
in property <bool> tun-mode-enabled: false;
|
||||
in property <bool> system-proxy-enabled: false;
|
||||
in property <int> proxy-port: 7890;
|
||||
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
|
||||
// Header
|
||||
Text {
|
||||
text: "Home";
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.xl;
|
||||
font-weight: Typography.weights.bold;
|
||||
// Fixed header
|
||||
Rectangle {
|
||||
height: 48px;
|
||||
background: Theme.colors.background;
|
||||
|
||||
HorizontalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
|
||||
Text {
|
||||
text: "Home";
|
||||
font-size: Typography.sizes.xl;
|
||||
font-weight: Typography.weights.bold;
|
||||
color: Theme.colors.foreground;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
|
||||
|
||||
// Scrollable content
|
||||
Flickable {
|
||||
viewport-height: content-layout.preferred-height + SpacingSystem.spacing.s4 * 2;
|
||||
|
||||
content-layout := VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
|
||||
// Profile Card
|
||||
ProfileCard {
|
||||
profile-name: root.profile-name;
|
||||
profile-node: root.profile-node;
|
||||
usage: root.profile-usage;
|
||||
total: root.profile-total;
|
||||
expiry: root.profile-expiry;
|
||||
updated: root.profile-updated;
|
||||
|
||||
refresh => {
|
||||
root.refresh-profile();
|
||||
}
|
||||
}
|
||||
|
||||
// Location Card
|
||||
LocationCard {
|
||||
ip: root.location-ip;
|
||||
region: root.location-region;
|
||||
}
|
||||
|
||||
// Settings Card
|
||||
gsCard {
|
||||
tun-enabled: root.tun-mode-enabled;
|
||||
proxy-enabled: root.system-proxy-enabled;
|
||||
port: root.proxy-port;
|
||||
|
||||
tun-toggled(enabled) => {
|
||||
root.toggle-tun-mode(enabled);
|
||||
}
|
||||
|
||||
proxy-toggled(enabled) => {
|
||||
root.toggle-system-proxy(enabled);
|
||||
}
|
||||
|
||||
port-clicked => {
|
||||
root.open-port-settings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Container {
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
|
||||
component ProfileCard {
|
||||
in property <string> profile-name: "";
|
||||
in property <string> profile-node: "";
|
||||
in property <float> usage: 0;
|
||||
in property <float> total: 100;
|
||||
in property <string> expiry: "";
|
||||
in property <string> updated: "";
|
||||
|
||||
callback refresh();
|
||||
|
||||
Card {
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
|
||||
// Header
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
padding-bottom: SpacingSystem.ss4;
|
||||
|
||||
// Icon
|
||||
Rectangle {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 12px;
|
||||
background: Theme.colors.primary.transparentize(0.9);
|
||||
|
||||
Text {
|
||||
text: "☁";
|
||||
color: Theme.colors.primary;
|
||||
font-size: 24px;
|
||||
horizontal-alignment: center;
|
||||
vertical-alignment: center;
|
||||
// Header with icon and name
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
alignment: space-between;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
|
||||
// Icon
|
||||
Rectangle {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: Theme.colors.primary;
|
||||
border-radius: SpacingSystem.radius.lg;
|
||||
|
||||
Text {
|
||||
text: "☁";
|
||||
font-size: 28px;
|
||||
horizontal-alignment: center;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
// Profile info
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: current-profile.name;
|
||||
font-size: Typography.sizes.lg;
|
||||
font-weight: Typography.weights.bold;
|
||||
color: Theme.colors.foreground;
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
Text {
|
||||
text: "🌍";
|
||||
font-size: Typography.sizes.xs;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: current-profile.type;
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
|
||||
Badge {
|
||||
text: "Vmess";
|
||||
variant: "outline";
|
||||
}
|
||||
|
||||
Badge {
|
||||
text: "UDP";
|
||||
variant: "outline";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh button
|
||||
Button {
|
||||
text: "🔄";
|
||||
variant: "ghost";
|
||||
size: "sm";
|
||||
}
|
||||
}
|
||||
|
||||
// Divider
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.colors.border;
|
||||
}
|
||||
|
||||
// Stats grid
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s6;
|
||||
|
||||
// Usage
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
horizontal-stretch: 1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
Text {
|
||||
text: "☁";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "已使用 / 总量";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: current-profile.usage;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
color: Theme.colors.foreground;
|
||||
}
|
||||
}
|
||||
|
||||
// Expire date
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
horizontal-stretch: 1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
Text {
|
||||
text: "✓";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "到期时间";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: current-profile.expire-at;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
color: Theme.colors.foreground;
|
||||
}
|
||||
}
|
||||
|
||||
// Updated date
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
horizontal-stretch: 1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
Text {
|
||||
text: "🕐";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "更新时间";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: current-profile.updated-at;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
color: Theme.colors.foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Info
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
|
||||
// Location Card (placeholder)
|
||||
Container {
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
|
||||
Text {
|
||||
text: root.profile-name;
|
||||
text: "位置信息";
|
||||
font-size: Typography.sizes.base;
|
||||
font-weight: Typography.weights.semibold;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.lg;
|
||||
font-weight: Typography.weights.bold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
Text {
|
||||
text: "🌐";
|
||||
font-size: Typography.sizes.xs;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.profile-node;
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.medium;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Badge {
|
||||
text: "Vmess";
|
||||
variant: "outline";
|
||||
}
|
||||
|
||||
Badge {
|
||||
text: "UDP";
|
||||
variant: "outline";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectan horizontal-stretch: 1;
|
||||
}
|
||||
|
||||
// Refresh button
|
||||
Button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
variant: "ghost";
|
||||
text: "↻";
|
||||
|
||||
clicked => {
|
||||
root.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.colors.border.transparentize(0.6);
|
||||
}
|
||||
|
||||
// Stats
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s6;
|
||||
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: "☁";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "已使用 / 总量";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.semibold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.usage + "GB / " + root.total + "GB";
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: "✓";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
vertical-aliter;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "到期时间";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.semibold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.expiry;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: "✓";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
vertical-: center;
|
||||
n
|
||||
Text {
|
||||
text: "更新时间";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.semibold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.updated;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component LocationCard {
|
||||
in property <string> ip: "";
|
||||
in property <string> region: "";
|
||||
|
||||
Card {
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
|
||||
// IP and Location
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s6;
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: "🌐";
|
||||
font-size: Typography.sizes.xs;
|
||||
vertical-alignment: center;
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
|
||||
Text {
|
||||
text: "🌍";
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: "当前位置: 日本 东京";
|
||||
font-size: Typography.sizes.sm;
|
||||
color: Theme.colors.foreground;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "IP: 192.168.1.1";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Quick Settings Card
|
||||
Container {
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
|
||||
Text {
|
||||
text: "IP";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
text: "快捷设置";
|
||||
font-size: Typography.sizes.base;
|
||||
font-weight: Typography.weights.semibold;
|
||||
vertical-alignment: center;
|
||||
color: Theme.colors.foreground;
|
||||
}
|
||||
|
||||
// Quick settings grid
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
|
||||
// System Proxy
|
||||
Rectangle {
|
||||
horizontal-stretch: 1;
|
||||
height: 80px;
|
||||
background: Theme.colors.muted;
|
||||
border-radius: SpacingSystem.radius.md;
|
||||
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s3;
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
alignment: center;
|
||||
|
||||
Text {
|
||||
text: "🌐";
|
||||
font-size: 24px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "系统代理";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.foreground;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
TouchArea {
|
||||
clicked => {
|
||||
root.toggle-setting("system-proxy", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TUN Mode
|
||||
Rectangle {
|
||||
horizontal-stretch: 1;
|
||||
height: 80px;
|
||||
background: Theme.colors.muted;
|
||||
border-radius: SpacingSystem.radius.md;
|
||||
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s3;
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
alignment: center;
|
||||
|
||||
Text {
|
||||
text: "🔧";
|
||||
font-size: 24px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "TUN 模式";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.foreground;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
TouchArea {
|
||||
clicked => {
|
||||
root.toggle-setting("tun-mode", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow LAN
|
||||
Rectangle {
|
||||
horizontal-stretch: 1;
|
||||
height: 80px;
|
||||
background: Theme.colors.muted;
|
||||
border-radius: SpacingSystem.radius.md;
|
||||
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s3;
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
alignment: center;
|
||||
|
||||
Text {
|
||||
text: "📡";
|
||||
font-size: 24px;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "允许局域网";
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.foreground;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
TouchArea {
|
||||
clicked => {
|
||||
root.toggle-setting("allow-lan", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.ip;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
: SpacingSystem.spacing.s1;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: "🌐";
|
||||
font-size: Typography.sizes.xs;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "所属地址";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.semibold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.region;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Latency
|
||||
VerticalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: "✓";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "延迟";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.semibold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
Row {
|
||||
LatencyItem { service: "Github"; latency: "122ms"; }
|
||||
LatencyItem { service: "Google"; latency: "45ms"; }
|
||||
LatencyItem { service: "Youtube"; latency: "67ms"; }
|
||||
LatencyItem { service: "Twitter"; latency: "89ms"; }
|
||||
}
|
||||
Row {
|
||||
LatencyItem { serviceetflix"; latency: "34ms"; }
|
||||
LatencyItem { service: "Steam"; latency: "156ms"; }
|
||||
LatencyItem { service: "Spotify"; latency: "78ms"; }
|
||||
LatencyItem { service: "Discord"; latency: "92ms"; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component LatencyItem {
|
||||
in property <string> service: "";
|
||||
in property <string> latency: "";
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Text {
|
||||
text: root.service;
|
||||
color: Theme.colors.muted-foreg;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.medium;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.latency;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.semibold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component SettingsCard {
|
||||
in property <bool> tun-enabled: false;
|
||||
in property <bool> proxy-enabled: false;
|
||||
in property <int> port: 7890;
|
||||
|
||||
callback tun-toggled(bool);
|
||||
callback proxy-toggled(bool);
|
||||
callback port-clicked();
|
||||
|
||||
Card {
|
||||
VerticalLayout {
|
||||
spacing: 0;
|
||||
|
||||
// TUN Mode
|
||||
SettingItem {
|
||||
label: "Tun 模式";
|
||||
|
||||
Switch {
|
||||
checked: root.tun-enabled;
|
||||
toggled(checked) => {
|
||||
root.tun-toggled(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.colors.border.transparentize(0.6);
|
||||
}
|
||||
|
||||
// System Proxy
|
||||
SettingItem {
|
||||
label: "系统代理";
|
||||
|
||||
Switch {
|
||||
checked: root.proxy-enabled;
|
||||
toggled(checked) => {
|
||||
root.proxy-toggled(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.colors.border.transparentize(0.6);
|
||||
}
|
||||
|
||||
// Proxy Port
|
||||
SettingItem {
|
||||
label: "代理端口";
|
||||
|
||||
But text: root.port;
|
||||
variant: "link";
|
||||
|
||||
clicked => {
|
||||
root.port-clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component SettingItem {
|
||||
in property <string> label: "";
|
||||
|
||||
height: 40px;
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
alignment: space-between;
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
Text {
|
||||
text: "✓";
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: Typography.sizes.sm;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.label;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.sm;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
@children
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user