fead.做了状态栏加了更多的胶囊组件。然后我稍微修了一下智教Hub组件

This commit is contained in:
lincube
2026-04-03 21:25:15 +08:00
parent 1c3cc76f21
commit 675096b6c4
19 changed files with 1488 additions and 17 deletions

View File

@@ -400,6 +400,29 @@
"settings.status_bar.text_capsule_position.right": "Right",
"settings.status_bar.text_capsule_content_label": "Text content (Markdown supported)",
"settings.status_bar.text_capsule_transparent_background_label": "Transparent background",
"settings.status_bar.network_speed_header": "Network Speed",
"settings.status_bar.network_speed_description": "Display real-time network upload and download speed on the status bar.",
"settings.status_bar.network_speed_position_label": "Network speed position",
"settings.status_bar.network_speed_position.left": "Left",
"settings.status_bar.network_speed_position.center": "Center",
"settings.status_bar.network_speed_position.right": "Right",
"settings.status_bar.network_speed_mode_label": "Display mode",
"settings.status_bar.network_speed_mode.both": "Upload + Download",
"settings.status_bar.network_speed_mode.upload": "Upload only",
"settings.status_bar.network_speed_mode.download": "Download only",
"settings.status_bar.network_speed_transparent_background_label": "Transparent background",
"settings.status_bar.show_network_type_icon_label": "Show network type icon",
"settings.status_bar.shadow_header": "Status Bar Shadow",
"settings.status_bar.shadow_desc": "Add shadow effect to the status bar for better visibility of transparent components.",
"settings.status_bar.shadow_enabled_label": "Enable shadow",
"settings.status_bar.shadow_color_label": "Shadow color",
"settings.status_bar.shadow_opacity_label": "Shadow opacity",
"settings.status_bar.theme_header": "Status Bar Theme",
"settings.status_bar.theme_desc": "Set the theme mode for the status bar independently.",
"settings.status_bar.theme_mode_label": "Theme mode",
"settings.status_bar.theme_mode.follow_global": "Follow Global",
"settings.status_bar.theme_mode.dark": "Dark",
"settings.status_bar.theme_mode.light": "Light",
"settings.components.title": "Components",
"settings.components.description": "Adjust component layout and corner design.",
"settings.components.grid_header": "Grid Settings",

View File

@@ -343,6 +343,29 @@
"settings.status_bar.text_capsule_position.right": "右",
"settings.status_bar.text_capsule_content_label": "テキスト内容Markdown対応",
"settings.status_bar.text_capsule_transparent_background_label": "透明な背景",
"settings.status_bar.network_speed_header": "ネットワーク速度",
"settings.status_bar.network_speed_description": "ステータスバーにリアルタイムのネットワーク速度を表示します。",
"settings.status_bar.network_speed_position_label": "ネットワーク速度の位置",
"settings.status_bar.network_speed_position.left": "左",
"settings.status_bar.network_speed_position.center": "中央",
"settings.status_bar.network_speed_position.right": "右",
"settings.status_bar.network_speed_mode_label": "表示モード",
"settings.status_bar.network_speed_mode.both": "アップロード + ダウンロード",
"settings.status_bar.network_speed_mode.upload": "アップロードのみ",
"settings.status_bar.network_speed_mode.download": "ダウンロードのみ",
"settings.status_bar.network_speed_transparent_background_label": "透明な背景",
"settings.status_bar.show_network_type_icon_label": "ネットワークタイプアイコンを表示",
"settings.status_bar.shadow_header": "ステータスバーの影",
"settings.status_bar.shadow_desc": "透明なコンポーネントの視認性を高めるために、ステータスバーに影効果を追加します。",
"settings.status_bar.shadow_enabled_label": "影を有効にする",
"settings.status_bar.shadow_color_label": "影の色",
"settings.status_bar.shadow_opacity_label": "影の不透明度",
"settings.status_bar.theme_header": "ステータスバーのテーマ",
"settings.status_bar.theme_desc": "ステータスバーのテーマモードを独立して設定します。",
"settings.status_bar.theme_mode_label": "テーマモード",
"settings.status_bar.theme_mode.follow_global": "グローバルに従う",
"settings.status_bar.theme_mode.dark": "ダーク",
"settings.status_bar.theme_mode.light": "ライト",
"settings.components.title": "コンポーネント",
"settings.components.description": "コンポーネントのレイアウトとコーナーデザインを調整します。",
"settings.components.grid_header": "グリッド設定",

View File

@@ -389,6 +389,29 @@
"settings.status_bar.text_capsule_position.right": "오른쪽",
"settings.status_bar.text_capsule_content_label": "텍스트 내용 (Markdown 지원)",
"settings.status_bar.text_capsule_transparent_background_label": "투명 배경",
"settings.status_bar.network_speed_header": "네트워크 속도",
"settings.status_bar.network_speed_description": "상태 표시줄에 실시간 네트워크 속도를 표시합니다.",
"settings.status_bar.network_speed_position_label": "네트워크 속도 위치",
"settings.status_bar.network_speed_position.left": "왼쪽",
"settings.status_bar.network_speed_position.center": "가욍데",
"settings.status_bar.network_speed_position.right": "오른쪽",
"settings.status_bar.network_speed_mode_label": "표시 모드",
"settings.status_bar.network_speed_mode.both": "업로드 + 다운로드",
"settings.status_bar.network_speed_mode.upload": "업로드만",
"settings.status_bar.network_speed_mode.download": "다운로드만",
"settings.status_bar.network_speed_transparent_background_label": "투명 배경",
"settings.status_bar.show_network_type_icon_label": "네트워크 유형 아이콘 표시",
"settings.status_bar.shadow_header": "상태 표시줄 그림자",
"settings.status_bar.shadow_desc": "투명한 구성 요소의 가시성을 높이기 위해 상태 표시줄에 그림자 효과를 추가합니다.",
"settings.status_bar.shadow_enabled_label": "그림자 활성화",
"settings.status_bar.shadow_color_label": "그림자 색상",
"settings.status_bar.shadow_opacity_label": "그림자 불투명도",
"settings.status_bar.theme_header": "상태 표시줄 테마",
"settings.status_bar.theme_desc": "상태 표시줄의 테마 모드를 독립적으로 설정합니다.",
"settings.status_bar.theme_mode_label": "테마 모드",
"settings.status_bar.theme_mode.follow_global": "전역 따르기",
"settings.status_bar.theme_mode.dark": "다크",
"settings.status_bar.theme_mode.light": "라이트",
"settings.components.title": "컴포넌트",
"settings.components.description": "컴포넌트 레이아웃과 모서리 디자인을 조정합니다.",
"settings.components.grid_header": "그리드 설정",

View File

@@ -395,6 +395,29 @@
"settings.status_bar.text_capsule_position.right": "靠右",
"settings.status_bar.text_capsule_content_label": "文字内容(支持 Markdown",
"settings.status_bar.text_capsule_transparent_background_label": "透明背景",
"settings.status_bar.network_speed_header": "网速显示",
"settings.status_bar.network_speed_description": "在状态栏显示实时网络上传和下载速度。",
"settings.status_bar.network_speed_position_label": "网速显示位置",
"settings.status_bar.network_speed_position.left": "靠左",
"settings.status_bar.network_speed_position.center": "居中",
"settings.status_bar.network_speed_position.right": "靠右",
"settings.status_bar.network_speed_mode_label": "显示模式",
"settings.status_bar.network_speed_mode.both": "上传 + 下载",
"settings.status_bar.network_speed_mode.upload": "仅上传",
"settings.status_bar.network_speed_mode.download": "仅下载",
"settings.status_bar.network_speed_transparent_background_label": "透明背景",
"settings.status_bar.show_network_type_icon_label": "显示网络类型图标",
"settings.status_bar.shadow_header": "状态栏阴影",
"settings.status_bar.shadow_desc": "为状态栏添加阴影效果,使透明背景的组件更清晰。",
"settings.status_bar.shadow_enabled_label": "启用阴影",
"settings.status_bar.shadow_color_label": "阴影颜色",
"settings.status_bar.shadow_opacity_label": "阴影透明度",
"settings.status_bar.theme_header": "状态栏主题",
"settings.status_bar.theme_desc": "独立设置状态栏的主题模式。",
"settings.status_bar.theme_mode_label": "主题模式",
"settings.status_bar.theme_mode.follow_global": "跟随全局",
"settings.status_bar.theme_mode.dark": "暗色",
"settings.status_bar.theme_mode.light": "浅色",
"settings.components.title": "组件",
"settings.components.description": "调整组件布局与圆角设计。",
"settings.components.grid_header": "网格设置",

View File

