Files
LanMountainDesktop/.trae/documents/class-schedule-widget-redesign.md
lincube 7a70476ce8 合并对设置系统的更新 (#11)
* Add Windows system chrome patchers (Harmony)

Introduce support for toggling the system chrome on Windows using Harmony patchers. Adds Lib.Harmony.Thin to package props and project, new patcher infrastructure (ChromePatchState, PatcherEntrance) and two Harmony patches that disable FluentAvalonia's Windows chrome when configured. Program.cs now loads the chrome setting and installs patchers conditionally on Windows/x86-x64. Settings viewmodel and view updated: expose IsWindowsOs, require restart on appearance changes, migrate SettingsWindow to FAAppWindow and adapt titlebar/layout (include Windows caption placeholder and footer menu items). Also add a .gitkeep and a build log file.

* Refactor settings window UI and theming

Improve theming and layout for the Settings window and related services.

- MaterialSurfaceService: add special material parameters for SettingsWindowBackground (lower alpha, no blur) and avoid hot-switching real backdrops for non-settings windows.
- GlassEffectService: add AdaptiveSettingsWindowTintBrush + ResolveSettingsWindowTintAlpha to provide optional content tinting tied to system material mode.
- SettingsWindowService: refactor theme application into ApplyThemeVariantAndResources, ensure settings window material is applied at show/activate times, and tidy theme/resource application flow.
- SettingsWindow.axaml / .axaml.cs: restructure title bar (separate Grid.Row=0 border) and FANavigationView host, add pane-footer toggle button for :minimal layout, use dynamic corner radius resource, and update toggle/visibility/icon logic and responsive layout code.
- SettingsPages: remove some IconText usages and adjust margins; use DesignCornerRadiusLg for update card corner radius.
- Add NuGet.Config to set local globalPackagesFolder and ignore .nuget/packages in .gitignore.

These changes aim to improve visuals, avoid backdrop overdraw, and make the settings window behavior consistent across themes and layouts.

* Add localization and localize settings pages

Add many new localization keys (en-US and zh-CN) for notifications, developer tools, about page, status bar, and video wallpaper. Update Notification, Dev, About and StatusBar view models to use LocalizationService, expose localized ObservableProperties, and refresh localized text at construction. Localize selection options and test notification texts, and fix notification severity handling. Wire up XAML to the new localized properties (About/Dev/StatusBar pages) and update the settings page title for notifications. Also adjust copyright line generation and replace hardcoded placeholders with bound Watermark properties.

* Redesign settings window with fluent shell & search

Rebuild the settings window as a Fluent shell: adds a custom 48-DIP titlebar with Back, pane toggle, icon/title, search box, restart/more menu, and caption-button spacer; moves compact pane toggle into the titlebar and preserves FANavigationView as the primary navigation surface. Introduces a SettingsSearchService (with UI AutoComplete integration, search indexing, navigation-by-result, and search result highlighting) plus focused tests for search filtering and theme material normalization. Adds navigation history/back stack, updates SettingsViewModels for new bindings and localization keys, and updates General/Apearance pages to expose new strings and options. Implements an "auto" system material mode: default in AppSettingsSnapshot, new MaterialAuto constants and normalization/resolution logic in ThemeAppearanceValues, WindowMaterialService and MaterialSurfaceService adjustments to prefer Mica on Win11 and Acrylic on Win10 using TransparencyLevelHint. GlassEffectService and AppearanceThemeService updated to use effective material mode and to track live theme state changes. Adds localization entries (en-US, zh-CN), spec/tasks docs, and other UI/style tweaks to support the redesign.

* fix.修折叠与展开按钮

* Add OOBE startup presentation and settings merge

Introduce a new OOBE step for "Startup & Presentation" that exposes startup and UI preferences in OobeWindow (toggles for taskbar, slide/fade transitions, fused popup, and autostart). Add HostAppSettingsOobeMerger to read/write Host settings.json (PascalCase fields) and MergeStartupPresentation behavior, plus LauncherWindowsStartupService to sync the current Launcher into the Windows Run key on Windows. Wire UI handlers, persist choices on Next, and load defaults when entering the step. Include unit tests for the merger, adjust SettingsWindow navigation pane/toggle handling, and update docs/LAUNCHER.md to describe the new OOBE step and implementation files.

* Move whiteboard persistence to file storage

Switch whiteboard note storage from legacy DB rows to per-note JSON files and add migration support. Update WhiteboardNoteSnapshot schema (version bump, viewport, canvas, expires, PathSvgData) and change IWhiteboardNotePersistenceService.SaveNote to return bool to surface write failures (e.g. read-only files). Implement file-based WhiteboardNotePersistenceService with legacy DB migration/cleanup, retention handling, and logging. Add comprehensive unit tests for persistence, stroke path builder, SVG import and viewport helper. Also add ThirdParty/DotNetCampus.InkCanvas project and reference it in the main csproj, and bump PostHog package to 2.6.0.

* Introduce render gate and chart caching

Replace UI DispatcherTimer polling with a StudySnapshotRenderGate across multiple widgets to queue and apply only the latest analytics snapshot; components updated include StudyDeductionReasonsWidget, StudyEnvironmentWidget, StudyInterruptDensityWidget, StudyNoiseCurveWidget. Add StudySnapshotRenderGate implementation to coordinate rendering and monitoring leases and update subscription/lease lifecycle handling (subscribe/unsubscribe, Acquire/Dispose leases, Clear/Dispose gate). Rewrite chart controls (StudyNoiseCurveChartControl and StudyNoiseDistributionScatterChartControl) to use stable logical-time origins, split series into static vs dynamic tails, add geometry/sample caching, stable jitter/coordinate mapping helpers, and expose internal helpers & counts for testing. Add unit tests (StudyComponentRenderingTests) covering the render gate and chart behaviors (layer counts, logical X mapping, stable jitter, cache rebuild). These changes improve rendering correctness and performance by avoiding redundant renders and enabling deterministic chart layout.

* Use MaterialColorSnapshot in appearance flow

Introduce unified material/color spec and tests, and refactor appearance plumbing to use MaterialColorSnapshot as the single source of truth. Add .trae material-color-service spec/checklist/tasks and integration/unit tests for plugin mapping and appearance VM behavior. AppearanceChangedEvent extended with new appearance change flags and HasChanged logic. ComponentEditorMaterialThemeAdapter rewritten to accept MaterialColorSnapshot and derive palette from snapshot data. Simplify AppearanceSettingsPageViewModel and related view code: remove legacy preview/custom-seed UI logic, preserve material/color fields when updating theme or corner radius, and update save calls to use with-expressions. Update ComponentEditorWindow to use adapter-provided OnPrimary brush and minor docs updates.

* Add material color services, plugin DTOs, and tests

Introduce IPC wire-format appearance DTOs (PluginIsolation.Contracts) and clarify they are distinct from the runtime PluginSdk snapshot. Update PluginSdk comments to document the runtime-facing snapshot shape. Change ComponentColorSchemeHelper to use the HostMaterialColorProvider and add an overload that accepts a MaterialColorSnapshot. Add new services and pipelines (MaterialColorService, MaterialSurfaceService, WindowMaterialService, WallpaperColorPipeline) and refactor AppearanceThemeService to depend on MaterialColorService while removing legacy internal implementations. Add multiple unit tests (ComponentColorSchemeHelper, PluginAppearanceBoundary, SettingsCatalogService, WallpaperSettingsPageViewModel) and update localization resources with new material_color and wallpaper keys.

* Add CODE_WIKI and update localization

Add a comprehensive CODE_WIKI.md documenting project architecture, modules, startup flow, plugin system, testing and developer workflows. Update localization resources (en-US.json, zh-CN.json) with new/translated keys for wallpaper controls (custom color UI), material & color settings (semantic roles, surfaces, refresh/polling state), appearance (corner radius), status bar font size options, privacy policy text, component library labels, clock settings, and new language entry (Korean). Also modify settings-related ViewModels and Settings page views to surface these new features and texts (MaterialColorSettingsPageViewModel.cs, SettingsViewModels.cs, WallpaperSettingsPageViewModel.cs, MainWindow.SettingsHardCut.Stubs.cs, ComponentsSettingsPage.axaml, WallpaperSettingsPage.axaml).

* Add Data settings page and storage scanner

Introduce a new "Data" settings page to visualize and manage local app storage. Adds DataStorageService (scanning, disk info, clean operations), DataSettingsPageViewModel, XAML view and code-behind, and HexToColor/HexToBrush converters; registers converters in App.axaml. Also update localization strings for the new page and add icon mapping so the settings entry uses the Database icon. Enables per-category and global cleaning workflows and formatted size display.

* Add IPC backoff/retries and safer disposal

Introduce exponential backoff, jitter and retry logic across IPC components to improve robustness and avoid tight retry loops; make disposal idempotent and add connection guards. Key changes:
- LauncherCoordinatorIpcServer / LauncherIpcServer: add backoff constants, ComputeBackoff(), consecutive error tracking and delayed retries with jitter.
- LanMountainDesktopIpcClient / LauncherIpcClient: add connect retry loops, timeouts, delayed retries, improved error logging, and use ArrayPool for buffered async writes; ensure proper cleanup on failures.
- PublicIpcHostService: add disposed flag, guard OnPeerConnected and Dispose, and clear connected peers on dispose.
- Add many auto-generated commit analysis docs under docs/auto_commit_md and new scripts for analyzing/generating commit docs.
These changes aim to make IPC connection handling more resilient and resource-safe.

* Add preview controls and settings UI tweaks

Introduce GridPreviewControl and CornerRadiusPreviewControl for visual previews and wire them into the Components settings (add ScreenAspectRatio, CornerRadiusPreviewValue, and screen aspect init). Refactor ComponentsSettingsPage UI to show live previews. Improve DataSettingsPage layout and storage bar logic (use item percentages directly, include remaining segment, adjust visuals and visibility triggers). Simplify LauncherSettingsPage header/appearance layout. Add SECURITY_AUDIT_REPORT.md, analysis summary, mockup HTML, and a local .claude settings file.

* Add install checkpoint/resume and DDSS workflows

Introduce install checkpoint support and resume logic for updates, plus related locking and validation. Adds InstallCheckpoint model, AppJsonContext serialization, and UpdatePaths helpers for deployment lock, apply-in-progress lock and install-checkpoint path. UpdateEngineService gains checkpoint load/save/delete, incoming-state validation, resume logic for PLONDS and legacy updates, apply lock handling, and safer cleanup; ApplyPendingPlondsUpdateAsync and ApplyPendingUpdate flow updated accordingly. Add DeploymentLock contract and extend UpdateState with pause/resume/cancel helpers. Tests updated to cover stale/valid checkpoint resume and legacy/PLONDS flows. CI: enhance ddss-publish to detect release channel, validate S3 assets, prepare and atomically publish channel pointer; add ddss-rollback workflow to publish rollbacks; adjust plonds-build concurrency and release events.

* changed.更了好多

* fix.消息盒子媒体播放器组件服务修复

* change.重做天气,为回到系统提供自定义功能。

* feat.airapp与融合桌面

* feat.动画优化与更新界面

* feat.数字时钟,白板功能修复

* feat.完善了时钟轻应用,为启动器提供了多语言支持

* feat.发布与打包优化

* changed.天气选项卡更新
2026-05-19 07:55:21 +08:00

15 KiB
Raw Blame History

课程表组件视觉重构 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: 彻底重构阑山桌面的课程表ClassScheduleWidget组件视觉设计参考小爱课程表的桌面小部件风格实现时间轴+色块卡片布局、科目自动配色、当前课程进度高亮等现代化视觉效果。

Architecture: 保留现有数据层ClassIslandScheduleDataService、Models和组件注册机制不变仅重构 Widget 的 UI 渲染层XAML + code-behind 中的渲染逻辑)。新增科目配色服务,为每门课程分配稳定的区分色。先创建 HTML Mock 验证视觉效果,再移植到 Avalonia XAML。

