Add WinUI and core source
build-winui / winui (push) Has been cancelled

This commit is contained in:
QWQLwToo
2026-06-26 13:27:13 +08:00
parent f59190251d
commit 7ecc6a8923
262 changed files with 137492 additions and 0 deletions
@@ -0,0 +1,268 @@
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Media;
using YMhut.Box.Core.Settings;
using YMhut.Box.WinUI.Services;
namespace YMhut.Box.WinUI.Controls;
public sealed class WeatherCapsuleControl : UserControl
{
private readonly ITitleWeatherService _weatherService;
private readonly ISettingsService _settingsService = AppServices.GetRequiredService<ISettingsService>();
private readonly Button _button;
private readonly AnimatedWeatherIconControl _weatherIcon;
private readonly ProgressRing _loadingRing;
private readonly TextBlock _locationText;
private readonly TextBlock _tempText;
private readonly TextBlock _conditionText;
private readonly Flyout _flyout;
private TitleWeatherSnapshot _snapshot = TitleWeatherSnapshot.Loading;
private TitleWeatherSnapshot? _lastAvailableSnapshot;
private int _loadVersion;
public WeatherCapsuleControl(ITitleWeatherService weatherService)
{
_weatherService = weatherService;
HorizontalAlignment = HorizontalAlignment.Right;
VerticalAlignment = VerticalAlignment.Center;
_weatherIcon = new AnimatedWeatherIconControl(20)
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
_loadingRing = new ProgressRing
{
Width = 18,
Height = 18,
IsActive = true,
Visibility = Visibility.Collapsed
};
_locationText = ModernUi.Text(_snapshot.Location, 12, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1);
_conditionText = ModernUi.Text(_snapshot.Condition, 10.5, foreground: ModernUi.TextSecondary, maxLines: 1);
_tempText = ModernUi.Text(_snapshot.TemperatureText, 15, FontWeights.SemiBold, ModernUi.TextPrimary, maxLines: 1);
ConfigureCompactLine(_locationText, 14);
ConfigureCompactLine(_conditionText, 13);
ConfigureCompactLine(_tempText, 18);
var visual = new Grid
{
ColumnSpacing = 9,
VerticalAlignment = VerticalAlignment.Center,
ColumnDefinitions =
{
new ColumnDefinition { Width = GridLength.Auto },
new ColumnDefinition(),
new ColumnDefinition { Width = GridLength.Auto }
}
};
var iconHost = new Grid { Width = 22, Height = 22, Children = { _weatherIcon, _loadingRing } };
visual.Children.Add(iconHost);
var text = new Grid
{
MinWidth = 76,
MaxWidth = 130,
VerticalAlignment = VerticalAlignment.Center,
RowDefinitions =
{
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto }
}
};
text.Children.Add(_locationText);
Grid.SetRow(_conditionText, 1);
text.Children.Add(_conditionText);
Grid.SetColumn(text, 1);
visual.Children.Add(text);
Grid.SetColumn(_tempText, 2);
visual.Children.Add(_tempText);
_flyout = new Flyout { Placement = FlyoutPlacementMode.BottomEdgeAlignedRight };
_flyout.Opening += (_, _) => _flyout.Content = BuildFlyoutContent();
_button = new Button
{
Height = 38,
MinWidth = 168,
MaxWidth = 242,
Margin = new Thickness(0, 4, 0, 4),
Padding = new Thickness(12, 4, 12, 4),
CornerRadius = new CornerRadius(19),
Background = ModernUi.Surface,
BorderBrush = ModernUi.Stroke,
BorderThickness = new Thickness(1),
Content = visual,
Flyout = _flyout
};
AutomationProperties.SetName(_button, AppLocalizer.T("天气", "Weather"));
ToolTipService.SetToolTip(_button, AppLocalizer.T("查看天气详情", "Show weather details"));
Content = _button;
ApplySnapshot(_snapshot);
}
public async Task LoadAsync(CancellationToken cancellationToken = default)
{
await RefreshAsync(cancellationToken).ConfigureAwait(false);
}
public async Task RefreshAsync(CancellationToken cancellationToken = default)
{
var loadVersion = Interlocked.Increment(ref _loadVersion);
DispatcherQueue.TryEnqueue(() => ApplySnapshot(TitleWeatherSnapshot.Loading, loadingOverlay: true));
var snapshot = await _weatherService.GetCurrentAsync(cancellationToken).ConfigureAwait(false);
if (loadVersion != _loadVersion)
{
return;
}
DispatcherQueue.TryEnqueue(() => ApplySnapshot(snapshot));
}
public void RefreshLanguage()
{
ApplySnapshot(_snapshot);
}
private void ApplySnapshot(TitleWeatherSnapshot snapshot, bool loadingOverlay = false)
{
var displaySnapshot = loadingOverlay && _lastAvailableSnapshot is not null
? _lastAvailableSnapshot
: snapshot;
_snapshot = displaySnapshot;
if (displaySnapshot.IsAvailable)
{
_lastAvailableSnapshot = displaySnapshot;
}
var loading = loadingOverlay || ReferenceEquals(snapshot, TitleWeatherSnapshot.Loading);
_loadingRing.IsActive = loading;
_loadingRing.Visibility = loading ? Visibility.Visible : Visibility.Collapsed;
_loadingRing.Opacity = loading ? 0.78 : 0;
_weatherIcon.Visibility = Visibility.Visible;
_weatherIcon.Opacity = loading ? 0.62 : 1;
_weatherIcon.Update(displaySnapshot, _settingsService.Current.AnimationsEnabled);
_locationText.Text = displaySnapshot.Location;
_conditionText.Text = displaySnapshot.Condition;
_tempText.Text = displaySnapshot.TemperatureText;
_button.Background = displaySnapshot.IsAvailable ? ModernUi.Surface : ModernUi.SurfaceAlt;
_button.BorderBrush = displaySnapshot.IsAvailable ? ModernUi.Stroke : ModernUi.StrokeStrong;
ToolTipService.SetToolTip(_button, loading ? AppLocalizer.T("天气正在刷新", "Weather is refreshing") : BuildTooltip(displaySnapshot));
AutomationProperties.SetName(_button, loading ? AppLocalizer.T("天气正在刷新", "Weather is refreshing") : BuildTooltip(displaySnapshot));
}
private string BuildTooltip(TitleWeatherSnapshot snapshot)
{
return snapshot.IsAvailable
? $"{snapshot.Location} {snapshot.Condition} {snapshot.TemperatureText}"
: AppLocalizer.T("天气暂不可用,点击重试", "Weather unavailable. Click to retry.");
}
private UIElement BuildFlyoutContent()
{
var snapshot = _snapshot;
var refresh = ModernUi.PillButton(AppLocalizer.T("刷新", "Refresh"), "\uE72C", async () => await RefreshAsync(), primary: true);
refresh.HorizontalAlignment = HorizontalAlignment.Right;
Grid.SetColumn(refresh, 2);
return new StackPanel
{
Width = 280,
Padding = new Thickness(4),
Spacing = 12,
Children =
{
new Grid
{
ColumnSpacing = 12,
ColumnDefinitions =
{
new ColumnDefinition { Width = GridLength.Auto },
new ColumnDefinition(),
new ColumnDefinition { Width = GridLength.Auto }
},
Children =
{
BuildFlyoutIcon(snapshot),
BuildTitleBlock(snapshot),
refresh
}
},
BuildDetailLine(AppLocalizer.T("体感", "Feels like"), snapshot.FeelsLikeText, "\uE706"),
BuildDetailLine(AppLocalizer.T("湿度", "Humidity"), snapshot.HumidityText, "\uE81F"),
BuildDetailLine(AppLocalizer.T("风速", "Wind"), snapshot.WindText, "\uE9CA"),
BuildDetailLine(AppLocalizer.T("今日温度", "Today"), snapshot.RangeText, "\uE787"),
BuildDetailLine(AppLocalizer.T("更新时间", "Updated"), snapshot.UpdatedText, "\uE823"),
snapshot.ErrorMessage is null
? new Border { Height = 0 }
: ModernUi.Card(
ModernUi.Text(snapshot.ErrorMessage, 12, foreground: ModernUi.TextSecondary, maxLines: 3),
new Thickness(10),
radius: 8,
background: ModernUi.SurfaceAlt)
}
};
}
private static StackPanel BuildTitleBlock(TitleWeatherSnapshot snapshot)
{
var panel = new StackPanel
{
Spacing = 1,
VerticalAlignment = VerticalAlignment.Center,
Children =
{
ModernUi.Text(snapshot.Location, 17, FontWeights.SemiBold, maxLines: 1),
ModernUi.Text($"{snapshot.Condition} · {snapshot.TemperatureText} · {snapshot.QueryLevel}", 13, foreground: ModernUi.TextSecondary, maxLines: 1)
}
};
Grid.SetColumn(panel, 1);
return panel;
}
private UIElement BuildFlyoutIcon(TitleWeatherSnapshot snapshot)
{
var icon = new AnimatedWeatherIconControl(44);
icon.Update(snapshot, _settingsService.Current.AnimationsEnabled);
return new Border
{
Width = 52,
Height = 52,
CornerRadius = new CornerRadius(8),
Background = ModernUi.AccentSoft,
BorderBrush = ModernUi.Stroke,
BorderThickness = new Thickness(1),
Child = icon
};
}
private static void ConfigureCompactLine(TextBlock text, double lineHeight)
{
text.TextWrapping = TextWrapping.NoWrap;
text.TextTrimming = TextTrimming.CharacterEllipsis;
text.LineHeight = lineHeight;
text.VerticalAlignment = VerticalAlignment.Center;
}
private static UIElement BuildDetailLine(string label, string value, string glyph)
{
var grid = new Grid { ColumnSpacing = 10 };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.Children.Add(ModernUi.IconTile(glyph, 30, ModernUi.SurfaceAlt, ModernUi.TextSecondary, 13));
var title = ModernUi.Text(label, 13, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1);
Grid.SetColumn(title, 1);
grid.Children.Add(title);
var text = ModernUi.Text(value, 13, FontWeights.SemiBold, ModernUi.TextPrimary, maxLines: 1);
Grid.SetColumn(text, 2);
grid.Children.Add(text);
return grid;
}
}