@@ -114,6 +114,8 @@ public sealed class AppSettingsSnapshot
public string ClockPosition { get; set; } = "Left"; // Left, Center, Right
public string ClockFontSize { get; set; } = "Medium"; // Small, Medium, Large
public bool ShowTextCapsule { get; set; } = false;
public string TextCapsuleContent { get; set; } = "**Hello** World!";
@@ -122,8 +124,28 @@ public sealed class AppSettingsSnapshot
public bool TextCapsuleTransparentBackground { get; set; } = false;
public string TextCapsuleFontSize { get; set; } = "Medium"; // Small, Medium, Large
public bool ShowNetworkSpeed { get; set; } = false;
public string NetworkSpeedPosition { get; set; } = "Right"; // Left, Center, Right
public string NetworkSpeedDisplayMode { get; set; } = "Both"; // Upload, Download, Both
public bool NetworkSpeedTransparentBackground { get; set; } = false;
public bool ShowNetworkTypeIcon { get; set; } = false;
public string NetworkSpeedFontSize { get; set; } = "Medium"; // Small, Medium, Large
public string StatusBarSpacingMode { get; set; } = "Relaxed";
public bool StatusBarShadowEnabled { get; set; } = false;
public string StatusBarShadowColor { get; set; } = "#000000";
public double StatusBarShadowOpacity { get; set; } = 0.3;
public int StatusBarCustomSpacingPercent { get; set; } = 12;
public bool EnableThreeFingerSwipe { get; set; } = false;

View File

@@ -317,11 +317,11 @@ public sealed record RecommendationApiOptions
public string ClassIslandHubApiUrl { get; init; } = "https://api.github.com/repos/ClassIsland/classisland-hub/contents/images";
public string SectlHubApiUrl { get; init; } = "https://api.github.com/repos/SECTL/SECTL-hub/contents/images";
public string SectlHubApiUrl { get; init; } = "https://api.github.com/repos/SECTL/SECTL-hub/contents/docs/.vuepress/public/images";
public string ClassIslandHubRawUrlTemplate { get; init; } = "https://raw.githubusercontent.com/ClassIsland/classisland-hub/main/images/{0}";
public string SectlHubRawUrlTemplate { get; init; } = "https://raw.githubusercontent.com/SECTL/SECTL-hub/main/images/{0}";
public string SectlHubRawUrlTemplate { get; init; } = "https://raw.githubusercontent.com/SECTL/SECTL-hub/main/docs/.vuepress/public/images/{0}";
public string RinLitHubRawUrlTemplate { get; init; } = "https://raw.githubusercontent.com/RinLit-233-shiroko/Rin-sHub/main/images/{0}";
}

View File

