change.重做天气,为回到系统提供自定义功能。
559
.trae/documents/weather-widget-material-redesign.md
Normal file
@@ -0,0 +1,559 @@
|
||||
# 天气组件 Material Design 重设计计划
|
||||
|
||||
> **目标:** 全面重构阑山桌面天气组件的视觉设计,遵循 Material Design 3 规范,参考 Google Weather、几何天气、Breez 天气和柠檬天气的设计语言。
|
||||
|
||||
---
|
||||
|
||||
## 当前状态分析
|
||||
|
||||
### 现有组件
|
||||
1. **WeatherWidget** - 基础天气(温度+天气状况+位置)
|
||||
2. **ExtendedWeatherWidget** - 扩展天气(含指标、逐小时、逐日预报)
|
||||
3. **HourlyWeatherWidget** - 逐小时天气
|
||||
4. **MultiDayWeatherWidget** - 多日天气
|
||||
5. **WeatherClockWidget** - 天气时钟
|
||||
|
||||
### 现有问题
|
||||
- 排版层次不清晰,文字大小对比不够
|
||||
- 布局过于紧凑,缺乏呼吸感
|
||||
- 内部卡片使用简单纯色背景,缺乏 Material 风格
|
||||
- 背景场景和前景内容缺乏深度分离
|
||||
- 圆角和间距不统一
|
||||
|
||||
### 现有视觉系统
|
||||
- 4套调色板:Google(默认)、Geometric、Breezy、LemonFlutter
|
||||
- 动态背景场景:MaterialWeatherSceneControl 绘制渐变+装饰
|
||||
- 图标系统:WeatherIconView + WeatherIconAssetResolver
|
||||
|
||||
---
|
||||
|
||||
## 设计方向
|
||||
|
||||
### 核心原则
|
||||
1. **Material Design 3** - 使用 M3 的排版、颜色、间距和形状规范
|
||||
2. **信息层级清晰** - 大字体温度、次要信息弱化
|
||||
3. **呼吸感** - 合理的间距和留白
|
||||
4. **深度感** - 前景卡片与背景场景分离
|
||||
5. **圆角一致性** - 遵循 DesignCornerRadius 规范
|
||||
|
||||
### 参考风格
|
||||
- **Google Weather** - 大字体温度、清晰层级、圆角卡片、柔和渐变
|
||||
- **几何天气** - 几何装饰、现代感
|
||||
- **Breez** - 清新留白、柔和色彩
|
||||
- **柠檬天气** - 活泼明亮
|
||||
|
||||
---
|
||||
|
||||
## 具体改动计划
|
||||
|
||||
### Task 1: 优化 MaterialWeatherPalette 和调色板系统
|
||||
|
||||
**文件:** `LanMountainDesktop/Views/Components/MaterialWeatherVisualTheme.cs`
|
||||
|
||||
**改动:**
|
||||
- 调整所有调色板的对比度,确保文字可读性
|
||||
- 优化背景渐变色彩,更加柔和自然
|
||||
- 统一文字主色和次色的对比度比例
|
||||
- 为每个风格增加 `SurfaceColor` 和 `SurfaceVariantColor` 用于卡片背景
|
||||
|
||||
**当前调色板字段:**
|
||||
```csharp
|
||||
public sealed record MaterialWeatherPalette(
|
||||
Color BackgroundTop,
|
||||
Color BackgroundBottom,
|
||||
Color PrimaryShape,
|
||||
Color SecondaryShape,
|
||||
Color AccentShape,
|
||||
Color TextPrimary,
|
||||
Color TextSecondary,
|
||||
Color SurfaceTint,
|
||||
Color OverlayTint);
|
||||
```
|
||||
|
||||
**新增字段:**
|
||||
```csharp
|
||||
Color SurfaceColor, // 卡片表面色(低透明度白色/黑色)
|
||||
Color SurfaceVariantColor, // 变体表面色
|
||||
Color OutlineColor // 分割线/边框色
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 重构 WeatherWidget(基础天气组件)
|
||||
|
||||
**文件:**
|
||||
- `LanMountainDesktop/Views/Components/WeatherWidget.axaml`
|
||||
- `LanMountainDesktop/Views/Components/WeatherWidget.axaml.cs`
|
||||
|
||||
**设计目标:**
|
||||
- 大字体温度显示(类似 Google Weather)
|
||||
- 天气状况文字清晰可读
|
||||
- 位置和温度范围弱化显示
|
||||
- 图标与文字对齐优化
|
||||
|
||||
**XAML 改动:**
|
||||
```xml
|
||||
<Border x:Name="RootBorder"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||||
ClipToBounds="True">
|
||||
<Grid>
|
||||
<components:MaterialWeatherSceneControl x:Name="Scene" />
|
||||
<Border x:Name="OverlayBorder" />
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<Grid x:Name="ContentGrid"
|
||||
RowDefinitions="*,Auto"
|
||||
Margin="20,16,20,14">
|
||||
|
||||
<!-- 上半区:温度 + 图标 -->
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<StackPanel VerticalAlignment="Center" Spacing="4">
|
||||
<!-- 温度:超大字体 -->
|
||||
<TextBlock x:Name="TemperatureTextBlock"
|
||||
Text="--°"
|
||||
FontSize="72"
|
||||
FontWeight="Bold"
|
||||
LineHeight="72" />
|
||||
<!-- 天气状况 -->
|
||||
<TextBlock x:Name="ConditionTextBlock"
|
||||
Text="Loading"
|
||||
FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 右侧图标 -->
|
||||
<components:WeatherIconView x:Name="MainIcon"
|
||||
Grid.Column="1"
|
||||
Width="72"
|
||||
Height="72"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<!-- 底部信息栏 -->
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,Auto">
|
||||
<TextBlock x:Name="LocationTextBlock"
|
||||
Text="Weather"
|
||||
FontSize="13"
|
||||
FontWeight="Medium"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
VerticalAlignment="Bottom" />
|
||||
<TextBlock x:Name="RangeTextBlock"
|
||||
Grid.Column="1"
|
||||
Text="-- / --"
|
||||
FontSize="13"
|
||||
FontWeight="Medium"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
```
|
||||
|
||||
**CS 改动:**
|
||||
- 调整响应式布局的字体缩放比例
|
||||
- 更新颜色绑定使用新的调色板字段
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 重构 ExtendedWeatherWidget(扩展天气组件)
|
||||
|
||||
**文件:**
|
||||
- `LanMountainDesktop/Views/Components/ExtendedWeatherWidget.axaml`
|
||||
- `LanMountainDesktop/Views/Components/ExtendedWeatherWidget.axaml.cs`
|
||||
|
||||
**设计目标:**
|
||||
- 顶部区域:位置+温度+图标横向排列
|
||||
- 指标区域:使用 Material 3 风格的标签卡片
|
||||
- 逐小时预报:水平滚动卡片,时间+图标+温度
|
||||
- 逐日预报:列表式布局,日期+图标+高低温
|
||||
|
||||
**XAML 改动:**
|
||||
```xml
|
||||
<Border x:Name="RootBorder"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||||
ClipToBounds="True">
|
||||
<Grid>
|
||||
<components:MaterialWeatherSceneControl x:Name="Scene" />
|
||||
<Border x:Name="OverlayBorder" />
|
||||
|
||||
<Grid x:Name="ContentGrid"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto"
|
||||
Margin="20,16,20,14"
|
||||
RowSpacing="12">
|
||||
|
||||
<!-- 顶部:位置 + 图标 + 温度 -->
|
||||
<Grid ColumnDefinitions="*,Auto,Auto" VerticalAlignment="Center">
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock x:Name="LocationTextBlock"
|
||||
Text="Weather"
|
||||
FontSize="13"
|
||||
FontWeight="Medium"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Opacity="0.72" />
|
||||
<TextBlock x:Name="ConditionTextBlock"
|
||||
Text="Loading"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
<components:WeatherIconView x:Name="MainIcon"
|
||||
Grid.Column="1"
|
||||
Width="56"
|
||||
Height="56"
|
||||
Margin="0,0,10,0" />
|
||||
<TextBlock x:Name="TemperatureTextBlock"
|
||||
Grid.Column="2"
|
||||
Text="--°"
|
||||
FontSize="56"
|
||||
FontWeight="Bold"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<!-- 指标区域 -->
|
||||
<UniformGrid x:Name="MetricGrid" Grid.Row="1" Rows="1" Columns="3" />
|
||||
|
||||
<!-- 逐小时预报 -->
|
||||
<Border Grid.Row="2"
|
||||
Background="{DynamicResource SurfaceColor}"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusMd}"
|
||||
Padding="10,8">
|
||||
<UniformGrid x:Name="HourlyGrid" Rows="1" Columns="6" />
|
||||
</Border>
|
||||
|
||||
<!-- 逐日预报 -->
|
||||
<Border Grid.Row="3"
|
||||
Background="{DynamicResource SurfaceColor}"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusMd}"
|
||||
Padding="10,8">
|
||||
<UniformGrid x:Name="DailyGrid" Rows="1" Columns="5" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
```
|
||||
|
||||
**CS 改动:**
|
||||
- `CreateMetric` 方法:使用圆角卡片,Material 3 风格标签
|
||||
- `BuildHourlyItems` 方法:改进卡片样式,统一圆角
|
||||
- `BuildDailyItems` 方法:改进卡片样式,统一圆角
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 重构 HourlyWeatherWidget(逐小时天气组件)
|
||||
|
||||
**文件:**
|
||||
- `LanMountainDesktop/Views/Components/HourlyWeatherWidget.axaml`
|
||||
- `LanMountainDesktop/Views/Components/HourlyWeatherWidget.axaml.cs`
|
||||
|
||||
**设计目标:**
|
||||
- 顶部简洁信息栏
|
||||
- 逐小时预报使用 Material 卡片风格
|
||||
- 时间、图标、温度垂直排列
|
||||
|
||||
**XAML 改动:**
|
||||
```xml
|
||||
<Border x:Name="RootBorder"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||||
ClipToBounds="True">
|
||||
<Grid>
|
||||
<components:MaterialWeatherSceneControl x:Name="Scene" />
|
||||
<Border x:Name="OverlayBorder" />
|
||||
|
||||
<Grid x:Name="ContentGrid"
|
||||
RowDefinitions="Auto,*"
|
||||
Margin="18,14"
|
||||
RowSpacing="12">
|
||||
|
||||
<!-- 顶部信息栏 -->
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto" VerticalAlignment="Center">
|
||||
<TextBlock x:Name="TemperatureTextBlock"
|
||||
Text="--°"
|
||||
FontSize="42"
|
||||
FontWeight="Bold"
|
||||
VerticalAlignment="Center" />
|
||||
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
|
||||
<TextBlock x:Name="ConditionTextBlock"
|
||||
Text="Loading"
|
||||
FontSize="15"
|
||||
FontWeight="SemiBold"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<TextBlock x:Name="LocationTextBlock"
|
||||
Text="Weather"
|
||||
FontSize="12"
|
||||
FontWeight="Medium"
|
||||
Opacity="0.72"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
<TextBlock x:Name="RangeTextBlock"
|
||||
Grid.Column="2"
|
||||
Text="-- / --"
|
||||
FontSize="12"
|
||||
FontWeight="Medium"
|
||||
VerticalAlignment="Center"
|
||||
Opacity="0.72"
|
||||
Margin="0,0,10,0" />
|
||||
<components:WeatherIconView x:Name="MainIcon"
|
||||
Grid.Column="3"
|
||||
Width="48"
|
||||
Height="48" />
|
||||
</Grid>
|
||||
|
||||
<!-- 逐小时预报卡片容器 -->
|
||||
<Border Grid.Row="1"
|
||||
Background="{DynamicResource SurfaceColor}"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusMd}"
|
||||
Padding="8,6">
|
||||
<UniformGrid x:Name="HourlyGrid" Rows="1" Columns="6" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 重构 MultiDayWeatherWidget(多日天气组件)
|
||||
|
||||
**文件:**
|
||||
- `LanMountainDesktop/Views/Components/MultiDayWeatherWidget.axaml`
|
||||
- `LanMountainDesktop/Views/Components/MultiDayWeatherWidget.axaml.cs`
|
||||
|
||||
**设计目标:**
|
||||
- 左侧:当前天气信息(图标+温度+状况+位置)
|
||||
- 右侧:多日预报列表,使用行式布局
|
||||
|
||||
**XAML 改动:**
|
||||
```xml
|
||||
<Border x:Name="RootBorder"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||||
ClipToBounds="True">
|
||||
<Grid>
|
||||
<components:MaterialWeatherSceneControl x:Name="Scene" />
|
||||
<Border x:Name="OverlayBorder" />
|
||||
|
||||
<Grid x:Name="ContentGrid"
|
||||
ColumnDefinitions="1.2*,1.6*"
|
||||
Margin="18,14"
|
||||
ColumnSpacing="14">
|
||||
|
||||
<!-- 左侧当前天气 -->
|
||||
<StackPanel VerticalAlignment="Center" Spacing="6">
|
||||
<components:WeatherIconView x:Name="MainIcon"
|
||||
Width="64"
|
||||
Height="64"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock x:Name="TemperatureTextBlock"
|
||||
Text="--°"
|
||||
FontSize="42"
|
||||
FontWeight="Bold" />
|
||||
<TextBlock x:Name="ConditionTextBlock"
|
||||
Text="Loading"
|
||||
FontSize="15"
|
||||
FontWeight="SemiBold"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<TextBlock x:Name="LocationTextBlock"
|
||||
Text="Weather"
|
||||
FontSize="12"
|
||||
FontWeight="Medium"
|
||||
Opacity="0.72"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 右侧多日预报 -->
|
||||
<Border Grid.Column="1"
|
||||
Background="{DynamicResource SurfaceColor}"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusMd}"
|
||||
Padding="10,8">
|
||||
<ItemsControl x:Name="DailyItemsControl" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 重构 WeatherClockWidget(天气时钟组件)
|
||||
|
||||
**文件:**
|
||||
- `LanMountainDesktop/Views/Components/WeatherClockWidget.axaml`
|
||||
- `LanMountainDesktop/Views/Components/WeatherClockWidget.axaml.cs`
|
||||
|
||||
**设计目标:**
|
||||
- 左侧:大字体时间+日期
|
||||
- 右侧:天气图标+温度+状况
|
||||
- 信息层级清晰
|
||||
|
||||
**XAML 改动:**
|
||||
```xml
|
||||
<Border x:Name="RootBorder"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||||
ClipToBounds="True">
|
||||
<Grid>
|
||||
<components:MaterialWeatherSceneControl x:Name="Scene" />
|
||||
<Border x:Name="OverlayBorder" />
|
||||
|
||||
<Grid x:Name="ContentGrid"
|
||||
ColumnDefinitions="*,Auto"
|
||||
Margin="18,12"
|
||||
ColumnSpacing="12">
|
||||
|
||||
<!-- 左侧时间 -->
|
||||
<StackPanel VerticalAlignment="Center" Spacing="2">
|
||||
<TextBlock x:Name="TimeTextBlock"
|
||||
Text="--:--"
|
||||
FontSize="38"
|
||||
FontWeight="Bold"
|
||||
LineHeight="38" />
|
||||
<TextBlock x:Name="DateTextBlock"
|
||||
Text="Weather"
|
||||
FontSize="12"
|
||||
FontWeight="Medium"
|
||||
Opacity="0.72"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 右侧天气 -->
|
||||
<StackPanel Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Spacing="1">
|
||||
<components:WeatherIconView x:Name="MainIcon"
|
||||
Width="44"
|
||||
Height="44"
|
||||
HorizontalAlignment="Right" />
|
||||
<TextBlock x:Name="TemperatureTextBlock"
|
||||
Text="--°"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
HorizontalAlignment="Right" />
|
||||
<TextBlock x:Name="ConditionTextBlock"
|
||||
Text="Loading"
|
||||
FontSize="11"
|
||||
FontWeight="Medium"
|
||||
HorizontalAlignment="Right"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
MaxWidth="100"
|
||||
Opacity="0.82" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: 更新 ExtendedWeatherWidget 的代码后置文件
|
||||
|
||||
**文件:** `LanMountainDesktop/Views/Components/ExtendedWeatherWidget.axaml.cs`
|
||||
|
||||
**改动:**
|
||||
- `CreateMetric` 方法改进:
|
||||
- 使用 `DesignCornerRadiusSm` 圆角
|
||||
- 使用新的 `SurfaceColor` 作为卡片背景
|
||||
- 优化字体大小和间距
|
||||
|
||||
- `BuildHourlyItems` 方法改进:
|
||||
- 使用 `DesignCornerRadiusSm` 圆角
|
||||
- 使用 `SurfaceColor` 作为卡片背景
|
||||
- 时间、图标、温度垂直排列,居中对齐
|
||||
|
||||
- `BuildDailyItems` 方法改进:
|
||||
- 使用 `DesignCornerRadiusSm` 圆角
|
||||
- 使用 `SurfaceColor` 作为卡片背景
|
||||
- 日期、图标、高低温垂直排列
|
||||
|
||||
---
|
||||
|
||||
### Task 8: 更新 HourlyWeatherWidget 的代码后置文件
|
||||
|
||||
**文件:** `LanMountainDesktop/Views/Components/HourlyWeatherWidget.axaml.cs`
|
||||
|
||||
**改动:**
|
||||
- `CreateChip` 方法改进:
|
||||
- 使用 `DesignCornerRadiusSm` 圆角
|
||||
- 使用 `SurfaceColor` 作为卡片背景
|
||||
- 优化垂直排列的间距
|
||||
|
||||
---
|
||||
|
||||
### Task 9: 更新 MultiDayWeatherWidget 的代码后置文件
|
||||
|
||||
**文件:** `LanMountainDesktop/Views/Components/MultiDayWeatherWidget.axaml.cs`
|
||||
|
||||
**改动:**
|
||||
- `CreateRow` 方法改进:
|
||||
- 添加底部分割线(除最后一行)
|
||||
- 优化列间距和对齐
|
||||
- 高低温使用不同透明度区分
|
||||
|
||||
---
|
||||
|
||||
### Task 10: 更新 MaterialWeatherVisualTheme 调色板
|
||||
|
||||
**文件:** `LanMountainDesktop/Views/Components/MaterialWeatherVisualTheme.cs`
|
||||
|
||||
**改动:**
|
||||
- 为 `MaterialWeatherPalette` 添加新字段:
|
||||
- `SurfaceColor` - 用于卡片表面
|
||||
- `SurfaceVariantColor` - 用于变体表面
|
||||
- `OutlineColor` - 用于分割线
|
||||
|
||||
- 更新所有调色板生成方法:
|
||||
- `ResolveGooglePalette`
|
||||
- `ResolveGeometricPalette`
|
||||
- `ResolveBreezyPalette`
|
||||
- `ResolveLemonPalette`
|
||||
|
||||
- 每个调色板需要为白天/夜晚模式提供合适的 SurfaceColor:
|
||||
- 白天:低透明度白色(如 `#14FFFFFF`)
|
||||
- 夜晚:低透明度黑色(如 `#1A000000`)
|
||||
|
||||
---
|
||||
|
||||
### Task 11: 构建和测试
|
||||
|
||||
**命令:**
|
||||
```bash
|
||||
dotnet build LanMountainDesktop.slnx -c Debug
|
||||
dotnet test LanMountainDesktop.slnx -c Debug
|
||||
```
|
||||
|
||||
**验证清单:**
|
||||
- [ ] 所有天气组件正常编译
|
||||
- [ ] 运行时无异常
|
||||
- [ ] 4套视觉风格正常切换
|
||||
- [ ] 响应式布局正常工作
|
||||
- [ ] 圆角资源正确应用
|
||||
|
||||
---
|
||||
|
||||
## 文件改动汇总
|
||||
|
||||
| 文件 | 改动类型 | 说明 |
|
||||
|------|---------|------|
|
||||
| `MaterialWeatherVisualTheme.cs` | 修改 | 添加 SurfaceColor 等字段,更新所有调色板 |
|
||||
| `WeatherWidget.axaml` | 修改 | 重构布局,优化排版 |
|
||||
| `WeatherWidget.axaml.cs` | 修改 | 调整响应式布局和颜色绑定 |
|
||||
| `ExtendedWeatherWidget.axaml` | 修改 | 重构布局,添加卡片容器 |
|
||||
| `ExtendedWeatherWidget.axaml.cs` | 修改 | 改进卡片创建方法 |
|
||||
| `HourlyWeatherWidget.axaml` | 修改 | 重构布局,添加卡片容器 |
|
||||
| `HourlyWeatherWidget.axaml.cs` | 修改 | 改进卡片创建方法 |
|
||||
| `MultiDayWeatherWidget.axaml` | 修改 | 重构布局,添加卡片容器 |
|
||||
| `MultiDayWeatherWidget.axaml.cs` | 修改 | 改进行创建方法 |
|
||||
| `WeatherClockWidget.axaml` | 修改 | 重构布局,优化排版 |
|
||||
| `WeatherClockWidget.axaml.cs` | 修改 | 调整响应式布局 |
|
||||
|
||||
---
|
||||
|
||||
## 设计规范检查清单
|
||||
|
||||
- [ ] 所有组件根容器使用 `DesignCornerRadiusComponent`
|
||||
- [ ] 内部卡片使用 `DesignCornerRadiusMd` 或 `DesignCornerRadiusSm`
|
||||
- [ ] 不使用硬编码圆角值
|
||||
- [ ] 文字对比度符合 VISUAL_SPEC 要求
|
||||
- [ ] 间距使用一致的倍数(4px 基线)
|
||||
- [ ] 字体层级:温度(64-72px) > 状况(16-18px) > 位置/范围(12-13px)
|
||||
342
.trae/documents/weather-widget-visual-redesign.md
Normal file
@@ -0,0 +1,342 @@
|
||||
# 天气组件视觉重构 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 彻底重构阑山桌面天气系列组件的背景视觉和文字排版,为每种图标风格(Google Weather / Geometric / Breezy / Lemon)提供独立的背景配色和视觉质感,参考各天气 App 的 Material Design 风格,实现几何质感+柔和渐变+层次分明的排版。
|
||||
|
||||
**Architecture:** 保留现有数据层(WeatherWidgetBase、WeatherSnapshot、WeatherIconAssetResolver)和组件注册机制不变。核心改动:1) 将 `MaterialWeatherVisualTheme.ResolvePalette()` 扩展为按 styleId 分派不同配色方案;2) 重构 `MaterialWeatherSceneControl` 为按 styleId 渲染不同背景风格;3) 改进各天气 Widget 的文字排版层次。先创建 HTML Mock 验证视觉效果。
|
||||
|
||||
**Tech Stack:** Avalonia UI (XAML + C# code-behind)、HTML/CSS (Mock 预览)
|
||||
|
||||
---
|
||||
|
||||
## 当前状态分析
|
||||
|
||||
### 现有天气组件体系
|
||||
5 个天气组件,全部继承自 `WeatherWidgetBase`:
|
||||
|
||||
| 组件 | 文件 | 功能 |
|
||||
|------|------|------|
|
||||
| WeatherWidget | `WeatherWidget.axaml(.cs)` | 基础天气:温度+状况+图标+位置 |
|
||||
| WeatherClockWidget | `WeatherClockWidget.axaml(.cs)` | 天气+时钟 |
|
||||
| ExtendedWeatherWidget | `ExtendedWeatherWidget.axaml(.cs)` | 扩展天气:含指标/小时/多日预报 |
|
||||
| HourlyWeatherWidget | `HourlyWeatherWidget.axaml(.cs)` | 逐小时天气 |
|
||||
| MultiDayWeatherWidget | `MultiDayWeatherWidget.axaml(.cs)` | 多日天气 |
|
||||
|
||||
### 核心问题
|
||||
|
||||
1. **背景与图标风格脱钩**: `MaterialWeatherVisualTheme.ResolvePalette()` 只返回一套配色,与 `WeatherVisualStyleId`(GoogleWeatherV4/Geometric/Breezy/LemonFlutter)完全无关。切换图标风格时背景不变。
|
||||
2. **背景视觉单调**: `MaterialWeatherSceneControl` 只有一种手绘几何风格(椭圆+云+雨滴),质感差,缺乏各 App 的特色。
|
||||
3. **文字排版粗糙**: 温度数字不够大,信息层次不分明,指标用纯文字堆叠,预报区域无卡片样式。
|
||||
4. **半透明遮罩硬编码**: 所有组件都覆盖 `<Border Background="#30FFFFFF" />` 等硬编码遮罩,不随风格变化。
|
||||
|
||||
### 各天气 App 风格特征
|
||||
|
||||
**Google Weather (v4)**:
|
||||
- 背景:大面积柔和蓝白渐变,晴天偏暖黄蓝,雨天偏深蓝灰
|
||||
- 装饰:极简,几乎无几何装饰,纯靠渐变色彩表现天气氛围
|
||||
- 排版:温度超大(72px+),天气状况中等,位置小字
|
||||
|
||||
**Geometric Weather (几何天气)**:
|
||||
- 背景:深色系渐变(深蓝/深紫/深灰),搭配半透明几何圆形装饰
|
||||
- 装饰:大面积半透明圆形叠加,营造深度感
|
||||
- 排版:紧凑信息密度,指标用小标签
|
||||
|
||||
**Breezy Weather (微风天气)**:
|
||||
- 背景:清新渐变(浅蓝/浅绿/浅紫),比 Geometric 更明亮
|
||||
- 装饰:柔和波浪线条 + 少量几何装饰,Material Design 风格
|
||||
- 排版:卡片式预报,圆角芯片
|
||||
|
||||
**Lemon Weather (柠檬天气)**:
|
||||
- 背景:暖色系渐变(橙黄/粉紫/暖蓝),柠檬2偏扁平,柠檬3偏Material
|
||||
- 装饰:天气场景装饰(太阳光芒/云朵轮廓/雨丝),更有场景感
|
||||
- 排版:温度超大,天气图标突出
|
||||
|
||||
---
|
||||
|
||||
## 设计方案
|
||||
|
||||
### 视觉论文 (Visual Thesis)
|
||||
每种图标风格拥有独特的背景渐变配色和几何装饰语言——Google 纯净渐变、Geometric 深色几何、Breezy 清新波浪、Lemon 暖色场景——配合超大温度数字和层次分明的排版,在桌面小组件空间内实现 Material Design 的几何质感。
|
||||
|
||||
### 配色方案设计
|
||||
|
||||
每种风格 × 每种天气条件 × 昼夜 = 独立配色。以下为关键配色定义:
|
||||
|
||||
#### Google Weather 风格
|
||||
| 天气 | 白天 Top→Bottom | 夜晚 Top→Bottom |
|
||||
|------|----------------|----------------|
|
||||
| Clear | #4FC3F7 → #B3E5FC | #0D47A1 → #1A237E |
|
||||
| PartlyCloudy | #81D4FA → #E1F5FE | #1565C0 → #283593 |
|
||||
| Cloudy | #90A4AE → #CFD8DC | #37474F → #455A64 |
|
||||
| Rain | #78909C → #B0BEC5 | #263238 → #37474F |
|
||||
| Storm | #546E7A → #78909C | #1A1A2E → #263238 |
|
||||
| Snow | #E1F5FE → #FFFFFF | #1A237E → #283593 |
|
||||
| Fog/Haze | #B0BEC5 → #ECEFF1 | #455A64 → #546E7A |
|
||||
|
||||
#### Geometric 风格
|
||||
| 天气 | 白天 Top→Bottom | 夜晚 Top→Bottom |
|
||||
|------|----------------|----------------|
|
||||
| Clear | #1A237E → #3949AB | #0A0E27 → #1A1A3E |
|
||||
| PartlyCloudy | #283593 → #5C6BC0 | #0D1033 → #1E1E4A |
|
||||
| Cloudy | #37474F → #607D8B | #1A1A2E → #2D2D44 |
|
||||
| Rain | #1A237E → #3F51B5 | #0A0E27 → #1A1A3E |
|
||||
| Storm | #1A1A2E → #3F51B5 | #050510 → #1A1A2E |
|
||||
| Snow | #E8EAF6 → #C5CAE9 | #1A237E → #283593 |
|
||||
| Fog/Haze | #455A64 → #78909C | #1A1A2E → #37474F |
|
||||
|
||||
#### Breezy 风格
|
||||
| 天气 | 白天 Top→Bottom | 夜晚 Top→Bottom |
|
||||
|------|----------------|----------------|
|
||||
| Clear | #4DD0E1 → #80DEEA | #006064 → #00838F |
|
||||
| PartlyCloudy | #4FC3F7 → #B2EBF2 | #00695C → #00897B |
|
||||
| Cloudy | #80CBC4 → #B2DFDB | #37474F → #546E7A |
|
||||
| Rain | #4DB6AC → #80CBC4 | #004D40 → #00695C |
|
||||
| Storm | #26A69A → #4DB6AC | #1A1A2E → #004D40 |
|
||||
| Snow | #E0F7FA → #FFFFFF | #006064 → #00838F |
|
||||
| Fog/Haze | #80CBC4 → #E0F7FA | #37474F → #546E7A |
|
||||
|
||||
#### Lemon 风格
|
||||
| 天气 | 白天 Top→Bottom | 夜晚 Top→Bottom |
|
||||
|------|----------------|----------------|
|
||||
| Clear | #FFB74D → #FFF176 | #1A237E → #311B92 |
|
||||
| PartlyCloudy | #FF8A65 → #FFCC80 | #283593 → #4A148C |
|
||||
| Cloudy | #BCAAA4 → #D7CCC8 | #37474F → #4E342E |
|
||||
| Rain | #90A4AE → #B0BEC5 | #1A1A2E → #311B92 |
|
||||
| Storm | #78909C → #90A4AE | #0D0D1A → #1A1A2E |
|
||||
| Snow | #FFF9C4 → #FFFFFF | #1A237E → #311B92 |
|
||||
| Fog/Haze | #D7CCC8 → #EFEBE9 | #4E342E → #5D4037 |
|
||||
|
||||
### 排版改进方案
|
||||
|
||||
1. **温度超大化**: 温度字号从 56-58px 提升到 64-72px(基础组件),形成视觉锚点
|
||||
2. **层次分明**: 温度 → 天气状况 → 位置/指标,字号递减,透明度递减
|
||||
3. **指标标签化**: 湿度/风速/AQI 用半透明圆角标签展示,而非纯文字
|
||||
4. **预报芯片化**: 小时/每日预报用圆角半透明芯片卡片
|
||||
5. **图标间距**: 天气图标与文字之间增加 8-12px 间距
|
||||
|
||||
---
|
||||
|
||||
## 文件变更清单
|
||||
|
||||
| 文件 | 操作 | 说明 |
|
||||
|------|------|------|
|
||||
| `Views/Components/MaterialWeatherVisualTheme.cs` | 修改 | 扩展 ResolvePalette 支持 styleId 分派,新增4套风格配色 |
|
||||
| `Views/Components/MaterialWeatherSceneControl.cs` | 修改 | 按 styleId 渲染不同背景风格(纯渐变/深色几何/清新波浪/暖色场景) |
|
||||
| `Views/Components/WeatherWidgetBase.cs` | 修改 | 传递 styleId 到 SceneControl.Apply(),移除硬编码遮罩 |
|
||||
| `Views/Components/WeatherWidget.axaml` | 修改 | 改进排版层次,移除硬编码遮罩 |
|
||||
| `Views/Components/WeatherWidget.axaml.cs` | 修改 | 适配新排版 |
|
||||
| `Views/Components/WeatherClockWidget.axaml` | 修改 | 改进排版,移除硬编码遮罩 |
|
||||
| `Views/Components/WeatherClockWidget.axaml.cs` | 修改 | 适配新排版 |
|
||||
| `Views/Components/ExtendedWeatherWidget.axaml` | 修改 | 改进排版,指标标签化,预报芯片化 |
|
||||
| `Views/Components/ExtendedWeatherWidget.axaml.cs` | 修改 | 适配新排版+标签+芯片 |
|
||||
| `Views/Components/HourlyWeatherWidget.axaml` | 修改 | 改进排版,预报芯片化 |
|
||||
| `Views/Components/HourlyWeatherWidget.axaml.cs` | 修改 | 适配新排版+芯片 |
|
||||
| `Views/Components/MultiDayWeatherWidget.axaml` | 修改 | 改进排版 |
|
||||
| `Views/Components/MultiDayWeatherWidget.axaml.cs` | 修改 | 适配新排版 |
|
||||
| `mocks/weather-widget-mock.html` | 新建 | HTML Mock 预览(4种风格×2种天气×2种主题) |
|
||||
|
||||
---
|
||||
|
||||
## Task 分解
|
||||
|
||||
### Task 1: 创建 HTML Mock 预览
|
||||
|
||||
**Files:**
|
||||
- Create: `mocks/weather-widget-mock.html`
|
||||
|
||||
- [ ] **Step 1: 创建 HTML Mock 文件**
|
||||
|
||||
创建完整的 HTML Mock,包含:
|
||||
- 4 种风格(Google / Geometric / Breezy / Lemon)× 2 种天气(晴/雨)× 2 种主题(亮/暗)
|
||||
- 每种风格展示基础天气组件(温度+状况+图标+位置)
|
||||
- 改进后的排版:超大温度、层次分明、指标标签化
|
||||
- 亮色/暗色主题切换按钮
|
||||
|
||||
- [ ] **Step 2: 在浏览器中打开 Mock 验证效果**
|
||||
|
||||
Run: `start mocks/weather-widget-mock.html`
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 扩展 MaterialWeatherVisualTheme 支持多风格配色
|
||||
|
||||
**Files:**
|
||||
- Modify: `LanMountainDesktop/Views/Components/MaterialWeatherVisualTheme.cs`
|
||||
|
||||
- [ ] **Step 1: 修改 ResolvePalette 方法签名**
|
||||
|
||||
将 `ResolvePalette(MaterialWeatherCondition condition, bool isNight)` 改为 `ResolvePalette(string? styleId, MaterialWeatherCondition condition, bool isNight)`,内部按 styleId 分派到不同配色方案。
|
||||
|
||||
- [ ] **Step 2: 新增 Google Weather 配色表**
|
||||
|
||||
为 GoogleWeatherV4 风格定义所有天气条件×昼夜的配色(参考上面配色方案设计章节)。
|
||||
|
||||
- [ ] **Step 3: 新增 Geometric 配色表**
|
||||
|
||||
为 Geometric 风格定义深色系配色。
|
||||
|
||||
- [ ] **Step 4: 新增 Breezy 配色表**
|
||||
|
||||
为 Breezy 风格定义清新渐变配色。
|
||||
|
||||
- [ ] **Step 5: 新增 Lemon 配色表**
|
||||
|
||||
为 LemonFlutter 风格定义暖色系配色。
|
||||
|
||||
- [ ] **Step 6: 更新所有调用点**
|
||||
|
||||
将所有 `ResolvePalette(condition, isNight)` 调用改为 `ResolvePalette(styleId, condition, isNight)`。
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 重构 MaterialWeatherSceneControl 支持多风格背景
|
||||
|
||||
**Files:**
|
||||
- Modify: `LanMountainDesktop/Views/Components/MaterialWeatherSceneControl.cs`
|
||||
|
||||
- [ ] **Step 1: 扩展 Apply 方法签名**
|
||||
|
||||
将 `Apply(MaterialWeatherCondition condition, MaterialWeatherPalette palette, bool isLive)` 改为 `Apply(string? styleId, MaterialWeatherCondition condition, MaterialWeatherPalette palette, bool isLive)`,存储 styleId。
|
||||
|
||||
- [ ] **Step 2: 实现 Google Weather 风格渲染**
|
||||
|
||||
纯渐变背景,无几何装饰。背景使用 palette 的 BackgroundTop→BackgroundBottom 渐变。仅保留天气特效(雨滴/雪花/雾线)。
|
||||
|
||||
- [ ] **Step 3: 实现 Geometric 风格渲染**
|
||||
|
||||
深色渐变 + 大面积半透明几何圆形叠加。在基础渐变上叠加 2-3 个大椭圆(使用 palette 的 PrimaryShape/SecondaryShape/AccentShape),营造深度感。保留天气特效。
|
||||
|
||||
- [ ] **Step 4: 实现 Breezy 风格渲染**
|
||||
|
||||
清新渐变 + 柔和波浪线条。在基础渐变上绘制 2-3 条正弦波浪线(使用 palette 的 SurfaceTint),营造微风感。保留天气特效。
|
||||
|
||||
- [ ] **Step 5: 实现 Lemon 风格渲染**
|
||||
|
||||
暖色渐变 + 天气场景装饰。晴天绘制太阳光芒(放射线),多云绘制云朵轮廓,雨天绘制雨丝。保留天气特效。
|
||||
|
||||
- [ ] **Step 6: 更新所有调用点**
|
||||
|
||||
将所有 `SceneControl.Apply(condition, palette, isLive)` 改为 `SceneControl.Apply(styleId, condition, palette, isLive)`。
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 更新 WeatherWidgetBase 传递 styleId
|
||||
|
||||
**Files:**
|
||||
- Modify: `LanMountainDesktop/Views/Components/WeatherWidgetBase.cs`
|
||||
|
||||
- [ ] **Step 1: 修改 ApplyCurrentScene 方法**
|
||||
|
||||
在 `ApplyCurrentScene()` 中将 `CurrentVisualStyleId` 传递给 `SceneControl.Apply()`。
|
||||
|
||||
- [ ] **Step 2: 修改 ApplySnapshot 中的 ResolvePalette 调用**
|
||||
|
||||
将 `MaterialWeatherVisualTheme.ResolvePalette(CurrentCondition, isNight)` 改为 `MaterialWeatherVisualTheme.ResolvePalette(CurrentVisualStyleId, CurrentCondition, isNight)`。
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 改进各天气 Widget 的 XAML 排版
|
||||
|
||||
**Files:**
|
||||
- Modify: `WeatherWidget.axaml` — 移除硬编码遮罩 `<Border Background="#30FFFFFF" />`,改用 palette 驱动的半透明遮罩
|
||||
- Modify: `WeatherClockWidget.axaml` — 同上
|
||||
- Modify: `ExtendedWeatherWidget.axaml` — 同上 + 指标区域改用标签样式
|
||||
- Modify: `HourlyWeatherWidget.axaml` — 同上 + 预报区域改用芯片样式
|
||||
- Modify: `MultiDayWeatherWidget.axaml` — 同上
|
||||
|
||||
- [ ] **Step 1: 移除所有硬编码遮罩**
|
||||
|
||||
将 `<Border Background="#30FFFFFF" />` / `#42FFFFFF` / `#34FFFFFF` / `#38FFFFFF` / `#3CFFFFFF` 替换为 `<Border x:Name="OverlayBorder" />`,在 code-behind 中根据 palette 设置遮罩颜色。
|
||||
|
||||
- [ ] **Step 2: 改进 WeatherWidget 排版**
|
||||
|
||||
增大温度字号(58→64),增加图标与文字间距,调整位置文字透明度。
|
||||
|
||||
- [ ] **Step 3: 改进 WeatherClockWidget 排版**
|
||||
|
||||
增大时钟字号,增加天气信息与时间间距。
|
||||
|
||||
- [ ] **Step 4: 改进 ExtendedWeatherWidget 排版**
|
||||
|
||||
指标用半透明圆角标签,小时/每日预报用圆角芯片卡片。
|
||||
|
||||
- [ ] **Step 5: 改进 HourlyWeatherWidget 排版**
|
||||
|
||||
预报区域用圆角芯片卡片样式。
|
||||
|
||||
- [ ] **Step 6: 改进 MultiDayWeatherWidget 排版**
|
||||
|
||||
每日预报行增加分隔线和更好的间距。
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 更新各天气 Widget 的 code-behind
|
||||
|
||||
**Files:**
|
||||
- Modify: 所有天气 Widget 的 `.axaml.cs` 文件
|
||||
|
||||
- [ ] **Step 1: 更新 WeatherWidget.axaml.cs**
|
||||
|
||||
- 设置 OverlayBorder 背景
|
||||
- 增大温度字号
|
||||
- 适配新排版参数
|
||||
|
||||
- [ ] **Step 2: 更新 WeatherClockWidget.axaml.cs**
|
||||
|
||||
- 设置 OverlayBorder 背景
|
||||
- 适配新排版
|
||||
|
||||
- [ ] **Step 3: 更新 ExtendedWeatherWidget.axaml.cs**
|
||||
|
||||
- 设置 OverlayBorder 背景
|
||||
- 指标标签化(CreateMetric 改为带圆角背景的标签)
|
||||
- 预报芯片化
|
||||
|
||||
- [ ] **Step 4: 更新 HourlyWeatherWidget.axaml.cs**
|
||||
|
||||
- 设置 OverlayBorder 背景
|
||||
- 预报芯片化(CreateChip 改为带圆角背景的芯片)
|
||||
|
||||
- [ ] **Step 5: 更新 MultiDayWeatherWidget.axaml.cs**
|
||||
|
||||
- 设置 OverlayBorder 背景
|
||||
- 适配新排版
|
||||
|
||||
---
|
||||
|
||||
### Task 7: 验证与测试
|
||||
|
||||
- [ ] **Step 1: 运行项目查看效果**
|
||||
|
||||
Run: `dotnet run --project LanMountainDesktop/LanMountainDesktop.csproj`
|
||||
|
||||
- [ ] **Step 2: 运行相关测试**
|
||||
|
||||
Run: `dotnet test LanMountainDesktop.slnx -c Debug`
|
||||
|
||||
- [ ] **Step 3: 检查圆角规范合规**
|
||||
|
||||
确认所有组件 RootBorder 使用 `DesignCornerRadiusComponent`,新增的标签/芯片使用 `DesignCornerRadiusSm`/`DesignCornerRadiusMd`。
|
||||
|
||||
---
|
||||
|
||||
## 假设与决策
|
||||
|
||||
1. **4 套独立风格**: 每种图标风格对应独立的背景配色和装饰风格,切换图标风格时背景也跟着变
|
||||
2. **配色表驱动**: 所有颜色定义在 `MaterialWeatherVisualTheme` 中,不硬编码到 SceneControl
|
||||
3. **保留天气特效**: 雨滴/雪花/雾线/闪电等天气特效在所有风格中保留,但颜色跟随 palette
|
||||
4. **遮罩动态化**: 半透明遮罩颜色从 palette 中派生,而非硬编码 `#30FFFFFF`
|
||||
5. **排版渐进改进**: 不做大规模 XAML 重构,而是在现有结构上优化字号/间距/透明度
|
||||
6. **数据层不变**: WeatherSnapshot、WeatherIconAssetResolver、WeatherWidgetBase 的数据逻辑不变
|
||||
7. **接口兼容**: IDesktopComponentWidget 等接口实现不变
|
||||
|
||||
## 验证步骤
|
||||
|
||||
1. HTML Mock 在浏览器中展示 4 种风格效果满意
|
||||
2. Avalonia 项目编译通过
|
||||
3. 运行项目,切换图标风格时背景配色和装饰风格跟着变化
|
||||
4. 亮色/暗色主题切换正常
|
||||
5. 5 个天气组件排版层次分明
|
||||
6. 指标标签化和预报芯片化正常显示
|
||||
7. 测试通过
|
||||
13
.trae/specs/dock-back-to-windows-button-display/checklist.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Checklist
|
||||
|
||||
- [ ] `AppSettingsSnapshot.BackToWindowsButtonDisplayMode` exists and defaults to `IconAndText`.
|
||||
- [ ] `AppSettingsSnapshot` contains icon source, Fluent icon name, and text icon settings with safe defaults.
|
||||
- [ ] General > Basic Settings includes one folded back-to-platform button settings expander.
|
||||
- [ ] The expander includes the display-mode dropdown.
|
||||
- [ ] The expander includes nested icon source, Fluent icon popup picker, and text icon input controls.
|
||||
- [ ] The Dock button left icon slot renders either a Fluent icon or custom text.
|
||||
- [ ] `IconAndText`, `IconOnly`, and `TextOnly` modes update the Dock button live.
|
||||
- [ ] Icon source, Fluent icon name, and text icon updates refresh the Dock button live.
|
||||
- [ ] The selected mode is preserved when MainWindow saves app settings.
|
||||
- [ ] Localization keys exist for zh-CN, en-US, ja-JP, and ko-KR.
|
||||
- [ ] `dotnet build LanMountainDesktop.slnx -c Debug` succeeds.
|
||||
29
.trae/specs/dock-back-to-windows-button-display/spec.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Dock Back To Windows Button Display
|
||||
|
||||
## Summary
|
||||
|
||||
The Dock "Back to platform" action should expose a configurable left icon slot while keeping the localized platform text fixed.
|
||||
|
||||
## Requirements
|
||||
|
||||
- The default display mode is `IconAndText` so existing users keep a familiar Dock layout after upgrade.
|
||||
- The localized platform text remains controlled by the app and is not user-editable.
|
||||
- General > Basic Settings exposes one Fluent Avalonia `FASettingsExpander` for the back-to-platform button, with icon-related controls folded into nested `FASettingsExpanderItem` rows.
|
||||
- The main row exposes a dropdown with `IconAndText`, `IconOnly`, and `TextOnly` options.
|
||||
- A nested icon source row selects Fluent icon or text icon.
|
||||
- Fluent icon mode uses a popup picker-style flyout with search and a grid of the full FluentIcons `Icon` enum.
|
||||
- Text icon mode lets the user enter short text for the left icon slot.
|
||||
- Changing the dropdown persists to `AppSettingsSnapshot.BackToWindowsButtonDisplayMode` and updates the Dock button without restarting.
|
||||
- Changing the icon source, Fluent icon, or text icon persists to app settings and updates the Dock button without restarting.
|
||||
- `IconOnly` keeps the existing tooltip text so the button remains understandable.
|
||||
- `PinnedTaskbarActions` continues to control whether the action is visible; it does not replace the display mode setting.
|
||||
|
||||
## Acceptance Scenarios
|
||||
|
||||
- With default settings, the Dock button shows a small circle icon and the localized platform text.
|
||||
- Selecting icon only hides the platform text and keeps the configured left icon visible.
|
||||
- Selecting text only hides the left icon slot and keeps the localized platform text visible.
|
||||
- Choosing a Fluent icon changes the left icon slot.
|
||||
- Entering a short text icon changes the left icon slot.
|
||||
- Restarting the app restores the selected display mode.
|
||||
- Clicking the button still runs the existing minimize/back-to-platform behavior.
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Avalonia.Controls;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Services;
|
||||
@@ -73,6 +75,48 @@ public sealed class DesktopComponentRenderModeTests
|
||||
Assert.Null(probe.RuntimeContext?.PlacementId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultRuntimeRegistrations_IncludeMaterialWeatherComponents()
|
||||
{
|
||||
var componentIds = DesktopComponentRuntimeRegistry.GetDefaultRegistrations()
|
||||
.Select(registration => registration.ComponentId)
|
||||
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
Assert.Contains(BuiltInComponentIds.DesktopWeatherClock, componentIds);
|
||||
Assert.Contains(BuiltInComponentIds.DesktopWeather, componentIds);
|
||||
Assert.Contains(BuiltInComponentIds.DesktopHourlyWeather, componentIds);
|
||||
Assert.Contains(BuiltInComponentIds.DesktopMultiDayWeather, componentIds);
|
||||
Assert.Contains(BuiltInComponentIds.DesktopExtendedWeather, componentIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WeatherVisualStyleCatalog_NormalizesLegacyAndSupportedIds()
|
||||
{
|
||||
Assert.Equal(WeatherVisualStyleId.GoogleWeatherV4, WeatherVisualStyleCatalog.Normalize(null));
|
||||
Assert.Equal(WeatherVisualStyleId.GoogleWeatherV4, WeatherVisualStyleCatalog.Normalize("DefaultWeather"));
|
||||
Assert.Equal(WeatherVisualStyleId.GoogleWeatherV4, WeatherVisualStyleCatalog.Normalize("HyperOS3"));
|
||||
Assert.Equal(WeatherVisualStyleId.Geometric, WeatherVisualStyleCatalog.Normalize("Geometric"));
|
||||
Assert.Equal(WeatherVisualStyleId.Breezy, WeatherVisualStyleCatalog.Normalize("Breezy"));
|
||||
Assert.Equal(WeatherVisualStyleId.LemonFlutter, WeatherVisualStyleCatalog.Normalize("LemonFlutter"));
|
||||
Assert.Equal(WeatherVisualStyleId.GoogleWeatherV4, WeatherVisualStyleCatalog.Normalize("MissingPack"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(WeatherVisualStyleId.GoogleWeatherV4)]
|
||||
[InlineData(WeatherVisualStyleId.Geometric)]
|
||||
[InlineData(WeatherVisualStyleId.Breezy)]
|
||||
[InlineData(WeatherVisualStyleId.LemonFlutter)]
|
||||
public void WeatherIconAssetResolver_ResolvesCoreWeatherStates(string styleId)
|
||||
{
|
||||
Assert.NotNull(WeatherIconAssetResolver.ResolveAssetUri(styleId, 0, "Clear", isDaylight: true));
|
||||
Assert.NotNull(WeatherIconAssetResolver.ResolveAssetUri(styleId, 1, "Partly cloudy", isDaylight: false));
|
||||
Assert.NotNull(WeatherIconAssetResolver.ResolveAssetUri(styleId, 7, "Rain", isDaylight: true));
|
||||
Assert.NotNull(WeatherIconAssetResolver.ResolveAssetUri(styleId, 4, "Thunderstorm", isDaylight: true));
|
||||
Assert.NotNull(WeatherIconAssetResolver.ResolveAssetUri(styleId, 13, "Snow", isDaylight: true));
|
||||
Assert.NotNull(WeatherIconAssetResolver.ResolveAssetUri(styleId, 18, "Fog", isDaylight: true));
|
||||
Assert.NotNull(WeatherIconAssetResolver.ResolveAssetUri(styleId, 999, "Unknown", isDaylight: true));
|
||||
}
|
||||
|
||||
private static DesktopComponentRuntimeDescriptor CreateDescriptor()
|
||||
{
|
||||
Assert.True(CreateRuntimeRegistry().TryGetDescriptor(ComponentId, out var descriptor));
|
||||
|
||||
16
LanMountainDesktop/Assets/MaterialWeatherIcons/NOTICE.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Material Weather Icons Sources
|
||||
|
||||
This folder contains weather icon assets imported for LanMountainDesktop weather widgets.
|
||||
|
||||
The icon packs are included because the product owner explicitly requested original-style assets and accepted the licensing risk for uncertain or non-free icon packs. Keep this notice with the assets.
|
||||
|
||||
## Included packs
|
||||
|
||||
- `google-weather-v4`: imported from `mbatthew/GoogleWeatherIconsV4Pack`, which documents that the application code is MIT but the weather icons are sourced from Google Weather Icons v4 and have uncertain licensing.
|
||||
- `geometric`: imported from `breezy-weather/geometric-icon-provider`, an open-source rewrite of the Geometric Weather icon provider. Breezy's icon-pack index documents related assets as non-free.
|
||||
- `breezy`: imported from `breezy-weather/breezy-weather` app resources. Breezy Weather is LGPL-3.0; verify individual asset terms before external redistribution.
|
||||
- `lemon-flutter`: imported from `yangSpica27/spica_weather_flutter`, MIT licensed.
|
||||
|
||||
## Pending sources
|
||||
|
||||
- Lemon Weather v2/v3 are not included yet. They should only be added after a concrete public repository and asset license are verified.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Breezy Weather Icon Pack
|
||||
|
||||
- Source: https://github.com/breezy-weather/breezy-weather
|
||||
- Related icon-pack documentation: https://github.com/breezy-weather/breezy-weather-icon-packs
|
||||
- Imported path: `app/src/main/res/drawable/weather_*.png`
|
||||
- License note: Breezy Weather code is LGPL-3.0; verify individual asset terms before external redistribution.
|
||||
- Usage: bundled as a selectable weather visual style at user request.
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 960 B |
|
After Width: | Height: | Size: 960 B |
|
After Width: | Height: | Size: 960 B |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,7 @@
|
||||
# Geometric Weather Icon Pack
|
||||
|
||||
- Source: https://github.com/breezy-weather/geometric-icon-provider
|
||||
- Related references: https://github.com/WangDaYeeeeee/GeometricWeather and https://app.sharess.cn/page/app/detail?id=hfkx5khY8cWw6bTLWKadOg%3D%3D
|
||||
- Imported path: `app/src/main/res/drawable/weather_*.png`
|
||||
- License note: provider code is LGPL-3.0; related Breezy icon-pack documentation marks Geometric assets as non-free.
|
||||
- Usage: bundled as a selectable weather visual style at user request.
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.9 KiB |