Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"os"
"path/filepath"

"github.com/go-toast/toast"
"github.com/wailsapp/wails/v2/pkg/runtime"

"trae-switch/internal/cert"
"trae-switch/internal/config"
"trae-switch/internal/hosts"
Expand Down Expand Up @@ -265,3 +268,41 @@ func (a *App) shutdown(ctx context.Context) {
}
}
}

func (a *App) ShowWindow() {
runtime.WindowShow(a.ctx)
runtime.WindowSetAlwaysOnTop(a.ctx, false)
}

func (a *App) HideWindow() {
runtime.WindowHide(a.ctx)
}

func (a *App) HideWindowWithNotification() {
runtime.WindowHide(a.ctx)

notification := toast.Notification{
AppID: "Trae Switch",
Title: "Trae Switch",
Message: "程序将在后台运行,点击托盘图标恢复窗口",
Icon: "", // No icon path needed for basic notification
}
if err := notification.Push(); err != nil {
log.Printf("Failed to send notification: %v", err)
}
}

func (a *App) QuitApp() {
if a.IsProxyRunning() {
a.StopProxy()
}
runtime.Quit(a.ctx)
}

func (a *App) SetTrayMode(enabled bool) error {
return config.SetTrayMode(enabled)
}

func (a *App) GetTrayMode() bool {
return config.GetTrayMode()
}
41 changes: 41 additions & 0 deletions frontend/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { onMount } from 'svelte'
import Button from './components/ui/Button.svelte'
import Card from './components/ui/Card.svelte'
import Switch from './components/ui/Switch.svelte'

let status = {
runningAsAdmin: false,
Expand All @@ -21,6 +22,7 @@
let error = ''
let success = ''
let theme = 'dark'
let trayMode = false

let showProviderModal = false
let editingProviderIndex = -1
Expand Down Expand Up @@ -59,8 +61,30 @@

await refreshStatus()
await loadProviders()
await loadTrayMode()
})

async function loadTrayMode() {
try {
trayMode = await window.go.main.App.GetTrayMode()
} catch (e) {
console.error('Failed to load tray mode:', e)
}
}

async function toggleTrayMode() {
try {
await window.go.main.App.SetTrayMode(trayMode)
if (trayMode) {
showSuccess('常驻任务栏已开启')
} else {
showSuccess('常驻任务栏已关闭')
}
} catch (e) {
showError(e.message || String(e))
}
}