@@ -3244,11 +3244,11 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis
private async Task<ZhiJiaoHubSnapshot> FetchZhiJiaoHubSnapshotAsync(string source, string mirrorSource, CancellationToken cancellationToken)
{
var (owner, repo, path) = source switch
var (owner, repo, path, rawUrlTemplate) = source switch
{
ZhiJiaoHubSources.Sectl => ("SECTL", "SECTL-hub", "docs/.vuepress/public/images"),
ZhiJiaoHubSources.RinLit => ("RinLit-233-shiroko", "Rin-sHub", "images"),
_ => ("ClassIsland", "classisland-hub", "images")
ZhiJiaoHubSources.Sectl =&gt; ("SECTL", "SECTL-hub", "docs/.vuepress/public/images", _options.SectlHubRawUrlTemplate),
ZhiJiaoHubSources.RinLit =&gt; ("RinLit-233-shiroko", "Rin-sHub", "images", _options.RinLitHubRawUrlTemplate),
_ =&gt; ("ClassIsland", "classisland-hub", "images", _options.ClassIslandHubRawUrlTemplate)
};
var contentsUrl = $"https://api.github.com/repos/{owner}/{repo}/contents/{path}";
@@ -3261,7 +3261,7 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis
try
{
var images = await FetchImagesFromContentsApi(owner, repo, path, contentsUrl, mirrorSource, cancellationToken);
var images = await FetchImagesFromContentsApi(owner, repo, path, rawUrlTemplate, contentsUrl, mirrorSource, cancellationToken);
if (images.Count == 0)
{
@@ -3291,7 +3291,7 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis
}
}
private async Task<List<ZhiJiaoHubImageItem>> FetchImagesFromContentsApi(string owner, string repo, string path, string contentsUrl, string mirrorSource, CancellationToken cancellationToken)
private async Task<List<ZhiJiaoHubImageItem>> FetchImagesFromContentsApi(string owner, string repo, string path, string rawUrlTemplate, string contentsUrl, string mirrorSource, CancellationToken cancellationToken)
{
var images = new List<ZhiJiaoHubImageItem>();
@@ -3362,7 +3362,9 @@ public sealed class RecommendationDataService : IRecommendationInfoService, IDis
}
else
{
imageUrl = $"https://raw.githubusercontent.com/{owner}/{repo}/main/{path}/{Uri.EscapeDataString(name)}";
// 使用为每个数据源专门配置的 raw URL 模板
// 注意:模板已经包含了正确的路径,只需要传入文件名
imageUrl = string.Format(rawUrlTemplate, Uri.EscapeDataString(name));
}
// 应用镜像加速到图片 URL

View File

@@ -42,12 +42,23 @@ public sealed record StatusBarSettingsState(
string ClockDisplayFormat,
bool ClockTransparentBackground,
string ClockPosition,
string ClockFontSize,
bool ShowTextCapsule,
string TextCapsuleContent,
string TextCapsulePosition,
bool TextCapsuleTransparentBackground,
string TextCapsuleFontSize,
bool ShowNetworkSpeed,
string NetworkSpeedPosition,
string NetworkSpeedDisplayMode,
bool NetworkSpeedTransparentBackground,
bool ShowNetworkTypeIcon,
string NetworkSpeedFontSize,
string SpacingMode,
int CustomSpacingPercent);
int CustomSpacingPercent,
bool ShadowEnabled,
string ShadowColor,
double ShadowOpacity);
public sealed record TextCapsuleSettingsState(
bool ShowTextCapsule,

View File

@@ -387,12 +387,23 @@ internal sealed class StatusBarSettingsService : IStatusBarSettingsService
snapshot.ClockDisplayFormat,
snapshot.StatusBarClockTransparentBackground,
snapshot.ClockPosition,
snapshot.ClockFontSize,
snapshot.ShowTextCapsule,
snapshot.TextCapsuleContent,
snapshot.TextCapsulePosition,
snapshot.TextCapsuleTransparentBackground,
snapshot.TextCapsuleFontSize,
snapshot.ShowNetworkSpeed,
snapshot.NetworkSpeedPosition,
snapshot.NetworkSpeedDisplayMode,
snapshot.NetworkSpeedTransparentBackground,
snapshot.ShowNetworkTypeIcon,
snapshot.NetworkSpeedFontSize,
snapshot.StatusBarSpacingMode,
snapshot.StatusBarCustomSpacingPercent);
snapshot.StatusBarCustomSpacingPercent,
snapshot.StatusBarShadowEnabled,
snapshot.StatusBarShadowColor,
snapshot.StatusBarShadowOpacity);
}
public void Save(StatusBarSettingsState state)
@@ -405,12 +416,23 @@ internal sealed class StatusBarSettingsService : IStatusBarSettingsService
snapshot.ClockDisplayFormat = state.ClockDisplayFormat;
snapshot.StatusBarClockTransparentBackground = state.ClockTransparentBackground;
snapshot.ClockPosition = state.ClockPosition;
snapshot.ClockFontSize = state.ClockFontSize;
snapshot.ShowTextCapsule = state.ShowTextCapsule;
snapshot.TextCapsuleContent = state.TextCapsuleContent;
snapshot.TextCapsulePosition = state.TextCapsulePosition;
snapshot.TextCapsuleTransparentBackground = state.TextCapsuleTransparentBackground;
snapshot.TextCapsuleFontSize = state.TextCapsuleFontSize;
snapshot.ShowNetworkSpeed = state.ShowNetworkSpeed;
snapshot.NetworkSpeedPosition = state.NetworkSpeedPosition;
snapshot.NetworkSpeedDisplayMode = state.NetworkSpeedDisplayMode;
snapshot.NetworkSpeedTransparentBackground = state.NetworkSpeedTransparentBackground;
snapshot.ShowNetworkTypeIcon = state.ShowNetworkTypeIcon;
snapshot.NetworkSpeedFontSize = state.NetworkSpeedFontSize;
snapshot.StatusBarSpacingMode = state.SpacingMode;
snapshot.StatusBarCustomSpacingPercent = state.CustomSpacingPercent;
snapshot.StatusBarShadowEnabled = state.ShadowEnabled;
snapshot.StatusBarShadowColor = state.ShadowColor;
snapshot.StatusBarShadowOpacity = state.ShadowOpacity;
_settingsService.SaveSnapshot(
SettingsScope.App,
snapshot,
@@ -423,12 +445,23 @@ internal sealed class StatusBarSettingsService : IStatusBarSettingsService
nameof(AppSettingsSnapshot.ClockDisplayFormat),
nameof(AppSettingsSnapshot.StatusBarClockTransparentBackground),
nameof(AppSettingsSnapshot.ClockPosition),
nameof(AppSettingsSnapshot.ClockFontSize),
nameof(AppSettingsSnapshot.ShowTextCapsule),
nameof(AppSettingsSnapshot.TextCapsuleContent),
nameof(AppSettingsSnapshot.TextCapsulePosition),
nameof(AppSettingsSnapshot.TextCapsuleTransparentBackground),
nameof(AppSettingsSnapshot.TextCapsuleFontSize),
nameof(AppSettingsSnapshot.ShowNetworkSpeed),
nameof(AppSettingsSnapshot.NetworkSpeedPosition),
nameof(AppSettingsSnapshot.NetworkSpeedDisplayMode),
nameof(AppSettingsSnapshot.NetworkSpeedTransparentBackground),
nameof(AppSettingsSnapshot.ShowNetworkTypeIcon),
nameof(AppSettingsSnapshot.NetworkSpeedFontSize),
nameof(AppSettingsSnapshot.StatusBarSpacingMode),
nameof(AppSettingsSnapshot.StatusBarCustomSpacingPercent)
nameof(AppSettingsSnapshot.StatusBarCustomSpacingPercent),
nameof(AppSettingsSnapshot.StatusBarShadowEnabled),
nameof(AppSettingsSnapshot.StatusBarShadowColor),
nameof(AppSettingsSnapshot.StatusBarShadowOpacity)
]);
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using LanMountainDesktop.ComponentSystem;
using LanMountainDesktop.Services;
@@ -22,7 +23,11 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
ClockFormats = CreateClockFormats();
ClockPositions = CreateClockPositions();
ClockFontSizes = CreateFontSizes();
TextCapsulePositions = CreateTextCapsulePositions();
NetworkSpeedPositions = CreateNetworkSpeedPositions();
NetworkSpeedDisplayModes = CreateNetworkSpeedDisplayModes();
NetworkSpeedFontSizes = CreateFontSizes();
SpacingModes = CreateSpacingModes();
RefreshLocalizedText();
@@ -37,8 +42,16 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
public IReadOnlyList<SelectionOption> TextCapsulePositions { get; }
public IReadOnlyList<SelectionOption> NetworkSpeedPositions { get; }
public IReadOnlyList<SelectionOption> NetworkSpeedDisplayModes { get; }
public IReadOnlyList<SelectionOption> SpacingModes { get; }
public IReadOnlyList<SelectionOption> ClockFontSizes { get; }
public IReadOnlyList<SelectionOption> NetworkSpeedFontSizes { get; }
[ObservableProperty]
private bool _showClock = true;
@@ -87,6 +100,12 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
[ObservableProperty]
private string _clockPositionLabel = string.Empty;
[ObservableProperty]
private SelectionOption _selectedClockFontSize = new("Medium", "Medium");
[ObservableProperty]
private string _clockFontSizeLabel = string.Empty;
[ObservableProperty]
private string _textCapsuleHeader = string.Empty;
@@ -114,6 +133,45 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
[ObservableProperty]
private string _textCapsuleTransparentBackgroundLabel = string.Empty;
[ObservableProperty]
private string _networkSpeedHeader = string.Empty;
[ObservableProperty]
private string _networkSpeedDescription = string.Empty;
[ObservableProperty]
private bool _showNetworkSpeed;
[ObservableProperty]
private SelectionOption _selectedNetworkSpeedPosition = new("Right", "Right");
[ObservableProperty]
private SelectionOption _selectedNetworkSpeedDisplayMode = new("Both", "Both");
[ObservableProperty]
private bool _networkSpeedTransparentBackground;
[ObservableProperty]
private string _networkSpeedPositionLabel = string.Empty;
[ObservableProperty]
private string _networkSpeedDisplayModeLabel = string.Empty;
[ObservableProperty]
private string _networkSpeedTransparentBackgroundLabel = string.Empty;
[ObservableProperty]
private bool _showNetworkTypeIcon;
[ObservableProperty]
private string _showNetworkTypeIconLabel = string.Empty;
[ObservableProperty]
private SelectionOption _selectedNetworkSpeedFontSize = new("Medium", "Medium");
[ObservableProperty]
private string _networkSpeedFontSizeLabel = string.Empty;
[ObservableProperty]
private string _spacingHeader = string.Empty;
@@ -123,6 +181,32 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
[ObservableProperty]
private string _customSpacingLabel = string.Empty;
[ObservableProperty]
private bool _statusBarShadowEnabled;
[ObservableProperty]
private Color _statusBarShadowColor = Colors.Black;
[ObservableProperty]
private double _statusBarShadowOpacity = 30;
public IBrush StatusBarShadowColorBrush => new SolidColorBrush(StatusBarShadowColor);
[ObservableProperty]
private string _statusBarShadowHeader = string.Empty;
[ObservableProperty]
private string _statusBarShadowDescription = string.Empty;
[ObservableProperty]
private string _statusBarShadowEnabledLabel = string.Empty;
[ObservableProperty]
private string _statusBarShadowColorLabel = string.Empty;
[ObservableProperty]
private string _statusBarShadowOpacityLabel = string.Empty;
public void Load()
{
var state = _settingsFacade.StatusBar.Get();
@@ -143,6 +227,12 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
string.Equals(option.Value, clockPosition, StringComparison.OrdinalIgnoreCase))
?? ClockPositions[0];
// 时钟字体大小设置
var clockFontSize = NormalizeFontSize(state.ClockFontSize);
SelectedClockFontSize = ClockFontSizes.FirstOrDefault(option =>
string.Equals(option.Value, clockFontSize, StringComparison.OrdinalIgnoreCase))
?? ClockFontSizes[1]; // 默认中等
// 文字胶囊设置
ShowTextCapsule = state.ShowTextCapsule;
TextCapsuleContent = state.TextCapsuleContent ?? "**Hello** World!";
@@ -152,12 +242,39 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
?? TextCapsulePositions[2]; // 默认靠右
TextCapsuleTransparentBackground = state.TextCapsuleTransparentBackground;
// 网速设置
ShowNetworkSpeed = state.ShowNetworkSpeed;
var networkSpeedPosition = NormalizeNetworkSpeedPosition(state.NetworkSpeedPosition);
SelectedNetworkSpeedPosition = NetworkSpeedPositions.FirstOrDefault(option =>
string.Equals(option.Value, networkSpeedPosition, StringComparison.OrdinalIgnoreCase))
?? NetworkSpeedPositions[2]; // 默认靠右
var networkSpeedDisplayMode = NormalizeNetworkSpeedDisplayMode(state.NetworkSpeedDisplayMode);
SelectedNetworkSpeedDisplayMode = NetworkSpeedDisplayModes.FirstOrDefault(option =>
string.Equals(option.Value, networkSpeedDisplayMode, StringComparison.OrdinalIgnoreCase))
?? NetworkSpeedDisplayModes[0]; // 默认双向
NetworkSpeedTransparentBackground = state.NetworkSpeedTransparentBackground;
ShowNetworkTypeIcon = state.ShowNetworkTypeIcon;
// 网速字体大小设置
var networkSpeedFontSize = NormalizeFontSize(state.NetworkSpeedFontSize);
SelectedNetworkSpeedFontSize = NetworkSpeedFontSizes.FirstOrDefault(option =>
string.Equals(option.Value, networkSpeedFontSize, StringComparison.OrdinalIgnoreCase))
?? NetworkSpeedFontSizes[1]; // 默认中等
var spacingMode = NormalizeSpacingMode(state.SpacingMode);
SelectedSpacingMode = SpacingModes.FirstOrDefault(option =>
string.Equals(option.Value, spacingMode, StringComparison.OrdinalIgnoreCase))
?? SpacingModes[1];
CustomSpacingPercent = Math.Clamp(state.CustomSpacingPercent, 0, 30);
IsCustomSpacingVisible = string.Equals(SelectedSpacingMode.Value, "Custom", StringComparison.OrdinalIgnoreCase);
// 状态栏阴影设置
StatusBarShadowEnabled = state.ShadowEnabled;
if (Color.TryParse(state.ShadowColor, out var shadowColor))
{
StatusBarShadowColor = shadowColor;
}
StatusBarShadowOpacity = Math.Clamp(state.ShadowOpacity * 100, 0, 100);
}
partial void OnShowClockChanged(bool value)
@@ -200,6 +317,16 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
Save();
}
partial void OnSelectedClockFontSizeChanged(SelectionOption value)
{
if (_isInitializing || value is null)
{
return;
}
Save();
}
partial void OnShowTextCapsuleChanged(bool value)
{
if (_isInitializing)
@@ -240,6 +367,66 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
Save();
}
partial void OnShowNetworkSpeedChanged(bool value)
{
if (_isInitializing)
{
return;
}
Save();
}
partial void OnSelectedNetworkSpeedPositionChanged(SelectionOption value)
{
if (_isInitializing || value is null)
{
return;
}
Save();
}
partial void OnSelectedNetworkSpeedDisplayModeChanged(SelectionOption value)
{
if (_isInitializing || value is null)
{
return;
}
Save();
}
partial void OnNetworkSpeedTransparentBackgroundChanged(bool value)
{
if (_isInitializing)
{
return;
}
Save();
}
partial void OnShowNetworkTypeIconChanged(bool value)
{
if (_isInitializing)
{
return;
}
Save();
}
partial void OnSelectedNetworkSpeedFontSizeChanged(SelectionOption value)
{
if (_isInitializing || value is null)
{
return;
}
Save();
}
partial void OnSelectedSpacingModeChanged(SelectionOption value)
{
IsCustomSpacingVisible = string.Equals(value?.Value, "Custom", StringComparison.OrdinalIgnoreCase);
@@ -268,6 +455,37 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
Save();
}
partial void OnStatusBarShadowEnabledChanged(bool value)
{
if (_isInitializing)
{
return;
}
Save();
}
partial void OnStatusBarShadowColorChanged(Color value)
{
OnPropertyChanged(nameof(StatusBarShadowColorBrush));
if (_isInitializing)
{
return;
}
Save();
}
partial void OnStatusBarShadowOpacityChanged(double value)
{
if (_isInitializing)
{
return;
}
Save();
}
private void Save()
{
var state = _settingsFacade.StatusBar.Get();
@@ -288,12 +506,23 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
SelectedClockFormat.Value,
ClockTransparentBackground,
SelectedClockPosition.Value,
SelectedClockFontSize?.Value ?? "Medium",
ShowTextCapsule,
TextCapsuleContent ?? "**Hello** World!",
SelectedTextCapsulePosition?.Value ?? "Right",
TextCapsuleTransparentBackground,
"Medium", // TextCapsuleFontSize - 暂时使用默认值
ShowNetworkSpeed,
SelectedNetworkSpeedPosition?.Value ?? "Right",
SelectedNetworkSpeedDisplayMode?.Value ?? "Both",
NetworkSpeedTransparentBackground,
ShowNetworkTypeIcon,
SelectedNetworkSpeedFontSize?.Value ?? "Medium",
NormalizeSpacingMode(SelectedSpacingMode.Value),
Math.Clamp(CustomSpacingPercent, 0, 30)));
Math.Clamp(CustomSpacingPercent, 0, 30),
StatusBarShadowEnabled,
StatusBarShadowColor.ToString(),
StatusBarShadowOpacity / 100.0));
}
private IReadOnlyList<SelectionOption> CreateClockFormats()
@@ -325,6 +554,26 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
];
}
private IReadOnlyList<SelectionOption> CreateNetworkSpeedPositions()
{
return
[
new SelectionOption("Left", L("settings.status_bar.network_speed_position.left", "Left")),
new SelectionOption("Center", L("settings.status_bar.network_speed_position.center", "Center")),
new SelectionOption("Right", L("settings.status_bar.network_speed_position.right", "Right"))
];
}
private IReadOnlyList<SelectionOption> CreateNetworkSpeedDisplayModes()
{
return
[
new SelectionOption("Both", L("settings.status_bar.network_speed_mode.both", "Upload + Download")),
new SelectionOption("Upload", L("settings.status_bar.network_speed_mode.upload", "Upload only")),
new SelectionOption("Download", L("settings.status_bar.network_speed_mode.download", "Download only"))
];
}
private IReadOnlyList<SelectionOption> CreateSpacingModes()
{
return
@@ -346,14 +595,27 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
ClockTransparentBackgroundLabel = L("settings.status_bar.clock_transparent_background_label", "Transparent background");
ClockTransparentBackgroundDescription = L("settings.status_bar.clock_transparent_background_desc", "Remove the capsule background and keep only the clock text.");
ClockPositionLabel = L("settings.status_bar.clock_position_label", "Clock position");
ClockFontSizeLabel = L("settings.status_bar.clock_font_size_label", "Font size");
TextCapsuleHeader = L("settings.status_bar.text_capsule_header", "Text Capsule");
TextCapsuleDescription = L("settings.status_bar.text_capsule_description", "Display custom text with Markdown support on the status bar.");
TextCapsulePositionLabel = L("settings.status_bar.text_capsule_position_label", "Text capsule position");
TextCapsuleContentLabel = L("settings.status_bar.text_capsule_content_label", "Text content (Markdown supported)");
TextCapsuleTransparentBackgroundLabel = L("settings.status_bar.text_capsule_transparent_background_label", "Transparent background");
NetworkSpeedHeader = L("settings.status_bar.network_speed_header", "Network Speed");
NetworkSpeedDescription = L("settings.status_bar.network_speed_description", "Display real-time network upload and download speed.");
NetworkSpeedPositionLabel = L("settings.status_bar.network_speed_position_label", "Network speed position");
NetworkSpeedDisplayModeLabel = L("settings.status_bar.network_speed_mode_label", "Display mode");
NetworkSpeedTransparentBackgroundLabel = L("settings.status_bar.network_speed_transparent_background_label", "Transparent background");
ShowNetworkTypeIconLabel = L("settings.status_bar.show_network_type_icon_label", "Show network type icon");
NetworkSpeedFontSizeLabel = L("settings.status_bar.network_speed_font_size_label", "Font size");
SpacingHeader = L("settings.status_bar.spacing_header", "Component Spacing");
SpacingDescription = L("settings.status_bar.spacing_desc", "Adjust spacing between status bar components.");
CustomSpacingLabel = L("settings.status_bar.spacing_custom_label", "Custom spacing (%)");
StatusBarShadowHeader = L("settings.status_bar.shadow_header", "Status Bar Shadow");
StatusBarShadowDescription = L("settings.status_bar.shadow_desc", "Add shadow effect to the status bar for better visibility.");
StatusBarShadowEnabledLabel = L("settings.status_bar.shadow_enabled_label", "Enable shadow");
StatusBarShadowColorLabel = L("settings.status_bar.shadow_color_label", "Shadow color");
StatusBarShadowOpacityLabel = L("settings.status_bar.shadow_opacity_label", "Shadow opacity");
}
private string NormalizeSpacingMode(string? value)
@@ -386,6 +648,46 @@ public sealed partial class StatusBarSettingsPageViewModel : ViewModelBase
};
}
private static string NormalizeNetworkSpeedPosition(string? value)
{
return value switch
{
_ when string.Equals(value, "Left", StringComparison.OrdinalIgnoreCase) => "Left",
_ when string.Equals(value, "Center", StringComparison.OrdinalIgnoreCase) => "Center",
_ => "Right"
};
}
private static string NormalizeNetworkSpeedDisplayMode(string? value)
{
return value switch
{
_ when string.Equals(value, "Upload", StringComparison.OrdinalIgnoreCase) => "Upload",
_ when string.Equals(value, "Download", StringComparison.OrdinalIgnoreCase) => "Download",
_ => "Both"
};
}
private static string NormalizeFontSize(string? value)
{
return value switch
{
_ when string.Equals(value, "Small", StringComparison.OrdinalIgnoreCase) => "Small",
_ when string.Equals(value, "Large", StringComparison.OrdinalIgnoreCase) => "Large",
_ => "Medium"
};
}
private IReadOnlyList<SelectionOption> CreateFontSizes()
{
return
[
new SelectionOption("Small", L("settings.status_bar.font_size.small", "Small")),
new SelectionOption("Medium", L("settings.status_bar.font_size.medium", "Medium")),
new SelectionOption("Large", L("settings.status_bar.font_size.large", "Large"))
];
}
private string L(string key, string fallback)
=> _localizationService.GetString(_languageCode, key, fallback);
}

