-
This commit is contained in:
452
ui/app.slint
452
ui/app.slint
@@ -1,210 +1,270 @@
|
||||
import { Theme } from "./theme/theme.slint";
|
||||
import { AppSidebar, NavItem } from "./components/app-sidebar.slint";
|
||||
import { StatusState } from "./components/status-indicator.slint";
|
||||
import { HomePage } from "./pages/home.slint";
|
||||
import { ProfilesPage, ProfileData } from "./pages/profiles.slint";
|
||||
import { ProxiesPage, ProxyGroup, ProxyNode } from "./pages/proxies.slint";
|
||||
import { LogsPage, LogEntry } from "./pages/logs.slint";
|
||||
import { ConnectionsPage, Connection } from "./pages/connections.slint";
|
||||
import { SettingsPage } from "./pages/settings.slint";
|
||||
// Main Application - Proxy Management Tool
|
||||
import { Theme, Typography, SpacingSystem } from "theme/theme.slint";
|
||||
import { Button } from "components/button.slint";
|
||||
import { Sidebar, NavItem } from "components/sidebar.slint";
|
||||
import { ToastContainer, ToastMessage } from "components/toast.slint";
|
||||
import { Profile, ProxyGroup, Connection, LogEntry, SettingItem } from "types.slint";
|
||||
import { ConnectionsPage } from "pages/connections.slint";
|
||||
import { LogsPage } from "pages/logs.slint";
|
||||
import { SettingsPage } from "pages/settings.slint";
|
||||
import { ProfilesPage } from "pages/profiles.slint";
|
||||
import { HomePage } from "pages/home.slint";
|
||||
import { ProxiesPage } from "pages/proxies.slint";
|
||||
|
||||
export component App inherits Window {
|
||||
title: "Clash Manager";
|
||||
preferred-width: 1200px;
|
||||
preferred-height: 800px;
|
||||
title: "Proxy Manager";
|
||||
background: Theme.colors.background;
|
||||
|
||||
// Navigation state
|
||||
in-out property <int> current-page: 0;
|
||||
|
||||
// Mihomo status
|
||||
in-out property <StatusState> mihomo-status: StatusState.stopped;
|
||||
in-out property <bool> mihomo-loading: false;
|
||||
|
||||
// Home page data
|
||||
in-out property <string> profile-name: "NanoCloud";
|
||||
in-out property <string> profile-node: "Free-Japan1-Ver.7";
|
||||
in-out property <float> profile-usage: 1.26;
|
||||
in-out property <float> profile-total: 100;
|
||||
in-out property <string> profile-expiry: "2025-11-11";
|
||||
in-out property <string> profile-updated: "2025-10-12 10:05";
|
||||
in-out property <string> location-ip: "47.238.198.100";
|
||||
in-out property <string> location-region: "Japan · Tokyo";
|
||||
in-out property <bool> tun-mode-enabled: false;
|
||||
in-out property <bool> system-proxy-enabled: false;
|
||||
in-out property <int> proxy-port: 7890;
|
||||
|
||||
// Profiles page data
|
||||
in-out property <[ProfileData]> profiles: [];
|
||||
in-out property <string> selected-profile-id: "";
|
||||
|
||||
// Proxies page data
|
||||
|
||||
// Window size settings
|
||||
min-width: 800px;
|
||||
min-height: 600px;
|
||||
preferred-width: 1000px;
|
||||
preferred-height: 700px;
|
||||
|
||||
// ===== Application State =====
|
||||
in-out property <string> current-view: "home";
|
||||
in-out property <bool> sidebar-collapsed: false;
|
||||
|
||||
// ===== Data State =====
|
||||
in-out property <Profile> current-profile;
|
||||
in-out property <[Profile]> profiles: [];
|
||||
in-out property <[ProxyGroup]> proxy-groups: [];
|
||||
in-out property <int> proxy-mode: 0;
|
||||
in-out property <string> selected-proxy: "";
|
||||
|
||||
// Logs page data
|
||||
in-out property <string> proxy-mode: "rule"; // "rule" | "global" | "direct"
|
||||
in-out property <[Connection]> connections: [];
|
||||
in-out property <[LogEntry]> mihomo-logs: [];
|
||||
in-out property <[LogEntry]> app-logs: [];
|
||||
in-out property <int> log-tab: 0;
|
||||
|
||||
// Connections page data
|
||||
in-out property <[Connection]> connections: [];
|
||||
|
||||
// Settings page data
|
||||
in-out property <bool> auto-start: false;
|
||||
in-out property <bool> silent-start: false;
|
||||
in-out property <bool> clash-core: false;
|
||||
in-out property <bool> allow-lan: false;
|
||||
in-out property <bool> ipv6: false;
|
||||
in-out property <bool> unified-delay: false;
|
||||
in-out property <int> log-level-index: 1;
|
||||
in-out property <string> app-dir: "C:/Program Files/Clash";
|
||||
in-out property <string> config-dir: "C:/Users/User/.config/clash";
|
||||
in-out property <string> core-dir: "C:/Program Files/Clash/core";
|
||||
in-out property <string> app-version: "1.0.0";
|
||||
|
||||
// Callbacks
|
||||
callback navigate(int);
|
||||
callback toggle-mihomo();
|
||||
callback refresh-profile();
|
||||
callback toggle-tun-mode(bool);
|
||||
callback toggle-system-proxy(bool);
|
||||
callback open-port-settings();
|
||||
callback add-profile();
|
||||
callback refresh-all-profiles();
|
||||
callback select-profile(string);
|
||||
callback edit-profile(string);
|
||||
callback delete-profile(string);
|
||||
callback refresh-single-profile(string);
|
||||
callback proxy-mode-changed(int);
|
||||
callback proxy-group-toggled(int, bool);
|
||||
callback proxy-selected(string);
|
||||
callback log-tab-changed(int);
|
||||
callback toggle-auto-start(bool);
|
||||
callback toggle-silent-start(bool);
|
||||
callback toggle-clash-core(bool);
|
||||
callback toggle-allow-lan(bool);
|
||||
callback toggle-ipv6(bool);
|
||||
callback toggle-unified-delay(bool);
|
||||
callback log-level-changed(int);
|
||||
callback open-tun-config();
|
||||
callback open-directory(string);
|
||||
|
||||
HorizontalLayout {
|
||||
// Sidebar
|
||||
AppSidebar {
|
||||
nav-items: [
|
||||
{ title: "Home", icon: "🏠" },
|
||||
{ title: "Proxies", icon: "🌐" },
|
||||
{ title: "Profiles", icon: "📋" },
|
||||
{ title: "Connections", icon: "🔗" },
|
||||
{ title: "Logs", icon: "📝" },
|
||||
{ title: "Settings", icon: "⚙" },
|
||||
];
|
||||
current-page: root.current-page;
|
||||
mihomo-status: root.mihomo-status;
|
||||
mihomo-loading: root.mihomo-loading;
|
||||
|
||||
navigate(index) => {
|
||||
root.current-page = index;
|
||||
root.navigate(index);
|
||||
in-out property <[SettingItem]> app-settings: [];
|
||||
in-out property <[SettingItem]> clash-settings: [];
|
||||
in-out property <[ToastMessage]> toasts: [];
|
||||
|
||||
// ===== Callbacks (Rust Implementation) =====
|
||||
// Data loading
|
||||
callback load-profiles();
|
||||
callback load-proxy-groups(string /* mode: rule/global/direct */);
|
||||
callback load-connections();
|
||||
callback load-logs(string /* type: mihomo/app */);
|
||||
callback load-settings();
|
||||
|
||||
// User actions
|
||||
callback select-profile(string /* profile-id */);
|
||||
callback select-proxy(string /* group-name */, string /* node-name */);
|
||||
callback test-proxy-delay(string /* node-name */);
|
||||
callback toggle-setting(string /* key */, bool /* value */);
|
||||
callback update-profile(string /* profile-id */);
|
||||
callback delete-profile(string /* profile-id */);
|
||||
callback add-profile(string /* url */);
|
||||
|
||||
// Toast notification
|
||||
callback show-toast(string /* message */, string /* type */);
|
||||
|
||||
// Sidebar navigation items
|
||||
property <[NavItem]> nav-items: [
|
||||
{ icon: "🏠", label: "Home", active: current-view == "home" },
|
||||
{ icon: "🌍", label: "Proxies", active: current-view == "proxies" },
|
||||
{ icon: "📋", label: "Profiles", active: current-view == "profiles" },
|
||||
{ icon: "🔗", label: "Connections", active: current-view == "connections" },
|
||||
{ icon: "📝", label: "Logs", active: current-view == "logs" },
|
||||
{ icon: "⚙", label: "Settings", active: current-view == "settings" },
|
||||
];
|
||||
|
||||
// Main layout
|
||||
VerticalLayout {
|
||||
// Top bar
|
||||
Rectangle {
|
||||
height: 60px;
|
||||
background: Theme.colors.card;
|
||||
|
||||
// Bottom border
|
||||
Rectangle {
|
||||
y: parent.height - 1px;
|
||||
height: 1px;
|
||||
background: Theme.colors.border;
|
||||
}
|
||||
|
||||
toggle-mihomo => {
|
||||
root.toggle-mihomo();
|
||||
|
||||
HorizontalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
alignment: space-between;
|
||||
|
||||
// Left: Title
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
alignment: start;
|
||||
|
||||
Text {
|
||||
text: "🔐 Proxy Manager";
|
||||
font-size: Typography.sizes.xl;
|
||||
font-weight: Typography.weights.bold;
|
||||
color: Theme.colors.foreground;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
// Right: Theme toggle button
|
||||
Button {
|
||||
text: Theme.is-dark-mode ? "☀ Light" : "🌙 Dark";
|
||||
variant: "outline";
|
||||
size: "sm";
|
||||
|
||||
clicked => {
|
||||
Theme.toggle-theme();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Content Area
|
||||
Rectangle {
|
||||
background: Theme.colors.background;
|
||||
|
||||
// Home Page
|
||||
if root.current-page == 0: HomePage {
|
||||
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;
|
||||
location-ip: root.location-ip;
|
||||
location-region: root.location-region;
|
||||
tun-mode-enabled: root.tun-mode-enabled;
|
||||
system-proxy-enabled: root.system-proxy-enabled;
|
||||
proxy-port: root.proxy-port;
|
||||
|
||||
refresh-profile => { root.refresh-profile(); }
|
||||
toggle-tun-mode(enabled) => { root.toggle-tun-mode(enabled); }
|
||||
toggle-system-proxy(enabled) => { root.toggle-system-proxy(enabled); }
|
||||
open-port-settings => { root.open-port-settings(); }
|
||||
|
||||
// Main content area
|
||||
HorizontalLayout {
|
||||
// Sidebar
|
||||
Sidebar {
|
||||
items: nav-items;
|
||||
collapsed: sidebar-collapsed;
|
||||
|
||||
item-clicked(index) => {
|
||||
if index == 0 {
|
||||
current-view = "home";
|
||||
root.load-profiles();
|
||||
root.load-settings();
|
||||
}
|
||||
else if index == 1 {
|
||||
current-view = "proxies";
|
||||
root.load-proxy-groups(proxy-mode);
|
||||
}
|
||||
else if index == 2 {
|
||||
current-view = "profiles";
|
||||
root.load-profiles();
|
||||
}
|
||||
else if index == 3 {
|
||||
current-view = "connections";
|
||||
root.load-connections();
|
||||
}
|
||||
else if index == 4 {
|
||||
current-view = "logs";
|
||||
root.load-logs("mihomo");
|
||||
}
|
||||
else if index == 5 {
|
||||
current-view = "settings";
|
||||
root.load-settings();
|
||||
}
|
||||
}
|
||||
|
||||
toggle-collapsed => {
|
||||
sidebar-collapsed = !sidebar-collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
// Proxies Page
|
||||
if root.current-page == 1: ProxiesPage {
|
||||
proxy-groups: root.proxy-groups;
|
||||
current-mode: root.proxy-mode;
|
||||
selected-proxy: root.selected-proxy;
|
||||
|
||||
mode-changed(mode) => { root.proxy-mode-changed(mode); }
|
||||
group-toggled(index, expanded) => { root.proxy-group-toggled(index, expanded); }
|
||||
proxy-selected(name) => { root.proxy-selected(name); }
|
||||
|
||||
// Main content area - Pages
|
||||
Rectangle {
|
||||
background: Theme.colors.background;
|
||||
horizontal-stretch: 1;
|
||||
vertical-stretch: 1;
|
||||
|
||||
// Home page
|
||||
if current-view == "home": HomePage {
|
||||
current-profile: root.current-profile;
|
||||
quick-settings: root.app-settings;
|
||||
|
||||
load-home-data => {
|
||||
root.load-profiles();
|
||||
root.load-settings();
|
||||
}
|
||||
|
||||
toggle-setting(key, value) => {
|
||||
root.toggle-setting(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Proxies page
|
||||
if current-view == "proxies": ProxiesPage {
|
||||
proxy-groups: root.proxy-groups;
|
||||
proxy-mode: root.proxy-mode;
|
||||
|
||||
load-proxy-groups(mode) => {
|
||||
root.proxy-mode = mode;
|
||||
root.load-proxy-groups(mode);
|
||||
}
|
||||
|
||||
select-proxy(group-name, node-name) => {
|
||||
root.select-proxy(group-name, node-name);
|
||||
}
|
||||
|
||||
test-proxy-delay(node-name) => {
|
||||
root.test-proxy-delay(node-name);
|
||||
}
|
||||
}
|
||||
|
||||
// Profiles page
|
||||
if current-view == "profiles": ProfilesPage {
|
||||
profiles: root.profiles;
|
||||
|
||||
load-profiles => {
|
||||
root.load-profiles();
|
||||
}
|
||||
|
||||
select-profile(profile-id) => {
|
||||
root.select-profile(profile-id);
|
||||
}
|
||||
|
||||
update-profile(profile-id) => {
|
||||
root.update-profile(profile-id);
|
||||
}
|
||||
|
||||
delete-profile(profile-id) => {
|
||||
root.delete-profile(profile-id);
|
||||
}
|
||||
|
||||
add-profile => {
|
||||
root.add-profile("");
|
||||
}
|
||||
}
|
||||
|
||||
// Connections page
|
||||
if current-view == "connections": ConnectionsPage {
|
||||
connections: root.connections;
|
||||
|
||||
load-connections => {
|
||||
root.load-connections();
|
||||
}
|
||||
}
|
||||
|
||||
// Logs page
|
||||
if current-view == "logs": LogsPage {
|
||||
mihomo-logs: root.mihomo-logs;
|
||||
app-logs: root.app-logs;
|
||||
|
||||
load-logs(log-type) => {
|
||||
root.load-logs(log-type);
|
||||
}
|
||||
}
|
||||
|
||||
// Settings page
|
||||
if current-view == "settings": SettingsPage {
|
||||
app-settings: root.app-settings;
|
||||
clash-settings: root.clash-settings;
|
||||
|
||||
load-settings => {
|
||||
root.load-settings();
|
||||
}
|
||||
|
||||
toggle-setting(key, value) => {
|
||||
root.toggle-setting(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Profiles Page
|
||||
if root.current-page == 2: ProfilesPage {
|
||||
profiles: root.profiles;
|
||||
selected-profile-id: root.selected-profile-id;
|
||||
|
||||
adrofile => { root.add-profile(); }
|
||||
refresh-all => { root.refresh-all-profiles(); }
|
||||
select-profile(id) => { root.select-profile(id); }
|
||||
edit-profile(id) => { root.edit-profile(id); }
|
||||
delete-profile(id) => { root.delete-profile(id); }
|
||||
refresh-profile(id) => { root.refresh-single-profile(id); }
|
||||
}
|
||||
|
||||
// Connections Page
|
||||
if root.current-page == 3: ConnectionsPage {
|
||||
connections: root.connections;
|
||||
}
|
||||
|
||||
// Logs Page
|
||||
if root.current-page == 4: LogsPage {
|
||||
mihomo-logs: root.mihomo-logs;
|
||||
app-logs: root.app-logs;
|
||||
current-tab: root.log-tab;
|
||||
|
||||
tab-changed(index) => { root.log-tab-changed(index); }
|
||||
}
|
||||
|
||||
// Settings Page
|
||||
if root.current-page == 5: SettingsPage {
|
||||
auto-start: root.auto-start;
|
||||
silent-start: root.silent-start;
|
||||
clash-core: root.clash-core;
|
||||
tun-mode: root.tun-mode-enabled;
|
||||
allow-lan: root.allow-lan;
|
||||
ipv6: root.ipv6;
|
||||
unified-delay: root.unified-delay;
|
||||
log-level-index: root.log-level-index;
|
||||
proxy-port: root.proxy-port;
|
||||
app-dir: root.app-dir;
|
||||
config-dir: root.config-dir;
|
||||
core-dir: root.core-dir;
|
||||
app-version: root.app-version;
|
||||
|
||||
toggle-auto-start(enabled) => { root.toggle-auto-start(enabled); }
|
||||
toggle-silent-start(enabled) => { root.toggle-silent-start(enabled); }
|
||||
toggle-clash-core(enabled) => { root.toggle-clash-core(enabled); }
|
||||
toggle-tun-mode(enabled) => { root.toggle-tun-mode(enabled); }
|
||||
toggle-allow-lan(enabled) => { root.toggle-allow-lan(enabled); }
|
||||
toggle-ipv6(enabled) => { root.toggle-ipv6(enabled); }
|
||||
toggle-unified-delay(enabled) => { root.toggle-unified-delay(enabled); }
|
||||
log-level-changed(index) => { root.log-level-changed(index); }
|
||||
open-port-settings => { root.open-port-settings(); }
|
||||
open-tun-config => { root.open-tun-config(); }
|
||||
open-directory(dir) => { root.open-directory(dir); }
|
||||
}
|
||||
}
|
||||
|
||||
// Toast container
|
||||
Rectangle {
|
||||
x: parent.width - 390px;
|
||||
y: 20px;
|
||||
width: 370px;
|
||||
|
||||
ToastContainer {
|
||||
toasts: toasts;
|
||||
|
||||
toast-dismissed(index) => {
|
||||
// Will be handled by Rust
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user