媒体播放组件,录音组件
This commit is contained in:
lincube
2026-03-03 18:26:29 +08:00
parent 478ed115a1
commit 094745122e
42 changed files with 4661 additions and 1093 deletions

View File

@@ -11,8 +11,6 @@ using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Threading;
using FluentIcons.Avalonia;
using FluentIcons.Common;
using LanMontainDesktop.Models;
using LanMontainDesktop.Services;
@@ -79,7 +77,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
private readonly record struct HourlyForecastItem(
DateTime Time,
string TimeLabel,
Symbol Icon,
HyperOS3WeatherVisualKind IconKind,
string TemperatureText);
private static readonly IWeatherInfoService DefaultWeatherInfoService = new XiaomiWeatherService();
@@ -114,7 +112,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
private bool _isAttached;
private bool _isRefreshing;
private readonly TextBlock[] _hourlyTimeBlocks;
private readonly SymbolIcon[] _hourlyIconBlocks;
private readonly Image[] _hourlyIconBlocks;
private readonly TextBlock[] _hourlyTempBlocks;
public HourlyWeatherWidget()
@@ -215,7 +213,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
var scale = ResolveScale();
var hostWidth = Bounds.Width > 1 ? Bounds.Width : Math.Max(140, _currentCellSize * 4);
var hostHeight = Bounds.Height > 1 ? Bounds.Height : Math.Max(78, _currentCellSize * 2);
var cornerRadius = Math.Clamp(_currentCellSize * metrics.CornerRadiusScale, 24, 44);
var cornerRadius = Math.Clamp(_currentCellSize * metrics.CornerRadiusScale, 24, 46);
RootBorder.CornerRadius = new CornerRadius(cornerRadius);
BackgroundImageLayer.CornerRadius = new CornerRadius(cornerRadius);
@@ -224,8 +222,8 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
BackgroundLightLayer.CornerRadius = new CornerRadius(cornerRadius);
BackgroundShadeLayer.CornerRadius = new CornerRadius(cornerRadius);
ContentPaddingBorder.Padding = new Thickness(
Math.Clamp(Math.Min((_currentCellSize * metrics.HorizontalPaddingScale) * scale, hostWidth * 0.028), 3, 18),
Math.Clamp(Math.Min((_currentCellSize * metrics.VerticalPaddingScale) * scale, hostHeight * 0.060), 2, 14));
Math.Clamp(Math.Min((_currentCellSize * metrics.HorizontalPaddingScale) * scale, hostWidth * 0.034), 4, 22),
Math.Clamp(Math.Min((_currentCellSize * metrics.VerticalPaddingScale) * scale, hostHeight * 0.068), 3, 18));
ApplyAdaptiveTypography();
ResetParticles();
}
@@ -448,11 +446,8 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
CityTextBlock.Text = ResolvePreciseDisplayLocation(rawLocation, _languageCode, L("weather.widget.location_unknown", "Unknown location"));
ConditionTextBlock.Text = ResolveWeatherConditionText(snapshot.Current.WeatherText, visualKind);
WeatherIconSymbol.Symbol = ResolveWeatherSymbol(visualKind);
WeatherIconSymbol.Foreground = CreateSolidBrush(
ResolveWeatherIconAccent(
WeatherIconSymbol.Symbol,
visualKind is WeatherVisualKind.ClearNight or WeatherVisualKind.CloudyNight));
SetMainWeatherIcon(visualKind);
SetLoadingSkeleton(false);
TemperatureTextBlock.Text = FormatTemperature(snapshot.Current.TemperatureC);
var (low, high) = ResolveTemperatureRange(snapshot);
@@ -465,13 +460,8 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
{
var fallbackKind = ResolveFallbackVisualKind();
ApplyVisualTheme(fallbackKind);
WeatherIconSymbol.Symbol = fallbackKind == WeatherVisualKind.ClearNight
? Symbol.WeatherMoon
: Symbol.WeatherSunny;
WeatherIconSymbol.Foreground = CreateSolidBrush(
ResolveWeatherIconAccent(
WeatherIconSymbol.Symbol,
fallbackKind is WeatherVisualKind.ClearNight or WeatherVisualKind.CloudyNight));
SetMainWeatherIcon(fallbackKind);
SetLoadingSkeleton(false);
CityTextBlock.Text = L("weather.widget.location_not_configured", "Weather location is not configured");
ConditionTextBlock.Text = L("weather.widget.configure_hint", "Open Settings > Weather to configure");
TemperatureTextBlock.Text = "--°";
@@ -485,13 +475,8 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
{
var loadingKind = IsNightNow() ? WeatherVisualKind.CloudyNight : WeatherVisualKind.CloudyDay;
ApplyVisualTheme(loadingKind);
WeatherIconSymbol.Symbol = loadingKind == WeatherVisualKind.CloudyNight
? Symbol.WeatherPartlyCloudyNight
: Symbol.WeatherPartlyCloudyDay;
WeatherIconSymbol.Foreground = CreateSolidBrush(
ResolveWeatherIconAccent(
WeatherIconSymbol.Symbol,
loadingKind is WeatherVisualKind.ClearNight or WeatherVisualKind.CloudyNight));
SetMainWeatherIcon(loadingKind);
SetLoadingSkeleton(true);
CityTextBlock.Text = ResolvePreciseDisplayLocation(
locationName,
_languageCode,
@@ -506,8 +491,8 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
private void ApplyFailedState(string locationName)
{
ApplyVisualTheme(WeatherVisualKind.Fog);
WeatherIconSymbol.Symbol = Symbol.WeatherFog;
WeatherIconSymbol.Foreground = CreateSolidBrush(ResolveWeatherIconAccent(WeatherIconSymbol.Symbol, false));
SetMainWeatherIcon(WeatherVisualKind.Fog);
SetLoadingSkeleton(false);
CityTextBlock.Text = ResolvePreciseDisplayLocation(
locationName,
_languageCode,
@@ -532,22 +517,21 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
var primary = CreateSolidBrush(palette.PrimaryText);
var particleBrush = ResolveParticleBrush(ToThemeKind(kind), palette.ParticleColor);
var isNightVisual = kind is WeatherVisualKind.ClearNight or WeatherVisualKind.CloudyNight;
var conditionSecondary = CreateSolidBrush(palette.SecondaryText, isNightVisual ? (byte)0xF0 : (byte)0xE6);
var rangeSecondary = CreateSolidBrush(palette.SecondaryText, isNightVisual ? (byte)0xE8 : (byte)0xD6);
var forecastTimeBrush = CreateSolidBrush(palette.TertiaryText, isNightVisual ? (byte)0xDA : (byte)0xC6);
var forecastTempBrush = CreateSolidBrush(palette.PrimaryText, isNightVisual ? (byte)0xF4 : (byte)0xEA);
HourlyPanelBorder.Background = CreateSolidBrush(isNightVisual ? "#1BFFFFFF" : "#1EFFFFFF");
var cityBrush = CreateSolidBrush(palette.SecondaryText, isNightVisual ? (byte)0xDC : (byte)0xCC);
var conditionSecondary = CreateSolidBrush(palette.PrimaryText, isNightVisual ? (byte)0xEE : (byte)0xE2);
var rangeSecondary = CreateSolidBrush(palette.PrimaryText, isNightVisual ? (byte)0xE6 : (byte)0xD9);
var forecastTimeBrush = CreateSolidBrush(palette.TertiaryText, isNightVisual ? (byte)0xCA : (byte)0xB6);
var forecastTempBrush = CreateSolidBrush(palette.PrimaryText, isNightVisual ? (byte)0xEA : (byte)0xDC);
HourlyPanelBorder.Background = CreateSolidBrush(isNightVisual ? "#12FFFFFF" : "#0CFFFFFF");
LocationIcon.Foreground = primary;
CityTextBlock.Foreground = primary;
CityTextBlock.Foreground = cityBrush;
TemperatureTextBlock.Foreground = primary;
WeatherIconSymbol.Foreground = CreateSolidBrush(ResolveWeatherIconAccent(WeatherIconSymbol.Symbol, isNightVisual));
ConditionTextBlock.Foreground = conditionSecondary;
RangeTextBlock.Foreground = rangeSecondary;
for (var i = 0; i < _hourlyTimeBlocks.Length; i++)
{
_hourlyTimeBlocks[i].Foreground = forecastTimeBrush;
_hourlyTempBlocks[i].Foreground = forecastTempBrush;
_hourlyIconBlocks[i].Foreground = CreateSolidBrush(ResolveWeatherIconAccent(_hourlyIconBlocks[i].Symbol, isNightVisual));
}
foreach (var particle in _particleVisuals)
@@ -660,11 +644,6 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
palette.ParticleColor);
}
private static Symbol ResolveWeatherSymbol(WeatherVisualKind kind)
{
return HyperOS3WeatherTheme.ResolveWeatherSymbol(ToThemeKind(kind));
}
private static HyperOS3WeatherVisualKind ToThemeKind(WeatherVisualKind kind)
{
return kind switch
@@ -720,14 +699,14 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
{
if (!low.HasValue && !high.HasValue)
{
return L("weather.widget.range_unknown", "-- / --");
return L("weather.widget.range_unknown", "--/--");
}
var lowText = FormatTemperature(low);
var highText = FormatTemperature(high);
return string.Format(
GetUiCulture(),
L("weather.widget.range_format", "{0} / {1}"),
L("weather.widget.range_format", "{0}/{1}"),
lowText,
highText);
}
@@ -769,7 +748,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
var candidate = TryFindNearestHourlyCandidate(hourlyCandidates, targetTime);
var weatherCode = candidate?.Hourly.WeatherCode ??
ResolveFallbackWeatherCode(targetTime, snapshot, fallbackDaily);
var icon = ResolveWeatherSymbol(ResolveVisualKind(weatherCode, IsNightHour(targetTime)));
var iconKind = ToThemeKind(ResolveVisualKind(weatherCode, IsNightHour(targetTime)));
var estimatedTemp = candidate?.Hourly.TemperatureC ??
EstimateHourlyTemperature(
@@ -782,7 +761,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
items.Add(new HourlyForecastItem(
targetTime,
displayLabel,
icon,
iconKind,
FormatTemperature(estimatedTemp)));
}
@@ -794,7 +773,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
const int itemCount = 6;
var items = new List<HourlyForecastItem>(itemCount);
var now = _timeZoneService?.GetCurrentTime() ?? DateTime.Now;
var symbol = ResolveWeatherSymbol(visualKind);
var iconKind = ToThemeKind(visualKind);
for (var i = 0; i < itemCount; i++)
{
var targetTime = now.AddHours(i);
@@ -803,7 +782,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
i == 0
? L("weather.hourly.now", "Now")
: targetTime.ToString("HH:mm", CultureInfo.InvariantCulture),
symbol,
iconKind,
"--°"));
}
@@ -812,21 +791,22 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
private void ApplyHourlyForecastItems(IReadOnlyList<HourlyForecastItem> items)
{
var isNightVisual = _activeVisualKind is WeatherVisualKind.ClearNight or WeatherVisualKind.CloudyNight;
var fallbackIcon = HyperOS3WeatherAssetLoader.LoadImage(
HyperOS3WeatherTheme.ResolveIconAsset(ToThemeKind(_activeVisualKind)));
for (var i = 0; i < _hourlyTimeBlocks.Length; i++)
{
if (i >= items.Count)
{
_hourlyTimeBlocks[i].Text = "--";
_hourlyTempBlocks[i].Text = "--°";
_hourlyIconBlocks[i].Symbol = ResolveWeatherSymbol(_activeVisualKind);
_hourlyIconBlocks[i].Source = fallbackIcon;
continue;
}
var item = items[i];
_hourlyTimeBlocks[i].Text = item.TimeLabel;
_hourlyIconBlocks[i].Symbol = item.Icon;
_hourlyIconBlocks[i].Foreground = CreateSolidBrush(ResolveWeatherIconAccent(item.Icon, isNightVisual));
_hourlyIconBlocks[i].Source = HyperOS3WeatherAssetLoader.LoadImage(
HyperOS3WeatherTheme.ResolveIconAsset(item.IconKind));
_hourlyTempBlocks[i].Text = item.TemperatureText;
}
}
@@ -951,12 +931,6 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
return estimated;
}
private static string ResolveWeatherIconAccent(Symbol symbol, bool isNightVisual)
{
var kind = isNightVisual ? HyperOS3WeatherVisualKind.ClearNight : HyperOS3WeatherVisualKind.ClearDay;
return HyperOS3WeatherTheme.ResolveIconAccent(kind, symbol);
}
private static string ResolvePreciseDisplayLocation(string? rawName, string languageCode, string fallback)
{
if (string.IsNullOrWhiteSpace(rawName))
@@ -1103,93 +1077,78 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
private void ApplyAdaptiveTypography()
{
var (layoutWidth, layoutHeight) = ResolveLayoutViewport();
var metrics = HyperOS3WeatherTheme.ResolveMetrics(HyperOS3WeatherWidgetKind.Hourly4x2);
var scale = ResolveScale(layoutWidth, layoutHeight);
var densityBoost = scale <= 0.55 ? 0.80 : scale <= 0.72 ? 0.88 : scale <= 0.92 ? 0.95 : scale >= 1.45 ? 1.06 : 1.0;
var compactness = Math.Clamp((0.88 - scale) / 0.50, 0, 1);
var cityLength = Math.Max(1, CityTextBlock.Text?.Length ?? 2);
var cityCompression = cityLength >= 12 ? 0.68 : cityLength >= 9 ? 0.80 : cityLength >= 6 ? 0.90 : 1.0;
var conditionLength = Math.Max(1, ConditionTextBlock.Text?.Length ?? 2);
var conditionCompression = conditionLength >= 12 ? 0.72 : conditionLength >= 8 ? 0.85 : conditionLength >= 6 ? 0.92 : 1.0;
var scaleX = Math.Clamp(layoutWidth / 608d, 0.58, 1.90);
var scaleY = Math.Clamp(layoutHeight / 288d, 0.58, 1.90);
var uiScale = Math.Clamp(Math.Min(scaleX, scaleY), 0.58, 1.75);
var innerWidth = Math.Max(120, layoutWidth);
var innerHeight = Math.Max(72, layoutHeight);
ContentGrid.RowSpacing = Math.Clamp(Math.Max(metrics.MainGap * scale, layoutHeight * Lerp(0.030, 0.018, compactness)), 2, 14);
TopRowGrid.ColumnSpacing = Math.Clamp(Math.Max(metrics.MainGap * scale, layoutWidth * 0.014), 3, 14);
BottomInfoStack.Spacing = Math.Clamp(Math.Max(metrics.SectionGap * scale, layoutHeight * 0.016), 2, 10);
BottomInfoStack.Margin = new Thickness(0, 0, 0, Math.Clamp(layoutHeight * 0.018, 0, 10));
ConditionRangeStack.Spacing = Math.Clamp(layoutWidth * 0.010, 3, 12);
ConditionRangeStack.Margin = new Thickness(0, 0, 0, Math.Clamp(layoutHeight * 0.018, 0, 10));
ContentGrid.RowSpacing = Math.Clamp(7 * scaleY, 2, 12);
TopRowGrid.ColumnSpacing = Math.Clamp(10 * scaleX, 6, 16);
TopRowGrid.RowSpacing = Math.Clamp(5 * scaleY, 2, 9);
BottomInfoStack.Margin = new Thickness(0, 0, 0, Math.Clamp(2 * scaleY, 0, 5));
BottomInfoStack.Spacing = Math.Clamp(2 * scaleY, 1, 5);
var summaryHeight = Math.Clamp(116 * scaleY, 82, 164);
var bodyHeight = Math.Max(52, innerHeight - summaryHeight - ContentGrid.RowSpacing);
TemperatureTextBlock.FontSize = Math.Clamp(94 * uiScale, 56, 126);
TemperatureTextBlock.FontWeight = ToVariableWeight(320);
TemperatureTextBlock.Margin = new Thickness(0, Math.Clamp(-2 * uiScale, -5, 0), 0, 0);
TemperatureTextBlock.MaxWidth = Math.Clamp(innerWidth * 0.22, 84, 168);
CityInfoBadge.Padding = new Thickness(
Math.Clamp(10 * uiScale, 6, 14),
Math.Clamp(4 * uiScale, 2, 8));
CityInfoBadge.CornerRadius = new CornerRadius(Math.Clamp(11 * uiScale, 8, 16));
LocationIcon.FontSize = Math.Clamp(14 * uiScale, 10, 20);
CityTextBlock.FontSize = Math.Clamp(21 * uiScale, 13, 31);
CityTextBlock.FontWeight = ToVariableWeight(560);
CityTextBlock.MaxWidth = Math.Clamp(innerWidth * 0.25, 80, 220);
ConditionInfoBadge.Padding = new Thickness(0);
ConditionInfoBadge.CornerRadius = new CornerRadius(Math.Clamp(8 * uiScale, 4, 12));
ConditionRangeStack.Spacing = Math.Clamp(12 * uiScale, 6, 18);
ConditionTextBlock.FontSize = Math.Clamp(34 * uiScale, 16, 46);
RangeTextBlock.FontSize = Math.Clamp(34 * uiScale, 16, 46);
ConditionTextBlock.FontWeight = ToVariableWeight(610);
RangeTextBlock.FontWeight = ToVariableWeight(620);
ConditionTextBlock.MaxWidth = Math.Clamp(innerWidth * 0.16, 46, 170);
RangeTextBlock.MaxWidth = Math.Clamp(innerWidth * 0.20, 60, 200);
var iconSize = Math.Clamp(68 * uiScale, 40, 90);
WeatherIconImage.Width = iconSize;
WeatherIconImage.Height = iconSize;
HourlyPanelBorder.Padding = new Thickness(
Math.Clamp(layoutWidth * 0.018, 4, 16),
Math.Clamp(layoutHeight * 0.020, 3, 12));
HourlyPanelBorder.CornerRadius = new CornerRadius(Math.Clamp(Math.Min(layoutWidth, layoutHeight) * 0.065, 8, 22));
HourlyGrid.ColumnSpacing = Math.Clamp(layoutWidth * 0.010, 1.5, 12);
var topBandHeight = Math.Max(18, layoutHeight * 0.22);
var middleBandHeight = Math.Max(24, layoutHeight * 0.30);
var bottomBandHeight = Math.Max(22, layoutHeight - topBandHeight - middleBandHeight - (ContentGrid.RowSpacing * 2));
LocationIcon.FontSize = Math.Min(Math.Clamp((metrics.IconFont * 0.6) * scale * densityBoost, 9, 30), topBandHeight * 0.58);
CityTextBlock.FontSize = Math.Min(Math.Clamp((metrics.PrimaryTextFont * 1.42) * scale * cityCompression * densityBoost, 12, 46), topBandHeight * 0.76);
WeatherIconSymbol.FontSize = Math.Min(Math.Clamp((metrics.IconFont * 1.02) * scale * densityBoost, 12, 56), topBandHeight * 0.95);
TemperatureTextBlock.FontSize = Math.Min(Math.Clamp((metrics.PrimaryTemperatureFont * 1.40) * scale * densityBoost, 26, 138), middleBandHeight * 0.92);
ConditionTextBlock.FontSize = Math.Min(Math.Clamp((metrics.PrimaryTextFont * 1.14) * scale * conditionCompression * densityBoost, 9, 40), middleBandHeight * 0.42);
RangeTextBlock.FontSize = Math.Min(Math.Clamp((metrics.SecondaryTextFont * 1.54) * scale * densityBoost, 10, 46), middleBandHeight * 0.50);
TemperatureTextBlock.Margin = new Thickness(0, Math.Clamp(layoutHeight * 0.008, 0, 6), 0, Math.Clamp(layoutHeight * 0.012, 0, 8));
var weightProgress = Math.Clamp((scale - 0.34) / 1.18, 0, 1);
CityTextBlock.FontWeight = ToVariableWeight(Lerp(540, 680, weightProgress));
TemperatureTextBlock.FontWeight = ToVariableWeight(Lerp(600, 760, weightProgress));
ConditionTextBlock.FontWeight = ToVariableWeight(Lerp(490, 620, weightProgress));
RangeTextBlock.FontWeight = ToVariableWeight(Lerp(490, 610, weightProgress));
var topRightMaxWidth = Math.Clamp(layoutWidth * Lerp(0.42, 0.34, compactness), 128, 280);
ConditionRangeStack.MaxWidth = topRightMaxWidth;
ConditionTextBlock.MaxWidth = Math.Max(44, topRightMaxWidth * Lerp(0.45, 0.40, compactness));
RangeTextBlock.MaxWidth = Math.Max(62, topRightMaxWidth * Lerp(0.55, 0.60, compactness));
var leftTopBudget = Math.Max(140, layoutWidth - topRightMaxWidth - Math.Clamp(64 * scale, 26, 92));
TemperatureTextBlock.MaxWidth = leftTopBudget;
CityTextBlock.MaxWidth = Math.Max(110, layoutWidth - Math.Clamp(86 * scale, 28, 120));
Math.Clamp(5 * scaleX, 3, 10),
Math.Clamp(3 * scaleY, 1, 7));
HourlyPanelBorder.CornerRadius = new CornerRadius(Math.Clamp(14 * uiScale, 8, 20));
HourlyGrid.ColumnSpacing = Math.Clamp(9 * scaleX, 4, 14);
var hourlyColumnCount = Math.Max(1, _hourlyTimeBlocks.Length);
var hourlyInnerWidth = Math.Max(
80,
layoutWidth - HourlyPanelBorder.Padding.Left - HourlyPanelBorder.Padding.Right - (HourlyGrid.ColumnSpacing * (hourlyColumnCount - 1)));
var hourlyCellWidth = Math.Max(32, hourlyInnerWidth / hourlyColumnCount);
var hourlyStackSpacing = Math.Clamp(bottomBandHeight * 0.065, 1, 5);
var hourlyInnerHeight = Math.Max(
20,
bottomBandHeight - HourlyPanelBorder.Padding.Top - HourlyPanelBorder.Padding.Bottom);
var hourlyLineHeight = Math.Max(6, (hourlyInnerHeight - (hourlyStackSpacing * 2)) / 3d);
var hourlyTimeMaxByWidth = Math.Clamp(hourlyCellWidth / Lerp(4.4, 3.8, 1 - compactness), 7, 24);
var hourlyTempMaxByWidth = Math.Clamp(hourlyCellWidth / Lerp(5.0, 4.4, 1 - compactness), 7, 28);
var hourlyIconMaxByWidth = Math.Clamp(hourlyCellWidth * Lerp(0.32, 0.38, 1 - compactness), 7, 30);
var hourlyTimeMaxByHeight = Math.Clamp(hourlyLineHeight * 0.95, 7, 24);
var hourlyTempMaxByHeight = Math.Clamp(hourlyLineHeight * 0.95, 7, 28);
var hourlyIconMaxByHeight = Math.Clamp(hourlyLineHeight * 1.05, 8, 30);
var hourlyTimeSize = Math.Min(
Math.Clamp((metrics.CaptionFont * 1.20) * scale * densityBoost, 8, 30),
Math.Min(hourlyTimeMaxByWidth, hourlyTimeMaxByHeight));
var hourlyIconSize = Math.Min(
Math.Clamp((metrics.IconFont * 0.64) * scale * densityBoost, 8, 34),
Math.Min(hourlyIconMaxByWidth, hourlyIconMaxByHeight));
var hourlyTempSize = Math.Min(
Math.Clamp((metrics.SecondaryTextFont * 1.34) * scale * densityBoost, 8, 34),
Math.Min(hourlyTempMaxByWidth, hourlyTempMaxByHeight));
96,
innerWidth - HourlyPanelBorder.Padding.Left - HourlyPanelBorder.Padding.Right - (HourlyGrid.ColumnSpacing * (hourlyColumnCount - 1)));
var hourlyCellWidth = Math.Max(34, hourlyInnerWidth / hourlyColumnCount);
var stackSpacing = Math.Clamp(2 * scaleY, 1, 4);
var hourlyTempSize = Math.Clamp(bodyHeight * 0.24, 14, 30);
var hourlyTimeSize = Math.Clamp(bodyHeight * 0.20, 10, 24);
var hourlyIconSize = Math.Clamp(bodyHeight * 0.28, 14, 34);
for (var i = 0; i < _hourlyTimeBlocks.Length; i++)
{
_hourlyTimeBlocks[i].FontSize = hourlyTimeSize;
_hourlyTempBlocks[i].FontSize = hourlyTempSize;
_hourlyIconBlocks[i].FontSize = hourlyIconSize;
_hourlyTimeBlocks[i].MaxWidth = hourlyCellWidth;
_hourlyTempBlocks[i].MaxWidth = hourlyCellWidth;
_hourlyTimeBlocks[i].FontWeight = ToVariableWeight(Lerp(480, 620, weightProgress));
_hourlyTempBlocks[i].FontWeight = ToVariableWeight(Lerp(500, 650, weightProgress));
_hourlyTimeBlocks[i].FontSize = hourlyTimeSize;
_hourlyIconBlocks[i].Width = hourlyIconSize;
_hourlyIconBlocks[i].Height = hourlyIconSize;
_hourlyTimeBlocks[i].MaxWidth = Math.Clamp(hourlyCellWidth, 36, 128);
_hourlyTempBlocks[i].MaxWidth = Math.Clamp(hourlyCellWidth, 36, 128);
_hourlyTimeBlocks[i].FontWeight = ToVariableWeight(500);
_hourlyTempBlocks[i].FontWeight = ToVariableWeight(590);
if (_hourlyTimeBlocks[i].Parent is StackPanel hourlyStack)
{
hourlyStack.Spacing = hourlyStackSpacing;
hourlyStack.Spacing = stackSpacing;
}
}
}
@@ -1199,6 +1158,18 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
return from + ((to - from) * t);
}
private void SetMainWeatherIcon(WeatherVisualKind kind)
{
WeatherIconImage.Source = HyperOS3WeatherAssetLoader.LoadImage(
HyperOS3WeatherTheme.ResolveIconAsset(ToThemeKind(kind)));
}
private void SetLoadingSkeleton(bool isLoading)
{
CityInfoBadge.Background = isLoading ? CreateSolidBrush("#24FFFFFF") : Brushes.Transparent;
ConditionInfoBadge.Background = isLoading ? CreateSolidBrush("#1CFFFFFF") : Brushes.Transparent;
}
private static FontWeight ToVariableWeight(double weight)
{
return (FontWeight)(int)Math.Clamp(Math.Round(weight), 1, 1000);