View File

@@ -1,4 +1,4 @@
<UserControl xmlns="https://github.com/avaloniaui"
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
@@ -25,6 +25,7 @@ public partial class ClockWidget : UserControl, IDesktopComponentWidget, ITimeZo
private ClockDisplayFormat _displayFormat = ClockDisplayFormat.HourMinuteSecond;
private bool _transparentBackground;
private double _lastAppliedCellSize = 100;
private string _fontSize = "Medium"; // Small, Medium, Large
public ClockWidget()
{
@@ -72,6 +73,21 @@ public partial class ClockWidget : UserControl, IDesktopComponentWidget, ITimeZo
TransparentBackground = transparentBackground;
}
public string WidgetFontSize
{
get => _fontSize;
set
{
_fontSize = value;
ApplyCellSize(_lastAppliedCellSize);
}
}
public void SetFontSize(string fontSize)
{
WidgetFontSize = fontSize;
}
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
ClearTimeZoneService();
@@ -138,7 +154,14 @@ public partial class ClockWidget : UserControl, IDesktopComponentWidget, ITimeZo
// 3. 核心:满盈字阶 (Filled Typography)
// 使主时间文字占据容器高度的 ~68%,产生饱满的视觉张力
var mainFontSize = targetHeight * 0.68;
// 根据字体大小设置调整基础大小
var fontSizeMultiplier = _fontSize switch
{
"Small" => 0.55,
"Large" => 0.85,
_ => 0.68 // Medium (default)
};
var mainFontSize = targetHeight * fontSizeMultiplier;
MainTimeTextBlock.FontSize = mainFontSize;
MainTimeTextBlock.FontWeight = FontWeight.SemiBold;

View File

