mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
130 lines
3.8 KiB
C#
130 lines
3.8 KiB
C#
using System;
|
||
using System.Globalization;
|
||
using Avalonia;
|
||
using Avalonia.Controls;
|
||
using Avalonia.Media;
|
||
using Avalonia.Threading;
|
||
using LanMontainDesktop.Services;
|
||
|
||
namespace LanMontainDesktop.Views.Components;
|
||
|
||
public enum ClockDisplayFormat
|
||
{
|
||
HourMinuteSecond, // HH:mm:ss
|
||
HourMinute // HH:mm
|
||
}
|
||
|
||
public partial class ClockWidget : UserControl
|
||
{
|
||
private readonly DispatcherTimer _timer = new()
|
||
{
|
||
Interval = TimeSpan.FromSeconds(1)
|
||
};
|
||
|
||
private TimeZoneService? _timeZoneService;
|
||
private ClockDisplayFormat _displayFormat = ClockDisplayFormat.HourMinuteSecond;
|
||
|
||
public ClockWidget()
|
||
{
|
||
InitializeComponent();
|
||
|
||
_timer.Tick += OnTimerTick;
|
||
AttachedToVisualTree += OnAttachedToVisualTree;
|
||
DetachedFromVisualTree += OnDetachedFromVisualTree;
|
||
UpdateClock();
|
||
}
|
||
|
||
public ClockDisplayFormat DisplayFormat
|
||
{
|
||
get => _displayFormat;
|
||
set
|
||
{
|
||
_displayFormat = value;
|
||
UpdateClock();
|
||
}
|
||
}
|
||
|
||
public void SetDisplayFormat(ClockDisplayFormat format)
|
||
{
|
||
DisplayFormat = format;
|
||
}
|
||
|
||
public void SetTimeZoneService(TimeZoneService timeZoneService)
|
||
{
|
||
if (_timeZoneService != null)
|
||
{
|
||
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
|
||
}
|
||
|
||
_timeZoneService = timeZoneService;
|
||
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
|
||
UpdateClock();
|
||
}
|
||
|
||
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
|
||
{
|
||
UpdateClock();
|
||
_timer.Start();
|
||
}
|
||
|
||
private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
|
||
{
|
||
_timer.Stop();
|
||
}
|
||
|
||
private void OnTimerTick(object? sender, EventArgs e)
|
||
{
|
||
UpdateClock();
|
||
}
|
||
|
||
private void OnTimeZoneChanged(object? sender, EventArgs e)
|
||
{
|
||
UpdateClock();
|
||
}
|
||
|
||
private void UpdateClock()
|
||
{
|
||
var now = _timeZoneService?.GetCurrentTime() ?? DateTime.Now;
|
||
|
||
MainTimeTextBlock.Text = now.ToString("HH:mm", CultureInfo.CurrentCulture);
|
||
SecondsTextBlock.Text = now.ToString("ss", CultureInfo.CurrentCulture);
|
||
|
||
SecondsTextBlock.IsVisible = _displayFormat == ClockDisplayFormat.HourMinuteSecond;
|
||
}
|
||
|
||
public void ApplyCellSize(double cellSize)
|
||
{
|
||
// --- Class Island “满盈”风格算法 ---
|
||
|
||
// 1. 计算组件高度:保持与任务栏核心比例一致 (0.74x)
|
||
var targetHeight = Math.Clamp(cellSize * 0.74, 34, 74);
|
||
RootBorder.Height = targetHeight;
|
||
|
||
// 2. 动态圆角:确保始终是完美的胶囊半圆
|
||
RootBorder.CornerRadius = new CornerRadius(targetHeight / 2);
|
||
RootBorder.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
||
|
||
// 3. 核心:满盈字阶 (Filled Typography)
|
||
// 使主时间文字占据容器高度的 ~68%,产生饱满的视觉张力
|
||
var mainFontSize = targetHeight * 0.68;
|
||
MainTimeTextBlock.FontSize = mainFontSize;
|
||
MainTimeTextBlock.FontWeight = FontWeight.SemiBold;
|
||
|
||
// 4. 次级信息:秒数维持 0.7x 比例,并增强透明度呼吸感
|
||
SecondsTextBlock.FontSize = mainFontSize * 0.7;
|
||
SecondsTextBlock.Opacity = 0.55;
|
||
|
||
// 5. 视觉占比:占据约 2.2 个单元格的感官宽度 (cellSize * 2 + gaps)
|
||
RootBorder.MinWidth = cellSize * 2.2;
|
||
|
||
// 6. 间距微调
|
||
if (MainTimeTextBlock.Parent is StackPanel panel)
|
||
{
|
||
panel.Spacing = Math.Clamp(cellSize * 0.06, 2, 8);
|
||
}
|
||
|
||
// 确保清除可能存在的固定 Padding,由代码控制“紧密感”
|
||
RootBorder.Padding = new Thickness(Math.Clamp(cellSize * 0.15, 12, 24), 0);
|
||
}
|
||
}
|