function toggleTheme() {
const currentIndex = themes.findIndex((item) => item.value === theme)
const nextTheme = themes[(currentIndex + 1) % themes.length].value
Expand Down Expand Up @@ -439,6 +463,23 @@
<Card className="p-4">
<h2 class="mb-4 font-semibold">系统配置</h2>

<div class="mb-3 flex items-center justify-between rounded-lg bg-muted/50 p-3">
<div class="flex items-center gap-3">
{#if trayMode}
<span class="h-2 w-2 rounded-full bg-success"></span>
{:else}
<span class="h-2 w-2 rounded-full bg-muted-foreground"></span>
{/if}
<div>
<div class="text-sm font-medium">常驻任务栏</div>
<div class="text-xs text-muted-foreground">
{trayMode ? '已开启' : '已关闭'}
</div>
</div>
</div>
<Switch checked={trayMode} on:change={() => { trayMode = !trayMode; toggleTrayMode() }} />
</div>

<div class="grid grid-cols-2 gap-3">
<div class="rounded-lg bg-muted/50 p-3">
<div class="flex items-center gap-3">
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/components/ui/Switch.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
<script>
import { cn } from '../../lib/utils.js';
import { createEventDispatcher } from 'svelte';

export let checked = false;
export let disabled = false;
export let className = '';

const dispatch = createEventDispatcher();

function toggle() {
if (!disabled) {
checked = !checked;
dispatch('change', checked);
}
}
</script>
Expand Down
12 changes: 12 additions & 0 deletions frontend/wailsjs/go/main/App.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export function GetProviders():Promise<Array<Record<string, any>>>;

export function GetStatus():Promise<Record<string, any>>;

export function GetTrayMode():Promise<boolean>;

export function HideWindow():Promise<void>;

export function HideWindowWithNotification():Promise<void>;

export function InstallCertificate():Promise<void>;

export function IsCertificateInstalled():Promise<boolean>;
Expand All @@ -25,12 +31,18 @@ export function QuickStart():Promise<void>;

export function QuickStop():Promise<void>;

export function QuitApp():Promise<void>;

export function RestoreHosts():Promise<void>;

export function SetActiveProvider(arg1:number):Promise<void>;

export function SetHosts():Promise<void>;

export function SetTrayMode(arg1:boolean):Promise<void>;

export function ShowWindow():Promise<void>;

export function StartProxy():Promise<void>;

export function StopProxy():Promise<void>;
Expand Down
24 changes: 24 additions & 0 deletions frontend/wailsjs/go/main/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ export function GetStatus() {
return window['go']['main']['App']['GetStatus']();
}

export function GetTrayMode() {
return window['go']['main']['App']['GetTrayMode']();
}

export function HideWindow() {
return window['go']['main']['App']['HideWindow']();
}

export function HideWindowWithNotification() {
return window['go']['main']['App']['HideWindowWithNotification']();
}

export function InstallCertificate() {
return window['go']['main']['App']['InstallCertificate']();
}
Expand Down Expand Up @@ -50,6 +62,10 @@ export function QuickStop() {
return window['go']['main']['App']['QuickStop']();
}

export function QuitApp() {
return window['go']['main']['App']['QuitApp']();
}

export function RestoreHosts() {
return window['go']['main']['App']['RestoreHosts']();
}
Expand All @@ -62,6 +78,14 @@ export function SetHosts() {
return window['go']['main']['App']['SetHosts']();
}

export function SetTrayMode(arg1) {
return window['go']['main']['App']['SetTrayMode'](arg1);
}

export function ShowWindow() {
return window['go']['main']['App']['ShowWindow']();
}

export function StartProxy() {
return window['go']['main']['App']['StartProxy']();
}
Expand Down
83 changes: 82 additions & 1 deletion frontend/wailsjs/runtime/runtime.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,85 @@ export function OnFileDropOff() :void
export function CanResolveFilePaths(): boolean;

// Resolves file paths for an array of files
export function ResolveFilePaths(files: File[]): void
export function ResolveFilePaths(files: File[]): void

// Notification types
export interface NotificationOptions {
id: string;
title: string;
subtitle?: string; // macOS and Linux only
body?: string;
categoryId?: string;
data?: { [key: string]: any };
}

export interface NotificationAction {
id?: string;
title?: string;
destructive?: boolean; // macOS-specific
}

export interface NotificationCategory {
id?: string;
actions?: NotificationAction[];
hasReplyField?: boolean;
replyPlaceholder?: string;
replyButtonTitle?: string;
}

// [InitializeNotifications](https://wails.io/docs/reference/runtime/notification#initializenotifications)
// Initializes the notification service for the application.
// This must be called before sending any notifications.
export function InitializeNotifications(): Promise<void>;

// [CleanupNotifications](https://wails.io/docs/reference/runtime/notification#cleanupnotifications)
// Cleans up notification resources and releases any held connections.
export function CleanupNotifications(): Promise<void>;

// [IsNotificationAvailable](https://wails.io/docs/reference/runtime/notification#isnotificationavailable)
// Checks if notifications are available on the current platform.
export function IsNotificationAvailable(): Promise<boolean>;

// [RequestNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#requestnotificationauthorization)
// Requests notification authorization from the user (macOS only).
export function RequestNotificationAuthorization(): Promise<boolean>;

// [CheckNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#checknotificationauthorization)
// Checks the current notification authorization status (macOS only).
export function CheckNotificationAuthorization(): Promise<boolean>;

// [SendNotification](https://wails.io/docs/reference/runtime/notification#sendnotification)
// Sends a basic notification with the given options.
export function SendNotification(options: NotificationOptions): Promise<void>;

// [SendNotificationWithActions](https://wails.io/docs/reference/runtime/notification#sendnotificationwithactions)
// Sends a notification with action buttons. Requires a registered category.
export function SendNotificationWithActions(options: NotificationOptions): Promise<void>;

// [RegisterNotificationCategory](https://wails.io/docs/reference/runtime/notification#registernotificationcategory)
// Registers a notification category that can be used with SendNotificationWithActions.
export function RegisterNotificationCategory(category: NotificationCategory): Promise<void>;

// [RemoveNotificationCategory](https://wails.io/docs/reference/runtime/notification#removenotificationcategory)
// Removes a previously registered notification category.
export function RemoveNotificationCategory(categoryId: string): Promise<void>;

// [RemoveAllPendingNotifications](https://wails.io/docs/reference/runtime/notification#removeallpendingnotifications)
// Removes all pending notifications from the notification center.
export function RemoveAllPendingNotifications(): Promise<void>;

// [RemovePendingNotification](https://wails.io/docs/reference/runtime/notification#removependingnotification)
// Removes a specific pending notification by its identifier.
export function RemovePendingNotification(identifier: string): Promise<void>;

// [RemoveAllDeliveredNotifications](https://wails.io/docs/reference/runtime/notification#removealldeliverednotifications)
// Removes all delivered notifications from the notification center.
export function RemoveAllDeliveredNotifications(): Promise<void>;

// [RemoveDeliveredNotification](https://wails.io/docs/reference/runtime/notification#removedeliverednotification)
// Removes a specific delivered notification by its identifier.
export function RemoveDeliveredNotification(identifier: string): Promise<void>;

// [RemoveNotification](https://wails.io/docs/reference/runtime/notification#removenotification)
// Removes a notification by its identifier (cross-platform convenience function).
export function RemoveNotification(identifier: string): Promise<void>;
56 changes: 56 additions & 0 deletions frontend/wailsjs/runtime/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,60 @@ export function CanResolveFilePaths() {

export function ResolveFilePaths(files) {
return window.runtime.ResolveFilePaths(files);
}

export function InitializeNotifications() {
return window.runtime.InitializeNotifications();
}

export function CleanupNotifications() {
return window.runtime.CleanupNotifications();
}

export function IsNotificationAvailable() {
return window.runtime.IsNotificationAvailable();
}

export function RequestNotificationAuthorization() {
return window.runtime.RequestNotificationAuthorization();
}

export function CheckNotificationAuthorization() {
return window.runtime.CheckNotificationAuthorization();
}

export function SendNotification(options) {
return window.runtime.SendNotification(options);
}

export function SendNotificationWithActions(options) {
return window.runtime.SendNotificationWithActions(options);
}

export function RegisterNotificationCategory(category) {
return window.runtime.RegisterNotificationCategory(category);
}

export function RemoveNotificationCategory(categoryId) {
return window.runtime.RemoveNotificationCategory(categoryId);
}

export function RemoveAllPendingNotifications() {
return window.runtime.RemoveAllPendingNotifications();
}

export function RemovePendingNotification(identifier) {
return window.runtime.RemovePendingNotification(identifier);
}

export function RemoveAllDeliveredNotifications() {
return window.runtime.RemoveAllDeliveredNotifications();
}

export function RemoveDeliveredNotification(identifier) {
return window.runtime.RemoveDeliveredNotification(identifier);
}

export function RemoveNotification(identifier) {
return window.runtime.RemoveNotification(identifier);
}
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ go 1.22.0

toolchain go1.24.1

require github.com/wailsapp/wails/v2 v2.11.0
require (
github.com/energye/systray v1.0.3
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
github.com/wailsapp/wails/v2 v2.11.0
)

require (
github.com/bep/debounce v1.2.1 // indirect
Expand All @@ -21,6 +25,7 @@ require (
github.com/leaanthony/u v1.1.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
Expand Down
Loading