@@ -0,0 +1,72 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:fi="using:FluentIcons.Avalonia"
mc:Ignorable="d"
d:DesignWidth="160"
d:DesignHeight="48"
x:Class="LanMountainDesktop.Views.Components.NetworkSpeedWidget">
<Border x:Name="RootBorder"
Classes="surface-translucent-panel"
Padding="0"
CornerRadius="{DynamicResource DesignCornerRadiusComponent}">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="12,0">
<!-- 上传速度 -->
<StackPanel x:Name="UploadPanel"
Orientation="Horizontal"
VerticalAlignment="Center">
<TextBlock Text="↑"
FontSize="12"
Opacity="0.7"
VerticalAlignment="Center"
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"/>
<TextBlock x:Name="UploadSpeedTextBlock"
FontSize="14"
FontWeight="SemiBold"
Margin="2,0,0,0"
VerticalAlignment="Center"
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"/>
</StackPanel>
<!-- 分隔符 -->
<Rectangle x:Name="Separator"
Width="1"
Height="16"
Margin="8,0"
Opacity="0.3"
Fill="{DynamicResource AdaptiveTextSecondaryBrush}"/>
<!-- 下载速度 -->
<StackPanel x:Name="DownloadPanel"
Orientation="Horizontal"
VerticalAlignment="Center">
<TextBlock Text="↓"
FontSize="12"
Opacity="0.7"
VerticalAlignment="Center"
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"/>
<TextBlock x:Name="DownloadSpeedTextBlock"
FontSize="14"
FontWeight="SemiBold"
Margin="2,0,0,0"
VerticalAlignment="Center"
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"/>
</StackPanel>
<!-- 网络类型图标 -->
<fi:SymbolIcon x:Name="NetworkTypeIcon"
Symbol="Globe"
FontSize="14"
Margin="8,0,0,0"
Opacity="0.8"
IsVisible="False"
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"/>
</StackPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,451 @@
using System;
using System.Linq;
using System.Net.NetworkInformation;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Threading;
using FluentIcons.Avalonia;
using FluentIcons.Common;
using LanMountainDesktop.Services;
using Symbol = FluentIcons.Common.Symbol;
namespace LanMountainDesktop.Views.Components;
public partial class NetworkSpeedWidget : UserControl, IDesktopComponentWidget
{
private readonly DispatcherTimer _timer = new();
private readonly DispatcherTimer _networkTypeTimer = new();
private NetworkInterface? _selectedInterface;
private long _lastBytesReceived;
private long _lastBytesSent;
private bool _isFirstUpdate = true;
private double _lastAppliedCellSize = 100;
private bool _transparentBackground;
private string _displayMode = "Both"; // "Upload", "Download", "Both"
private bool _showNetworkTypeIcon;
private string _fontSize = "Medium"; // Small, Medium, Large
public NetworkSpeedWidget()
{
InitializeComponent();
SetupTimer();
SelectBestInterface();
UpdateDisplayMode();
UpdateNetworkTypeIcon();
}
public string DisplayMode
{
get => _displayMode;
set
{
if (_displayMode == value) return;
_displayMode = value;
UpdateDisplayMode();
}
}
public bool TransparentBackground
{
get => _transparentBackground;
set
{
if (_transparentBackground == value) return;
_transparentBackground = value;
ApplyChrome();
ApplyCellSize(_lastAppliedCellSize);
}
}
public bool ShowNetworkTypeIcon
{
get => _showNetworkTypeIcon;
set
{
if (_showNetworkTypeIcon == value) return;
_showNetworkTypeIcon = value;
UpdateNetworkTypeIcon();
}
}
public void SetDisplayMode(string mode)
{
DisplayMode = mode;
}
public void SetTransparentBackground(bool transparent)
{
TransparentBackground = transparent;
}
public void SetShowNetworkTypeIcon(bool show)
{
ShowNetworkTypeIcon = show;
}
public string WidgetFontSize
{
get => _fontSize;
set
{
_fontSize = value;
ApplyCellSize(_lastAppliedCellSize);
}
}
public void SetFontSize(string fontSize)
{
WidgetFontSize = fontSize;
}
private void SetupTimer()
{
// 网速更新定时器(每秒)
_timer.Interval = TimeSpan.FromSeconds(1);
_timer.Tick += (_, _) => UpdateSpeed();
_timer.Start();
// 网络类型检测定时器每500ms满足响应延迟要求
_networkTypeTimer.Interval = TimeSpan.FromMilliseconds(500);
_networkTypeTimer.Tick += (_, _) => UpdateNetworkTypeIcon();
_networkTypeTimer.Start();
}
private void SelectBestInterface()
{
try
{
var interfaces = NetworkInterface.GetAllNetworkInterfaces()
.Where(ni => ni.OperationalStatus == OperationalStatus.Up)
.Where(ni => ni.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.Where(ni => ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel)
.Where(ni => !ni.Description.Contains("Virtual", StringComparison.OrdinalIgnoreCase))
.Where(ni => !ni.Description.Contains("VPN", StringComparison.OrdinalIgnoreCase))
.ToList();
// 优先选择有流量的物理网卡
_selectedInterface = interfaces
.OrderByDescending(ni => ni.GetIPv4Statistics().BytesReceived + ni.GetIPv4Statistics().BytesSent)
.FirstOrDefault();
// 如果没有找到,选择第一个活动的非虚拟网卡
_selectedInterface ??= interfaces.FirstOrDefault();
if (_selectedInterface != null)
{
var stats = _selectedInterface.GetIPv4Statistics();
_lastBytesReceived = stats.BytesReceived;
_lastBytesSent = stats.BytesSent;
}
}
catch
{
// 忽略错误,下次重试
}
}
private void UpdateSpeed()
{
try
{
// 如果当前网卡不可用,尝试重新选择
if (_selectedInterface == null ||
_selectedInterface.OperationalStatus != OperationalStatus.Up)
{
SelectBestInterface();
}
if (_selectedInterface == null)
{
UploadSpeedTextBlock.Text = "--";
DownloadSpeedTextBlock.Text = "--";
return;
}
var stats = _selectedInterface.GetIPv4Statistics();
var currentBytesReceived = stats.BytesReceived;
var currentBytesSent = stats.BytesSent;
if (_isFirstUpdate)
{
_lastBytesReceived = currentBytesReceived;
_lastBytesSent = currentBytesSent;
_isFirstUpdate = false;
return;
}
// 计算速度(每秒字节数)
var downloadBytes = currentBytesReceived - _lastBytesReceived;
var uploadBytes = currentBytesSent - _lastBytesSent;
// 处理计数器重置的情况
if (downloadBytes < 0) downloadBytes = 0;
if (uploadBytes < 0) uploadBytes = 0;
UploadSpeedTextBlock.Text = FormatSpeed(uploadBytes);
DownloadSpeedTextBlock.Text = FormatSpeed(downloadBytes);
_lastBytesReceived = currentBytesReceived;
_lastBytesSent = currentBytesSent;
}
catch
{
// 错误时显示 --
UploadSpeedTextBlock.Text = "--";
DownloadSpeedTextBlock.Text = "--";
}
}
private void UpdateNetworkTypeIcon()
{
try
{
if (!_showNetworkTypeIcon || NetworkTypeIcon == null)
{
if (NetworkTypeIcon != null)
NetworkTypeIcon.IsVisible = false;
return;
}
// 获取当前活动的网络接口
var activeInterface = GetActiveNetworkInterface();
if (activeInterface == null)
{
// 无网络连接
NetworkTypeIcon.Symbol = Symbol.DismissCircle;
NetworkTypeIcon.IsVisible = true;
return;
}
// 根据网络类型设置图标
switch (activeInterface.NetworkInterfaceType)
{
case NetworkInterfaceType.Wireless80211:
// WiFi
NetworkTypeIcon.Symbol = Symbol.WiFi;
break;
case NetworkInterfaceType.Ethernet:
// 有线网络 - 检查是否是移动网络热点
if (IsLikelyMobileHotspot(activeInterface))
{
NetworkTypeIcon.Symbol = Symbol.Phone;
}
else
{
NetworkTypeIcon.Symbol = Symbol.PlugConnected;
}
break;
default:
// 其他类型,尝试根据描述判断
var symbol = GetSymbolFromDescription(activeInterface.Description);
NetworkTypeIcon.Symbol = symbol;
break;
}
NetworkTypeIcon.IsVisible = true;
}
catch
{
// 错误时隐藏图标
if (NetworkTypeIcon != null)
NetworkTypeIcon.IsVisible = false;
}
}
private NetworkInterface? GetActiveNetworkInterface()
{
try
{
// 优先使用当前选中的网卡
if (_selectedInterface != null &&
_selectedInterface.OperationalStatus == OperationalStatus.Up)
{
return _selectedInterface;
}
// 否则查找最佳网卡
var interfaces = NetworkInterface.GetAllNetworkInterfaces()
.Where(ni => ni.OperationalStatus == OperationalStatus.Up)
.Where(ni => ni.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.Where(ni => ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel)
.ToList();
// 优先返回有流量的网卡
return interfaces
.OrderByDescending(ni => ni.GetIPv4Statistics().BytesReceived + ni.GetIPv4Statistics().BytesSent)
.FirstOrDefault();
}
catch
{
return null;
}
}
private static bool IsLikelyMobileHotspot(NetworkInterface ni)
{
// 通过描述判断是否是移动热点
var desc = ni.Description.ToLowerInvariant();
return desc.Contains("mobile") ||
desc.Contains("cellular") ||
desc.Contains("phone") ||
desc.Contains("tether");
}
private static Symbol GetSymbolFromDescription(string description)
{
var desc = description.ToLowerInvariant();
if (desc.Contains("wifi") || desc.Contains("wi-fi") || desc.Contains("wireless"))
return Symbol.WiFi;
if (desc.Contains("ethernet") || desc.Contains("lan") || desc.Contains("wired"))
return Symbol.PlugConnected;
if (desc.Contains("cellular") || desc.Contains("mobile") || desc.Contains("lte") || desc.Contains("5g") || desc.Contains("4g"))
return Symbol.Phone;
if (desc.Contains("bluetooth"))
return Symbol.Bluetooth;
// 默认使用 Globe 图标
return Symbol.Globe;
}
private static string FormatSpeed(long bytesPerSecond)
{
// 根据数值大小决定显示格式始终保持3个字符宽度
// 例如: 1.23, 12.3, 123
return bytesPerSecond switch
{
>= 1024 * 1024 * 1024 => FormatWithThreeDigits(bytesPerSecond / (1024.0 * 1024.0 * 1024.0), "G"),
>= 1024 * 1024 => FormatWithThreeDigits(bytesPerSecond / (1024.0 * 1024.0), "M"),
>= 1024 => FormatWithThreeDigits(bytesPerSecond / 1024.0, "K"),
_ => FormatWithThreeDigits(bytesPerSecond, "B")
};
}
/// <summary>
/// 格式化数字始终保持3个有效数字的显示宽度
/// </summary>
private static string FormatWithThreeDigits(double value, string unit)
{
// 根据数值大小决定小数位数,确保总宽度一致
// < 10: 显示两位小数 (如 1.23)
// 10-99: 显示一位小数 (如 12.3)
// >= 100: 显示整数 (如 123)
string formatted = value switch
{
< 10 => $"{value:F2}",
< 100 => $"{value:F1}",
_ => $"{value:F0}"
};
return formatted + unit;
}
private void UpdateDisplayMode()
{
switch (_displayMode)
{
case "Upload":
UploadPanel.IsVisible = true;
DownloadPanel.IsVisible = false;
Separator.IsVisible = false;
break;
case "Download":
UploadPanel.IsVisible = false;
DownloadPanel.IsVisible = true;
Separator.IsVisible = false;
break;
case "Both":
default:
UploadPanel.IsVisible = true;
DownloadPanel.IsVisible = true;
Separator.IsVisible = true;
break;
}
}
public void ApplyCellSize(double cellSize)
{
_lastAppliedCellSize = cellSize;
// 计算组件高度:保持与任务栏核心比例一致 (0.74x)
var targetHeight = Math.Clamp(cellSize * 0.74, 34, 74);
RootBorder.Height = targetHeight;
// 主矩形统一到主题主档圆角
RootBorder.CornerRadius = ResolveUnifiedMainRectangle();
RootBorder.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
// 根据单元格大小和字体大小设置调整字体大小
var fontSizeMultiplier = _fontSize switch
{
"Small" => 0.32,
"Large" => 0.48,
_ => 0.4 // Medium (default)
};
var fontSize = Math.Clamp(targetHeight * fontSizeMultiplier, 11, 22);
UploadSpeedTextBlock.FontSize = fontSize;
DownloadSpeedTextBlock.FontSize = fontSize;
// 调整图标大小
if (NetworkTypeIcon != null)
{
NetworkTypeIcon.FontSize = Math.Clamp(targetHeight * 0.35, 10, 18);
}
// 设置最小和最大宽度
RootBorder.MinWidth = cellSize * 1.5;
RootBorder.MaxWidth = cellSize * 5;
if (_transparentBackground)
{
RootBorder.MinWidth = 0;
RootBorder.Padding = new Thickness(Math.Clamp(cellSize * 0.06, 4, 10), 0);
return;
}
// 确保清除可能存在的固定 Padding由代码控制"紧密感"
RootBorder.Padding = new Thickness(Math.Clamp(cellSize * 0.15, 12, 24), 0);
}
private void ApplyChrome()
{
if (_transparentBackground)
{
RootBorder.Classes.Remove("glass-panel");
RootBorder.Background = Brushes.Transparent;
RootBorder.BorderBrush = Brushes.Transparent;
RootBorder.BorderThickness = new Thickness(0);
RootBorder.BoxShadow = default;
return;
}
if (!RootBorder.Classes.Contains("glass-panel"))
{
RootBorder.Classes.Add("glass-panel");
}
RootBorder.ClearValue(Border.BackgroundProperty);
RootBorder.ClearValue(Border.BorderBrushProperty);
RootBorder.ClearValue(Border.BorderThicknessProperty);
RootBorder.ClearValue(Border.BoxShadowProperty);
}
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
private static double ResolveUnifiedMainRadiusValue() =>
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
_timer?.Stop();
_networkTypeTimer?.Stop();
}
}

View File

@@ -365,14 +365,29 @@ public partial class MainWindow
: ClockDisplayFormat.HourMinuteSecond;
_statusBarClockTransparentBackground = snapshot.StatusBarClockTransparentBackground;
_clockPosition = NormalizeClockPosition(snapshot.ClockPosition);
_clockFontSize = NormalizeFontSize(snapshot.ClockFontSize);
_showTextCapsule = snapshot.ShowTextCapsule;
_textCapsuleContent = snapshot.TextCapsuleContent ?? "**Hello** World!";
_textCapsulePosition = NormalizeTextCapsulePosition(snapshot.TextCapsulePosition);
_textCapsuleTransparentBackground = snapshot.TextCapsuleTransparentBackground;
_textCapsuleFontSize = NormalizeFontSize(snapshot.TextCapsuleFontSize);
_showNetworkSpeed = snapshot.ShowNetworkSpeed;
_networkSpeedPosition = NormalizeNetworkSpeedPosition(snapshot.NetworkSpeedPosition);
_networkSpeedDisplayMode = NormalizeNetworkSpeedDisplayMode(snapshot.NetworkSpeedDisplayMode);
_networkSpeedTransparentBackground = snapshot.NetworkSpeedTransparentBackground;
_showNetworkTypeIcon = snapshot.ShowNetworkTypeIcon;
_networkSpeedFontSize = NormalizeFontSize(snapshot.NetworkSpeedFontSize);
_statusBarShadowEnabled = snapshot.StatusBarShadowEnabled;
_statusBarShadowColor = snapshot.StatusBarShadowColor ?? "#000000";
_statusBarShadowOpacity = snapshot.StatusBarShadowOpacity;
ApplyClockSettingsToAllWidgets();
ApplyTextCapsuleSettingsToAllWidgets();
ApplyNetworkSpeedSettingsToAllWidgets();
ApplyStatusBarShadow();
}
private void ApplyClockSettingsToAllWidgets()
@@ -381,16 +396,19 @@ public partial class MainWindow
{
ClockWidgetLeft.SetDisplayFormat(_clockDisplayFormat);
ClockWidgetLeft.SetTransparentBackground(_statusBarClockTransparentBackground);
ClockWidgetLeft.SetFontSize(_clockFontSize);
}
if (ClockWidgetCenter is not null)
{
ClockWidgetCenter.SetDisplayFormat(_clockDisplayFormat);
ClockWidgetCenter.SetTransparentBackground(_statusBarClockTransparentBackground);
ClockWidgetCenter.SetFontSize(_clockFontSize);
}
if (ClockWidgetRight is not null)
{
ClockWidgetRight.SetDisplayFormat(_clockDisplayFormat);
ClockWidgetRight.SetTransparentBackground(_statusBarClockTransparentBackground);
ClockWidgetRight.SetFontSize(_clockFontSize);
}
}
@@ -404,6 +422,16 @@ public partial class MainWindow
};
}
private static string NormalizeFontSize(string? value)
{
return value switch
{
_ when string.Equals(value, "Small", StringComparison.OrdinalIgnoreCase) => "Small",
_ when string.Equals(value, "Large", StringComparison.OrdinalIgnoreCase) => "Large",
_ => "Medium"
};
}
private void ApplyTextCapsuleSettingsToAllWidgets()
{
if (TextCapsuleWidgetLeft is not null)
@@ -433,6 +461,90 @@ public partial class MainWindow
};
}
private void ApplyNetworkSpeedSettingsToAllWidgets()
{
if (NetworkSpeedWidgetLeft is not null)
{
NetworkSpeedWidgetLeft.SetDisplayMode(_networkSpeedDisplayMode);
NetworkSpeedWidgetLeft.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetLeft.SetShowNetworkTypeIcon(_showNetworkTypeIcon);
NetworkSpeedWidgetLeft.SetFontSize(_networkSpeedFontSize);
}
if (NetworkSpeedWidgetCenter is not null)
{
NetworkSpeedWidgetCenter.SetDisplayMode(_networkSpeedDisplayMode);
NetworkSpeedWidgetCenter.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetCenter.SetShowNetworkTypeIcon(_showNetworkTypeIcon);
NetworkSpeedWidgetCenter.SetFontSize(_networkSpeedFontSize);
}
if (NetworkSpeedWidgetRight is not null)
{
NetworkSpeedWidgetRight.SetDisplayMode(_networkSpeedDisplayMode);
NetworkSpeedWidgetRight.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetRight.SetShowNetworkTypeIcon(_showNetworkTypeIcon);
NetworkSpeedWidgetRight.SetFontSize(_networkSpeedFontSize);
}
}
private static string NormalizeNetworkSpeedPosition(string? value)
{
return value switch
{
_ when string.Equals(value, "Left", StringComparison.OrdinalIgnoreCase) => "Left",
_ when string.Equals(value, "Center", StringComparison.OrdinalIgnoreCase) => "Center",
_ => "Right"
};
}
private static string NormalizeNetworkSpeedDisplayMode(string? value)
{
return value switch
{
_ when string.Equals(value, "Upload", StringComparison.OrdinalIgnoreCase) => "Upload",
_ when string.Equals(value, "Download", StringComparison.OrdinalIgnoreCase) => "Download",
_ => "Both"
};
}
private void ApplyStatusBarShadow()
{
if (StatusBarOverlay is null)
{
return;
}
if (_statusBarShadowEnabled)
{
if (Color.TryParse(_statusBarShadowColor, out var shadowColor))
{
var opacity = Math.Clamp(_statusBarShadowOpacity, 0, 1);
StatusBarOverlay.IsVisible = true;
var gradientBrush = new LinearGradientBrush
{
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative)
};
var alpha1 = (byte)(shadowColor.A * opacity * 0.8);
var alpha2 = (byte)(shadowColor.A * opacity * 0.4);
var color1 = Color.FromArgb(alpha1, shadowColor.R, shadowColor.G, shadowColor.B);
var color2 = Color.FromArgb(alpha2, shadowColor.R, shadowColor.G, shadowColor.B);
gradientBrush.GradientStops.Add(new GradientStop(color1, 0.0));
gradientBrush.GradientStops.Add(new GradientStop(color2, 0.3));
gradientBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 1.0));
StatusBarOverlay.Background = gradientBrush;
}
}
else
{
StatusBarOverlay.IsVisible = false;
}
}
/// <summary>
/// 检测状态栏组件是否会发生碰撞
/// </summary>
@@ -676,6 +788,14 @@ public partial class MainWindow
if (TextCapsuleWidgetRight is not null)
TextCapsuleWidgetRight.IsVisible = false;
// 先隐藏所有网速控件
if (NetworkSpeedWidgetLeft is not null)
NetworkSpeedWidgetLeft.IsVisible = false;
if (NetworkSpeedWidgetCenter is not null)
NetworkSpeedWidgetCenter.IsVisible = false;
if (NetworkSpeedWidgetRight is not null)
NetworkSpeedWidgetRight.IsVisible = false;
// 根据位置设置显示对应的时钟控件(带碰撞检测)
if (showClock)
{
@@ -770,6 +890,53 @@ public partial class MainWindow
}
}
// 根据位置设置显示对应的网速控件(带碰撞检测)
if (_showNetworkSpeed)
{
var targetPosition = _networkSpeedPosition;
var canAdd = CanAddComponentAtPosition(targetPosition);
if (canAdd)
{
var targetNetworkSpeed = targetPosition switch
{
"Left" => NetworkSpeedWidgetLeft,
"Center" => NetworkSpeedWidgetCenter,
_ => NetworkSpeedWidgetRight
};
if (targetNetworkSpeed is not null)
{
targetNetworkSpeed.IsVisible = true;
targetNetworkSpeed.SetTransparentBackground(_networkSpeedTransparentBackground);
targetNetworkSpeed.SetDisplayMode(_networkSpeedDisplayMode);
hasVisibleTopStatusComponent = true;
}
}
else
{
// 如果目标位置无法添加,尝试其他位置
var alternativePosition = FindAlternativePosition(targetPosition);
if (alternativePosition is not null)
{
var targetNetworkSpeed = alternativePosition switch
{
"Left" => NetworkSpeedWidgetLeft,
"Center" => NetworkSpeedWidgetCenter,
_ => NetworkSpeedWidgetRight
};
if (targetNetworkSpeed is not null)
{
targetNetworkSpeed.IsVisible = true;
targetNetworkSpeed.SetTransparentBackground(_networkSpeedTransparentBackground);
targetNetworkSpeed.SetDisplayMode(_networkSpeedDisplayMode);
hasVisibleTopStatusComponent = true;
}
}
}
}
if (TopStatusBarHost is not null)
{
TopStatusBarHost.IsVisible = hasVisibleTopStatusComponent;
@@ -871,6 +1038,82 @@ public partial class MainWindow
TextCapsuleWidgetCenter.IsVisible = false;
}
}
// 调整网速组件位置(优先级:时钟 > 文字胶囊 > 网速)
if (NetworkSpeedWidgetLeft?.IsVisible == true && WouldComponentsCollide())
{
// 尝试将左侧网速移到中间
if (CanAddComponentAtPosition("Center"))
{
NetworkSpeedWidgetLeft.IsVisible = false;
NetworkSpeedWidgetCenter!.IsVisible = true;
NetworkSpeedWidgetCenter.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetCenter.SetDisplayMode(_networkSpeedDisplayMode);
}
// 或者移到右侧
else if (CanAddComponentAtPosition("Right"))
{
NetworkSpeedWidgetLeft.IsVisible = false;
NetworkSpeedWidgetRight!.IsVisible = true;
NetworkSpeedWidgetRight.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetRight.SetDisplayMode(_networkSpeedDisplayMode);
}
// 如果都无法添加,则隐藏网速
else
{
NetworkSpeedWidgetLeft.IsVisible = false;
}
}
if (NetworkSpeedWidgetRight?.IsVisible == true && WouldComponentsCollide())
{
// 尝试将右侧网速移到中间
if (CanAddComponentAtPosition("Center"))
{
NetworkSpeedWidgetRight.IsVisible = false;
NetworkSpeedWidgetCenter!.IsVisible = true;
NetworkSpeedWidgetCenter.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetCenter.SetDisplayMode(_networkSpeedDisplayMode);
}
// 或者移到左侧
else if (CanAddComponentAtPosition("Left"))
{
NetworkSpeedWidgetRight.IsVisible = false;
NetworkSpeedWidgetLeft!.IsVisible = true;
NetworkSpeedWidgetLeft.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetLeft.SetDisplayMode(_networkSpeedDisplayMode);
}
// 如果都无法添加,则隐藏网速
else
{
NetworkSpeedWidgetRight.IsVisible = false;
}
}
if (NetworkSpeedWidgetCenter?.IsVisible == true && WouldComponentsCollide())
{
// 尝试将中间网速移到左侧
if (CanAddComponentAtPosition("Left"))
{
NetworkSpeedWidgetCenter.IsVisible = false;
NetworkSpeedWidgetLeft!.IsVisible = true;
NetworkSpeedWidgetLeft.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetLeft.SetDisplayMode(_networkSpeedDisplayMode);
}
// 或者移到右侧
else if (CanAddComponentAtPosition("Right"))
{
NetworkSpeedWidgetCenter.IsVisible = false;
NetworkSpeedWidgetRight!.IsVisible = true;
NetworkSpeedWidgetRight.SetTransparentBackground(_networkSpeedTransparentBackground);
NetworkSpeedWidgetRight.SetDisplayMode(_networkSpeedDisplayMode);
}
// 如果都无法添加,则隐藏网速
else
{
NetworkSpeedWidgetCenter.IsVisible = false;
}
}
}
/// <summary>