Tech Stack: Avalonia UI (XAML + C# code-behind)、HTML/CSS (Mock 预览)


当前状态分析

现有组件结构

  • XAML: ClassScheduleWidget.axaml — 仅定义了 RootBorder、HeaderGrid日期+星期+课数、ScrollViewer+CourseListPanel、StatusTextBlock
  • Code-behind: ClassScheduleWidget.axaml.cs — 所有课程项 UI 在 CreateSingleItemControl() 中手动构建:圆点(Bullet) + 文字栈(课程名/时间/详情)
  • 数据层: ClassIslandScheduleDataService + ClassIslandScheduleModels — 不变
  • 编辑器: ClassScheduleComponentEditor.axaml(.cs) — 不变

现有设计问题

  1. 视觉单调: 仅用小圆点区分课程,所有课程外观一致,缺乏层次感
  2. 信息密度低: 课程名、时间、教师名挤在一行,可读性差
  3. 当前课不突出: 仅通过圆点颜色变化标识当前课程,几乎无法一眼识别
  4. 色彩硬编码: 颜色值直接写在 C# 中,不使用语义资源键,不遵循 VISUAL_SPEC
  5. 无时间轴感: 列表式排列无法体现课程的时间先后和持续长度

小爱课程表参考设计特征

  1. 时间轴布局: 左侧显示时间刻度,右侧是课程色块卡片
  2. 科目配色: 每门课程自动分配一种柔和区分色,卡片使用对应色块背景
  3. 当前课高亮: 正在进行的课程有明显的视觉强调(放大/进度条/发光)
  4. 进度指示: 当前课程显示上课进度(已过时间/总时长)
  5. 紧凑信息: 课程名+教室/教师信息在色块内清晰排列
  6. 课间分隔: 课间休息区域有视觉分隔(虚线/淡色区域)

设计方案

视觉论文 (Visual Thesis)

时间轴驱动的色块卡片布局,柔和科目配色,当前课程进度高亮——在桌面小组件有限空间内实现信息密度与美感的平衡。

布局结构

┌─────────────────────────────────────┐
│  7/24  周一          今天3节课       │  ← 头部:日期 + 星期 + 课数
├─────────────────────────────────────┤
│  08:00 ┌──────────────────────┐     │
│        │  语文                │     │  ← 科目色块卡片
│        │  王老师 · 教室301     │     │
│  08:45 └──────────────────────┘     │
│        ┌──────────────────────┐     │
│        │  数学 ████████░░ 75% │     │  ← 当前课:进度条 + 高亮
│        │  李老师 · 教室205     │     │
│  09:30 └──────────────────────┘     │
│  ...                                │
└─────────────────────────────────────┘

科目配色方案

使用一组预定义的柔和色彩,按科目名哈希值稳定分配:

  • 语文: #5B8FF9 (蓝)
  • 数学: #F6903D (橙)
  • 英语: #5AD8A6 (绿)
  • 物理: #E8684A (红)
  • 化学: #9270CA (紫)
  • 生物: #FF9845 (琥珀)
  • 历史: #1E9493 (青)
  • 地理: #FF99C3 (粉)
  • 政治: #7262FD (靛)
  • 体育: #78D3F8 (天蓝)
  • 默认: #8B95A5 (灰)

当前课程高亮

  • 卡片左侧显示 3px 宽的强调色竖条
  • 卡片底部显示细进度条(已过时间/总时长)
  • 卡片背景使用科目色的 15% 透明度版本
  • 非当前课程使用科目色的 8% 透明度版本

文件变更清单

文件 操作 说明
LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml 修改 重构 XAML 布局:时间轴+卡片区域
LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs 修改 重构渲染逻辑:色块卡片、科目配色、进度条
LanMountainDesktop/Views/Components/SubjectColorService.cs 新建 科目配色服务:稳定哈希分配颜色
mocks/class-schedule-mock.html 新建 HTML Mock 预览(亮色+暗色)

Task 分解

Task 1: 创建 HTML Mock 预览

Files:

  • Create: mocks/class-schedule-mock.html

  • Step 1: 创建 HTML Mock 文件

创建完整的 HTML Mock包含

  • 亮色/暗色主题切换
  • 时间轴+色块卡片布局
  • 科目自动配色
  • 当前课程进度条高亮
  • 课间分隔区域
  • 响应式尺寸(模拟桌面组件 2x4 / 4x4 等尺寸)

Mock 中应包含示例数据:

08:00-08:45  语文  王老师
08:55-09:40  数学  李老师 (当前课,进度 60%)
09:50-10:35  英语  张老师
10:45-11:30  物理  赵老师
14:00-14:45  化学  陈老师
14:55-15:40  生物  刘老师
  • Step 2: 在浏览器中打开 Mock 验证效果

Run: start mocks/class-schedule-mock.html

  • Step 3: 根据视觉效果调整 Mock 细节

调整间距、色值、字体大小、进度条样式等直到满意。


Task 2: 创建科目配色服务

Files:

  • Create: LanMountainDesktop/Views/Components/SubjectColorService.cs

  • Step 1: 实现 SubjectColorService

using System;
using Avalonia.Media;

namespace LanMountainDesktop.Views.Components;

internal static class SubjectColorService
{
    private static readonly (string Name, string Hex)[] Palette = [
        ("语文", "#5B8FF9"),
        ("数学", "#F6903D"),
        ("英语", "#5AD8A6"),
        ("物理", "#E8684A"),
        ("化学", "#9270CA"),
        ("生物", "#FF9845"),
        ("历史", "#1E9493"),
        ("地理", "#FF99C3"),
        ("政治", "#7262FD"),
        ("体育", "#78D3F8"),
        ("音乐", "#F25E7E"),
        ("美术", "#C2A1FD"),
    ];

    private static readonly string DefaultHex = "#8B95A5";

    public static Color ResolveColor(string subjectName)
    {
        foreach (var (name, hex) in Palette)
        {
            if (subjectName.Contains(name, StringComparison.OrdinalIgnoreCase))
            {
                return Color.Parse(hex);
            }
        }

        var hash = StableHash(subjectName);
        var index = (int)(hash % (uint)Palette.Length);
        return Color.Parse(Palette[index].Hex);
    }

    public static Color ResolveBackgroundColor(string subjectName, bool isCurrent, bool isNight)
    {
        var baseColor = ResolveColor(subjectName);
        var alpha = isCurrent ? 0.18 : 0.08;
        return new Color(
            (byte)(alpha * 255),
            baseColor.R,
            baseColor.G,
            baseColor.B);
    }

    public static Color ResolveForegroundColor(string subjectName, bool isNight)
    {
        var baseColor = ResolveColor(subjectName);
        return isNight
            ? new Color(0xFF, (byte)Math.Min(255, baseColor.R + 60), (byte)Math.Min(255, baseColor.G + 60), (byte)Math.Min(255, baseColor.B + 60))
            : baseColor;
    }

    private static uint StableHash(string input)
    {
        uint hash = 5381;
        foreach (var c in input)
        {
            hash = ((hash << 5) + hash) ^ (uint)c;
        }
        return hash;
    }
}
  • Step 2: 验证编译通过

Run: dotnet build LanMountainDesktop/LanMountainDesktop.csproj -c Debug --no-restore


Task 3: 重构 ClassScheduleWidget XAML 布局

Files:

  • Modify: LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml

  • Step 1: 重写 XAML 布局

新的 XAML 结构:

  • RootBorder 保持 DesignCornerRadiusComponent
  • 头部区域:日期(大号)+ 星期 + 课数 + 进度摘要
  • 课程列表区域ScrollViewer 包裹 StackPanel
  • 每个 CourseItem 将在 code-behind 中构建为Grid(时间列 + 卡片列)
    • 时间列StartTime / EndTime 垂直排列
    • 卡片列Border(科目色背景) > StackPanel(课程名 + 教师信息 + 进度条)

XAML 只定义骨架,课程项仍由 code-behind 动态构建(因为需要科目配色和进度计算)。

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="LanMountainDesktop.Views.Components.ClassScheduleWidget">
    <Border x:Name="RootBorder"
            Background="{DynamicResource AdaptiveSurfaceRaisedBrush}"
            BorderBrush="{DynamicResource AdaptiveButtonBorderBrush}"
            BorderThickness="1"
            CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
            Padding="0">
        <Grid x:Name="LayoutGrid"
              RowDefinitions="Auto,*">
            <Grid x:Name="HeaderGrid"
                  ColumnDefinitions="Auto,*,Auto"
                  Padding="16,12,16,8">
                <StackPanel x:Name="DateGroup"
                            Orientation="Horizontal"
                            VerticalAlignment="Center">
                    <TextBlock x:Name="MonthTextBlock"
                               FontWeight="Bold"
                               TextTrimming="CharacterEllipsis" />
                    <TextBlock x:Name="SlashTextBlock"
                               Text="/"
                               FontWeight="Bold" />
                    <TextBlock x:Name="DayTextBlock"
                               FontWeight="Bold"
                               TextTrimming="CharacterEllipsis" />
                </StackPanel>
                <TextBlock x:Name="WeekdayTextBlock"
                           Grid.Column="1"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           FontWeight="SemiBold"
                           TextTrimming="CharacterEllipsis" />
                <Border x:Name="ClassCountBadge"
                        Grid.Column="2"
                        VerticalAlignment="Center"
                        Padding="8,3"
                        CornerRadius="{DynamicResource DesignCornerRadiusMicro}">
                    <TextBlock x:Name="ClassCountTextBlock"
                               FontWeight="SemiBold"
                               TextTrimming="CharacterEllipsis" />
                </Border>
            </Grid>
            <ScrollViewer x:Name="ContentScrollViewer"
                          Grid.Row="1"
                          HorizontalScrollBarVisibility="Disabled"
                          VerticalScrollBarVisibility="Auto">
                <StackPanel x:Name="CourseListPanel"
                            Spacing="4" />
            </ScrollViewer>
            <TextBlock x:Name="StatusTextBlock"
                       Grid.Row="1"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       TextAlignment="Center"
                       IsVisible="False"
                       TextWrapping="Wrap" />
        </Grid>
    </Border>
</UserControl>

Task 4: 重构 ClassScheduleWidget 渲染逻辑

Files:

  • Modify: LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs

  • Step 1: 扩展 CourseItemViewModel

在现有 record 中增加字段:

private sealed record CourseItemViewModel(
    string Name,
    string TimeRange,
    string Detail,
    bool IsCurrent,
    TimeSpan StartTime,
    TimeSpan EndTime,
    double Progress);
  • Step 2: 修改 BuildCourseItemViewModels 计算进度

在构建 ViewModel 时,对当前课程计算 Progress = (now - startTime) / (endTime - startTime)。

  • Step 3: 重写 CreateSingleItemControl

新的课程项 UI 结构:

Grid (2列: 时间列 Auto + 卡片列 *)
├── StackPanel (时间列)
│   ├── TextBlock (开始时间, 如 "08:00")
│   └── TextBlock (结束时间, 如 "08:45", 较淡)
└── Border (卡片列, 科目色背景, 圆角 DesignCornerRadiusSm)
    ├── 左侧强调竖条 (当前课显示, 3px宽, 科目色)
    └── StackPanel
        ├── TextBlock (课程名, 科目色前景, 加粗)
        ├── TextBlock (教师/教室, 次要色)
        └── ProgressBar (当前课显示, 科目色)

关键改动点:

  1. 移除圆点(Bullet),改用时间轴左侧时间标签
  2. 课程卡片使用 SubjectColorService 配色
  3. 当前课程卡片左侧显示强调竖条 + 底部进度条
  4. 课间区域用淡色分隔线标识
  5. 颜色使用语义资源键(AdaptiveTextPrimaryBrush 等),科目色通过 SubjectColorService 获取
  • Step 4: 重写 ApplyAdaptiveLayout

更新自适应布局逻辑:

  • 头部日期/星期/课数徽章的字号和间距

  • 移除旧的圆点、文字栈相关计算

  • 新增时间列宽度、卡片圆角、进度条高度等计算

  • 使用 ComponentChromeCornerRadiusHelper 获取圆角 Token

  • Step 5: 更新 IncrementalUpdateItems 和 IncrementalUpdateCurrentCourseHighlight

适配新的 UI 结构:

  • 更新进度条值

  • 更新科目色背景

  • 更新强调竖条可见性

  • Step 6: 更新 RefreshSchedule 中的时间计算

BuildCourseItemViewModels 中传入 StartTime/EndTime/Progress

  • Step 7: 验证编译通过

Run: dotnet build LanMountainDesktop/LanMountainDesktop.csproj -c Debug


Task 5: 验证与测试

  • 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. 科目配色: 使用预定义调色板 + 哈希回退,不依赖 ClassIsland 数据中的科目颜色(因为 ClassIsland 不提供科目颜色字段)
  2. 进度条: 仅当前课程显示进度条,非当前课程不显示
  3. 课间分隔: 用 4px 间距 + 可选的淡色虚线分隔,不做复杂的课间休息区域
  4. Mock 优先: 先完成 HTML Mock 确认视觉效果,再实现 Avalonia 代码
  5. 编辑器不变: ClassScheduleComponentEditor 不需要修改
  6. 数据层不变: ClassIslandScheduleDataService 和 Models 不需要修改
  7. 接口兼容: IDesktopComponentWidget、ITimeZoneAwareComponentWidget、IComponentPlacementContextAware 接口实现不变

验证步骤

  1. HTML Mock 在浏览器中展示效果满意
  2. Avalonia 项目编译通过
  3. 运行项目,课程表组件显示新布局
  4. 亮色/暗色主题切换正常
  5. 当前课程高亮和进度条正常
  6. 科目配色稳定(同一科目每次显示颜色一致)
  7. 测试通过