diff --git a/App.xaml.cs b/App.xaml.cs index 2bf7de7..f05e20f 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -87,6 +87,9 @@ public partial class App : Application // 后台异步拉一次应用列表,不阻塞启动 _ = _appCache.RefreshAsync(); + // 加载主题(必须在 StartAsync 之前,这样主窗第一次 Show 时资源已经在) + Services.ThemeService.Apply(config.Ui.Theme); + await _webSocketService.StartAsync(); } diff --git a/Assets/Build-Icon.ps1 b/Assets/Build-Icon.ps1 new file mode 100644 index 0000000..eebc0b8 --- /dev/null +++ b/Assets/Build-Icon.ps1 @@ -0,0 +1,84 @@ +# 从 Assets/gotify-mascot.png 生成多分辨率 ICO +# 输出:Assets/gotify-mascot.ico +param( + [string]$Png = "$PSScriptRoot\gotify-mascot.png", + [string]$Ico = "$PSScriptRoot\gotify-mascot.ico" +) + +Add-Type -AssemblyName System.Drawing + +$src = [System.Drawing.Image]::FromFile((Resolve-Path $Png)) +$srcW = $src.Width +$srcH = $src.Height + +# 多分辨率列表(像素) — 包含原始尺寸 +$sizes = @(16, 24, 32, 48, 64, 128, 196) | Where-Object { $_ -le [math]::Max($srcW, $srcH) } +if (($srcW, $srcH) -notin $sizes) { $sizes += ,($srcW, $srcH) | Out-Null } +$sizes = $sizes | Sort-Object -Unique + +# 1) 把每个分辨率的位图渲染成 PNG 字节 +$entries = @() +foreach ($sz in $sizes) { + $bmp = New-Object System.Drawing.Bitmap $sz, $sz, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb) + $g = [System.Drawing.Graphics]::FromImage($bmp) + $g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic + $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality + $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality + $g.Clear([System.Drawing.Color]::Transparent) + $g.DrawImage($src, 0, 0, $sz, $sz) + $g.Dispose() + + $ms = New-Object System.IO.MemoryStream + $bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png) + $pngBytes = $ms.ToArray() + $ms.Dispose() + $bmp.Dispose() + + $entries += [pscustomobject]@{ + Width = $sz + Height = $sz + Bytes = $pngBytes + } +} +$src.Dispose() + +# 2) 组装 ICO 文件 +# ICONDIR (6 bytes) +# ICONDIRENTRY * N (16 bytes each) +# Image data + +$out = New-Object System.IO.MemoryStream +$bw = New-Object System.IO.BinaryWriter $out + +# ICONDIR +$bw.Write([uint16]0) # Reserved +$bw.Write([uint16]1) # Type: 1 = ICO +$bw.Write([uint16]$entries.Count) # Count + +# ICONDIRENTRY (16 bytes each) +$dataOffset = 6 + 16 * $entries.Count +foreach ($e in $entries) { + $w = if ($e.Width -ge 256) { 0 } else { $e.Width } + $h = if ($e.Height -ge 256) { 0 } else { $e.Height } + $bw.Write([byte]$w) # Width + $bw.Write([byte]$h) # Height + $bw.Write([byte]0) # Color count (0 = >256 colors) + $bw.Write([byte]0) # Reserved + $bw.Write([uint16]1) # Color planes + $bw.Write([uint16]32) # Bits per pixel + $bw.Write([uint32]$e.Bytes.Length) + $bw.Write([uint32]$dataOffset) + $dataOffset += $e.Bytes.Length +} + +# Image data +foreach ($e in $entries) { + $bw.Write($e.Bytes) +} + +$bw.Flush() +[System.IO.File]::WriteAllBytes($Ico, $out.ToArray()) +$bw.Dispose() +$out.Dispose() + +Write-Host "ICO built: $Ico ($((Get-Item $Ico).Length) bytes, $($entries.Count) sizes: $($sizes -join ','))" diff --git a/Assets/gotify-mascot.ico b/Assets/gotify-mascot.ico new file mode 100644 index 0000000..731ee6d Binary files /dev/null and b/Assets/gotify-mascot.ico differ diff --git a/Assets/gotify-mascot.png b/Assets/gotify-mascot.png new file mode 100644 index 0000000..d33ecc5 Binary files /dev/null and b/Assets/gotify-mascot.png differ diff --git a/Converters/ValueConverters.cs b/Converters/ValueConverters.cs index 93f2aa8..1bcc8fd 100644 --- a/Converters/ValueConverters.cs +++ b/Converters/ValueConverters.cs @@ -3,8 +3,10 @@ using System.Windows; using System.Windows.Data; using System.Windows.Media; -// 双开 WPF + WinForms 时,Color 在两个命名空间都有,固定走 WPF 的。 +// 双开 WPF + WinForms 时,这几个类型两个命名空间都有,固定走 WPF 的。 +using Application = System.Windows.Application; using Color = System.Windows.Media.Color; +using Brush = System.Windows.Media.Brush; namespace WindowsGotify; @@ -19,13 +21,16 @@ public sealed class PriorityToBrushConverter : IValueConverter if (value is int p1) { - return p1 switch + // 从主题字典里取色,跟着 Theme 切换走 + var key = p1 switch { - >= 8 => new SolidColorBrush(Color.FromRgb(0xD1, 0x34, 0x38)), // 紧急 - 红 - >= 5 => new SolidColorBrush(Color.FromRgb(0xCA, 0x50, 0x10)), // 重要 - 橙 - >= 1 => new SolidColorBrush(Color.FromRgb(0x4A, 0x55, 0x68)), // 一般 - 灰蓝 - _ => new SolidColorBrush(Color.FromRgb(0x88, 0x88, 0x88)) // 静默 - 浅灰 + >= 8 => "PriorityUrgent", + >= 5 => "PriorityHigh", + >= 1 => "PriorityNormal", + _ => "PriorityLow" }; + if (Application.Current?.TryFindResource(key) is Brush b) return b; + return new SolidColorBrush(Colors.Gray); } return new SolidColorBrush(Colors.Gray); } diff --git a/MainWindow.xaml b/MainWindow.xaml index fcbb6d6..04e779a 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -8,10 +8,10 @@ MinWidth="900" MinHeight="560" WindowStartupLocation="CenterScreen" - Background="#FAFAFA"> + Background="{DynamicResource WindowBackground}" + Foreground="{DynamicResource PrimaryText}"> - @@ -27,43 +27,28 @@ - - + CornerRadius="4" Margin="0,2,8,2" Padding="4,2" + VerticalAlignment="Top" HorizontalAlignment="Stretch"> - - - + - - + Foreground="{DynamicResource PrimaryText}"> - + Foreground="{DynamicResource SecondaryText}" FontSize="12" /> @@ -95,26 +77,32 @@ - - - - - + + + + + + + + + + +