View File

@@ -650,8 +650,24 @@ public partial class MainWindow
TaskbarLayoutMode = _taskbarLayoutMode,
ClockDisplayFormat = _clockDisplayFormat == ClockDisplayFormat.HourMinute ? "HourMinute" : "HourMinuteSecond",
StatusBarClockTransparentBackground = _statusBarClockTransparentBackground,
ClockPosition = _clockPosition,
ClockFontSize = _clockFontSize,
ShowTextCapsule = _showTextCapsule,
TextCapsuleContent = _textCapsuleContent,
TextCapsulePosition = _textCapsulePosition,
TextCapsuleTransparentBackground = _textCapsuleTransparentBackground,
TextCapsuleFontSize = _textCapsuleFontSize,
ShowNetworkSpeed = _showNetworkSpeed,
NetworkSpeedPosition = _networkSpeedPosition,
NetworkSpeedDisplayMode = _networkSpeedDisplayMode,
NetworkSpeedTransparentBackground = _networkSpeedTransparentBackground,
ShowNetworkTypeIcon = _showNetworkTypeIcon,
NetworkSpeedFontSize = _networkSpeedFontSize,
StatusBarSpacingMode = _statusBarSpacingMode,
StatusBarCustomSpacingPercent = _statusBarCustomSpacingPercent,
StatusBarShadowEnabled = _statusBarShadowEnabled,
StatusBarShadowColor = _statusBarShadowColor,
StatusBarShadowOpacity = _statusBarShadowOpacity,
DisabledPluginIds = existingSnapshot.DisabledPluginIds,
StudyFrameMs = existingSnapshot.StudyFrameMs,
StudyScoreThresholdDbfs = existingSnapshot.StudyScoreThresholdDbfs,

View File

@@ -226,13 +226,34 @@
</Grid>
</Border>
<!-- 状态栏阴影层 - macOS 风格的完整阴影带 -->
<Border x:Name="StatusBarOverlay"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="1"
IsVisible="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Height="24"
ZIndex="0"
Margin="0,0,0,-24">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Color="#CC000000" Offset="0.0" />
<GradientStop Color="#66000000" Offset="0.3" />
<GradientStop Color="#00000000" Offset="1.0" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="TopStatusBarHost"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="1"
Background="Transparent"
BorderThickness="0"
Padding="4">
Padding="4"
ZIndex="2">
<Grid ColumnDefinitions="*,Auto,*">
<!-- 左侧状态栏组件 -->
<StackPanel x:Name="TopStatusLeftPanel"
@@ -246,6 +267,9 @@
<comp:TextCapsuleWidget x:Name="TextCapsuleWidgetLeft"
IsVisible="False"
Margin="0" />
<comp:NetworkSpeedWidget x:Name="NetworkSpeedWidgetLeft"
IsVisible="False"
Margin="0" />
</StackPanel>
<!-- 中间状态栏组件 -->
<StackPanel x:Name="TopStatusCenterPanel"
@@ -259,6 +283,9 @@
<comp:TextCapsuleWidget x:Name="TextCapsuleWidgetCenter"
IsVisible="False"
Margin="0" />
<comp:NetworkSpeedWidget x:Name="NetworkSpeedWidgetCenter"
IsVisible="False"
Margin="0" />
</StackPanel>
<!-- 右侧状态栏组件 -->
<StackPanel x:Name="TopStatusRightPanel"
@@ -272,6 +299,9 @@
<comp:TextCapsuleWidget x:Name="TextCapsuleWidgetRight"
IsVisible="False"
Margin="0" />
<comp:NetworkSpeedWidget x:Name="NetworkSpeedWidgetRight"
IsVisible="False"
Margin="0" />
</StackPanel>
</Grid>
</Border>

View File

@@ -136,10 +136,21 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
private int _statusBarCustomSpacingPercent = 12;
private bool _statusBarClockTransparentBackground;
private string _clockPosition = "Left"; // Left, Center, Right
private string _clockFontSize = "Medium"; // Small, Medium, Large
private bool _showTextCapsule;
private string _textCapsuleContent = "**Hello** World!";
private string _textCapsulePosition = "Right"; // Left, Center, Right
private bool _textCapsuleTransparentBackground;
private string _textCapsuleFontSize = "Medium"; // Small, Medium, Large
private bool _showNetworkSpeed;
private string _networkSpeedPosition = "Right"; // Left, Center, Right
private string _networkSpeedDisplayMode = "Both"; // Upload, Download, Both
private bool _networkSpeedTransparentBackground;
private bool _showNetworkTypeIcon;
private string _networkSpeedFontSize = "Medium"; // Small, Medium, Large
private bool _statusBarShadowEnabled;
private string _statusBarShadowColor = "#000000";
private double _statusBarShadowOpacity = 0.3;
private int _desktopEdgeInsetPercent = DefaultEdgeInsetPercent;
private string _taskbarLayoutMode = TaskbarLayoutBottomFullRowMacStyle;
private string _languageCode = "zh-CN";
@@ -720,6 +731,13 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
TextCapsuleWidgetRight.Margin = new Thickness(0);
TextCapsuleWidgetRight.ApplyCellSize(cellSize);
NetworkSpeedWidgetLeft.Margin = new Thickness(0);
NetworkSpeedWidgetLeft.ApplyCellSize(cellSize);
NetworkSpeedWidgetCenter.Margin = new Thickness(0);
NetworkSpeedWidgetCenter.ApplyCellSize(cellSize);
NetworkSpeedWidgetRight.Margin = new Thickness(0);
NetworkSpeedWidgetRight.ApplyCellSize(cellSize);
var buttonMinWidth = Math.Clamp(taskbarCellHeight * 2.35, 100, 340);
BackToWindowsButton.Margin = new Thickness(0);
@@ -763,6 +781,9 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
TextCapsuleWidgetLeft.ApplyCellSize(_currentDesktopCellSize);
TextCapsuleWidgetCenter.ApplyCellSize(_currentDesktopCellSize);
TextCapsuleWidgetRight.ApplyCellSize(_currentDesktopCellSize);
NetworkSpeedWidgetLeft.ApplyCellSize(_currentDesktopCellSize);
NetworkSpeedWidgetCenter.ApplyCellSize(_currentDesktopCellSize);
NetworkSpeedWidgetRight.ApplyCellSize(_currentDesktopCellSize);
}
}

View File

@@ -70,6 +70,24 @@
</ComboBox>
</Grid>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="16">
<TextBlock Text="{Binding ClockFontSizeLabel}"
VerticalAlignment="Center" />
<ComboBox Grid.Column="1"
Width="220"
IsEnabled="{Binding ShowClock}"
ItemsSource="{Binding ClockFontSizes}"
SelectedItem="{Binding SelectedClockFontSize}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</ui:SettingsExpanderItem>
</ui:SettingsExpander>
<ui:SettingsExpander Header="{Binding TextCapsuleHeader}"
@@ -126,6 +144,92 @@
</ui:SettingsExpanderItem>
</ui:SettingsExpander>
<ui:SettingsExpander Header="{Binding NetworkSpeedHeader}"
Description="{Binding NetworkSpeedDescription}">
<ui:SettingsExpander.IconSource>
<fi:SymbolIconSource Symbol="ArrowBidirectionalUpDown" />
</ui:SettingsExpander.IconSource>
<ui:SettingsExpander.Footer>
<ToggleSwitch IsChecked="{Binding ShowNetworkSpeed}" />
</ui:SettingsExpander.Footer>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="16">
<TextBlock Text="{Binding NetworkSpeedPositionLabel}"
VerticalAlignment="Center" />
<ComboBox Grid.Column="1"
Width="220"
IsEnabled="{Binding ShowNetworkSpeed}"
ItemsSource="{Binding NetworkSpeedPositions}"
SelectedItem="{Binding SelectedNetworkSpeedPosition}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="16">
<TextBlock Text="{Binding NetworkSpeedDisplayModeLabel}"
VerticalAlignment="Center" />
<ComboBox Grid.Column="1"
Width="220"
IsEnabled="{Binding ShowNetworkSpeed}"
ItemsSource="{Binding NetworkSpeedDisplayModes}"
SelectedItem="{Binding SelectedNetworkSpeedDisplayMode}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="*,Auto"
ColumnSpacing="16">
<TextBlock Text="{Binding NetworkSpeedTransparentBackgroundLabel}"
VerticalAlignment="Center" />
<ToggleSwitch Grid.Column="1"
IsChecked="{Binding NetworkSpeedTransparentBackground}"
IsEnabled="{Binding ShowNetworkSpeed}"
VerticalAlignment="Center" />
</Grid>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="*,Auto"
ColumnSpacing="16">
<TextBlock Text="{Binding ShowNetworkTypeIconLabel}"
VerticalAlignment="Center" />
<ToggleSwitch Grid.Column="1"
IsChecked="{Binding ShowNetworkTypeIcon}"
IsEnabled="{Binding ShowNetworkSpeed}"
VerticalAlignment="Center" />
</Grid>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="16">
<TextBlock Text="{Binding NetworkSpeedFontSizeLabel}"
VerticalAlignment="Center" />
<ComboBox Grid.Column="1"
Width="220"
IsEnabled="{Binding ShowNetworkSpeed}"
ItemsSource="{Binding NetworkSpeedFontSizes}"
SelectedItem="{Binding SelectedNetworkSpeedFontSize}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</ui:SettingsExpanderItem>
</ui:SettingsExpander>
<Separator Classes="settings-separator" />
<controls:IconText Icon="Apps"
@@ -164,6 +268,55 @@
</Grid>
</ui:SettingsExpanderItem>
</ui:SettingsExpander>
<Separator Classes="settings-separator" />
<controls:IconText Icon="Square"
Text="{Binding StatusBarShadowHeader}"
Margin="0,0,0,4" />
<ui:SettingsExpander Header="{Binding StatusBarShadowHeader}"
Description="{Binding StatusBarShadowDescription}">
<ui:SettingsExpander.IconSource>
<fi:SymbolIconSource Symbol="Square" />
</ui:SettingsExpander.IconSource>
<ui:SettingsExpander.Footer>
<ToggleSwitch IsChecked="{Binding StatusBarShadowEnabled}" />
</ui:SettingsExpander.Footer>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="16">
<TextBlock Text="{Binding StatusBarShadowColorLabel}"
VerticalAlignment="Center" />
<Button Grid.Column="1"
HorizontalAlignment="Right"
IsEnabled="{Binding StatusBarShadowEnabled}">
<Border Width="32"
Height="32"
CornerRadius="4"
Background="{Binding StatusBarShadowColorBrush}" />
<Button.Flyout>
<Flyout Placement="BottomEdgeAlignedRight">
<ColorPicker Color="{Binding StatusBarShadowColor}" />
</Flyout>
</Button.Flyout>
</Button>
</Grid>
</ui:SettingsExpanderItem>
<ui:SettingsExpanderItem>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="16">
<TextBlock Text="{Binding StatusBarShadowOpacityLabel}"
VerticalAlignment="Center" />
<Slider Grid.Column="1"
Minimum="0"
Maximum="100"
TickFrequency="10"
IsEnabled="{Binding StatusBarShadowEnabled}"
Value="{Binding StatusBarShadowOpacity}" />
</Grid>
</ui:SettingsExpanderItem>
</ui:SettingsExpander>
</StackPanel>
</ScrollViewer>
</UserControl>