跳转至

Phase 2: Base 库核心详细设计文档

文档信息

项目 内容
文档版本 v1.0
创建日期 2026-02-20
阶段代号 Phase 2 - Base 库核心
预计周期 3~4 周
依赖阶段 Phase 0, Phase 1

一、阶段目标

1.1 核心目标

建立所有上层模块依赖的基础设施,包括主题引擎、动画管理、分辨率适配、配置中心和日志系统。

1.2 具体交付物

  • [ ] ThemeEngine 主题引擎模块
  • [ ] AnimationManager 动画管理器
  • [ ] DPIManager 分辨率适配管理器
  • [ ] ConfigStore 配置中心
  • [ ] Logger 日志系统
  • [ ] 各模块单元测试

二、模块架构设计

2.1 整体依赖关系

┌──────────────────────────────────────────────────────────┐
│                   Application Layer                       │
│                  (Shell / Third-party Apps)               │
├──────────────────────────────────────────────────────────┤
│                         SDK Layer                         │
├──────────────────────────────────────────────────────────┤
│                      Base Library                         │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐      │
│  │ ThemeEngine  │ │AnimationMgr  │ │  DPIManager  │      │
│  └──────────────┘ └──────────────┘ └──────────────┘      │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐      │
│  │ ConfigStore  │ │   Logger     │ │HardwareProbe │      │
│  └──────────────┘ └──────────────┘ └──────────────┘      │
├──────────────────────────────────────────────────────────┤
│                      Qt6 Framework                        │
│  Core / Gui / Widgets / Multimedia / Network             │
└──────────────────────────────────────────────────────────┘

2.2 Base 库目录结构

src/base/
├── include/CFDesktop/Base/
│   ├── ThemeEngine/
│   │   ├── ThemeEngine.h          # 主题引擎主类
│   │   ├── Theme.h                # 主题数据结构
│   │   ├── ThemeLoader.h          # 主题加载器
│   │   └── ThemeVariables.h       # 主题变量系统
│   │
│   ├── AnimationManager/
│   │   ├── AnimationManager.h     # 动画管理器
│   │   ├── Animation.h            # 动画基类
│   │   ├── PropertyAnimation.h    # 属性动画
│   │   ├── GroupAnimation.h       # 组动画
│   │   └── AnimationPolicy.h      # 动画策略(来自 Phase 1)
│   │
│   ├── DPIManager/
│   │   ├── DPIManager.h           # DPI 管理器
│   │   ├── DisplayInfo.h          # 显示信息
│   │   └── DPIConverter.h         # 单位转换工具
│   │
│   ├── ConfigStore/
│   │   ├── ConfigStore.h          # 配置存储主类
│   │   ├── ConfigNode.h           # 配置节点
│   │   └── ConfigWatcher.h        # 配置监视器
│   │
│   └── Logger/
│       ├── Logger.h               # 日志主类
│       ├── LogMessage.h           # 日志消息
│       ├── LogSink.h              # 日志输出抽象
│       ├── FileSink.h             # 文件输出
│       ├── ConsoleSink.h          # 控制台输出
│       └── NetworkSink.h          # 网络输出
└── src/
    ├── theme/
    │   ├── ThemeEngine.cpp
    │   ├── ThemeLoader.cpp
    │   ├── QSSProcessor.cpp       # QSS 处理器
    │   └── VariableResolver.cpp   # 变量解析器
    ├── animation/
    │   ├── AnimationManager.cpp
    │   ├── PropertyAnimation.cpp
    │   └── GroupAnimation.cpp
    ├── dpi/
    │   ├── DPIManager.cpp
    │   └── DPIConverter.cpp
    ├── config/
    │   ├── ConfigStore.cpp
    │   └── ConfigWatcher.cpp
    └── logging/
        ├── Logger.cpp
        ├── FileSink.cpp
        ├── ConsoleSink.cpp
        └── NetworkSink.cpp

三、主题引擎 (ThemeEngine)

3.1 主题包结构

assets/themes/
└── default/
    ├── theme.json                 # 主题元数据
    ├── variables/
    │   ├── colors.json            # 颜色变量
    │   ├── sizes.json             # 尺寸变量
    │   └── fonts.json             # 字体变量
    ├── styles/
    │   ├── base.qss               # 基础样式
    │   ├── widgets.qss            # 控件样式
    │   └── animations.qss         # 动画样式
    └── icons/
        ├── actions/               # 动作图标
        ├── status/                # 状态图标
        └── devices/               # 设备图标

3.2 主题元数据格式

文件: assets/themes/default/theme.json

{
    "meta": {
        "name": "Default Light",
        "version": "1.0.0",
        "author": "CFDesktop Team",
        "description": "Default light theme",
        "hwTier": "any"
    },
    "inherit": null,
    "settings": {
        "windowOpacity": 0.95,
        "enableBlur": true,
        "enableShadows": true,
        "animationPolicy": "full"
    }
}

3.3 颜色变量定义

文件: assets/themes/default/variables/colors.json

{
    "primary": "#2196F3",
    "primaryDark": "#1976D2",
    "primaryLight": "#BBDEFB",
    "secondary": "#FF9800",
    "accent": "#FF4081",
    "background": "#FFFFFF",
    "surface": "#F5F5F5",
    "error": "#F44336",
    "success": "#4CAF50",
    "warning": "#FFC107",
    "info": "#2196F3",
    "text": {
        "primary": "#212121",
        "secondary": "#757575",
        "disabled": "#BDBDBD",
        "inverse": "#FFFFFF"
    },
    "divider": "#E0E0E0",
    "shadow": "rgba(0, 0, 0, 0.12)"
}

3.4 QSS 模板语法

/* assets/themes/default/styles/base.qss */
QWidget {
    background-color: @background;
    color: @text.primary;
}

QPushButton {
    background-color: @primary;
    color: @text.inverse;
    border: none;
    border-radius: @radius.medium;
    padding: @padding.normal;
    font-size: @font.size.medium;
}

QPushButton:hover {
    background-color: @primaryLight;
}

QPushButton:pressed {
    background-color: @primaryDark;
}

QPushButton:disabled {
    background-color: @divider;
    color: @text.disabled;
}

3.5 ThemeEngine 类接口

文件: include/CFDesktop/Base/ThemeEngine/ThemeEngine.h

#pragma once
#include <QObject>
#include <QString>
#include <QColor>
#include <QFont>
#include <QMap>
#include "Theme.h"

namespace CFDesktop::Base {

/**
 * @brief 主题引擎主类
 *
 * 负责加载、切换和管理主题,提供变量查询接口。
 * 单例模式,进程内唯一实例。
 */
class ThemeEngine : public QObject {
    Q_OBJECT

public:
    static ThemeEngine* instance();

    /**
     * @brief 加载主题
     * @param themePath 主题路径
     * @return 是否成功
     */
    bool loadTheme(const QString& themePath);

    /**
     * @brief 切换主题
     * @param themeName 主题名称
     */
    void switchTheme(const QString& themeName);

    /**
     * @brief 获取当前主题
     */
    Theme currentTheme() const;

    /**
     * @brief 获取颜色变量
     * @param key 变量名 (支持点分隔路径: "text.primary")
     */
    QColor color(const QString& key) const;

    /**
     * @brief 获取尺寸变量
     * @param key 变量名
     */
    int size(const QString& key) const;

    /**
     * @brief 获取字体变量
     * @param key 变量名
     */
    QFont font(const QString& key) const;

    /**
     * @brief 获取任意变量
     */
    QVariant variable(const QString& key) const;

    /**
     * @brief 应用主题到应用
     * @param app 目标应用
     */
    void applyToApplication(QApplication* app);

    /**
     * @brief 处理 QSS 中的变量引用
     * @param qss 原始 QSS
     * @return 处理后的 QSS
     */
    QString processQSS(const QString& qss) const;

    /**
     * @brief 获取当前主题样式表
     */
    QString styleSheet() const;

    /**
     * @brief 重新加载主题(热更新)
     */
    void reload();

signals:
    /**
     * @brief 主题变化信号
     */
    void themeChanged(const Theme& theme);

    /**
     * @brief 颜色变量变化信号
     */
    void colorChanged(const QString& key, const QColor& color);

private:
    ThemeEngine(QObject* parent = nullptr);
    ~ThemeEngine() = default;

    void loadVariables(const QString& path);
    void loadStyles(const QString& path);
    void resolveThemeInheritance(Theme& theme);
    QString resolveVariables(const QString& input) const;

private:
    static ThemeEngine* s_instance;
    Theme m_currentTheme;
    QMap<QString, QColor> m_colors;
    QMap<QString, int> m_sizes;
    QMap<QString, QFont> m_fonts;
    QMap<QString, QString> m_styleSheets;
    QString m_themePath;
};

} // namespace CFDesktop::Base

3.6 主题降级策略

根据 HWTier 自动应用不同效果:

特性 Low 档 Mid 档 High 档
阴影效果 禁用 简单阴影 完整阴影
圆角 小圆角 (2px) 中圆角 (4px) 大圆角 (8px)
模糊背景 禁用 半透明模糊 全模糊
渐变 禁用 简单渐变 复杂渐变
动画 禁用 基础动画 完整动画

四、动画管理器 (AnimationManager)

4.1 AnimationManager 类接口

文件: include/CFDesktop/Base/AnimationManager/AnimationManager.h

#pragma once
#include <QObject>
#include <QPointer>
#include <QVariant>
#include <QPropertyAnimation>
#include "Animation.h"

namespace CFDesktop::Base {

/**
 * @brief 动画管理器
 *
 * 统一管理所有动画,根据 HWTier 自动调整动画参数。
 * Low 档位时所有动画时长归零,实现透明降级。
 */
class AnimationManager : public QObject {
    Q_OBJECT

public:
    static AnimationManager* instance();

    /**
     * @brief 创建属性动画
     * @param target 目标对象
     * @param propertyName 属性名
     * @param startValue 起始值
     * @param endValue 结束值
     * @param duration 动画时长 (毫秒),Low 档会自动归零
     * @return 动画指针
     */
    QPropertyAnimation* createPropertyAnimation(
        QObject* target,
        const QByteArray& propertyName,
        const QVariant& startValue,
        const QVariant& endValue,
        int duration = 300
    );

    /**
     * @brief 创建淡入动画
     */
    QPropertyAnimation* createFadeIn(
        QWidget* widget,
        int duration = 300
    );

    /**
     * @brief 创建淡出动画
     */
    QPropertyAnimation* createFadeOut(
        QWidget* widget,
        int duration = 300
    );

    /**
     * @brief 创建滑入动画
     */
    QPropertyAnimation* createSlideIn(
        QWidget* widget,
        Qt::Direction direction,
        int distance = 100,
        int duration = 300
    );

    /**
     * @brief 创建缩放动画
     */
    QPropertyAnimation* createScale(
        QWidget* widget,
        qreal fromScale,
        qreal toScale,
        int duration = 300
    );

    /**
     * @brief 创建旋转动画
     */
    QPropertyAnimation* createRotation(
        QWidget* widget,
        qreal fromAngle,
        qreal toAngle,
        int duration = 300
    );

    /**
     * @brief 创建并行动画组
     */
    QParallelAnimationGroup* createParallelGroup(
        const QList<QAbstractAnimation*>& animations
    );

    /**
     * @brief 创建串行动画组
     */
    QSequentialAnimationGroup* createSequentialGroup(
        const QList<QAbstractAnimation*>& animations
    );

    /**
     * @brief 启动动画
     */
    void start(QAbstractAnimation* animation);

    /**
     * @brief 停止动画
     */
    void stop(QAbstractAnimation* animation);

    /**
     * @brief 停止所有动画
     */
    void stopAll();

    /**
     * @brief 调整动画时长(根据 HWTier)
     * @param originalDuration 原始时长
     * @return 调整后的时长
     */
    int adjustDuration(int originalDuration) const;

    /**
     * @brief 是否启用动画
     */
    bool isAnimationEnabled() const;

signals:
    /**
     * @brief 动画策略变化信号
     */
    void animationPolicyChanged(const AnimationPolicy& policy);

private:
    AnimationManager(QObject* parent = nullptr);
    ~AnimationManager() = default;

    void updatePolicy();
    QPropertyAnimation* createBaseAnimation(
        QObject* target,
        const QByteArray& propertyName
    );

private:
    static AnimationManager* s_instance;
    AnimationPolicy m_policy;
    QList<QPointer<QAbstractAnimation>> m_runningAnimations;
};

} // namespace CFDesktop::Base

4.2 预定义动画类型

namespace CFDesktop::Base {

/**
 * @brief 预定义动画类型
 */
enum class AnimationType {
    None,           // 无动画
    Fade,           // 淡入淡出
    Slide,          // 滑动
    Scale,          // 缩放
    Rotate,         // 旋转
    Bounce,         // 弹跳
    Elastic,        // 弹性
    Complex         // 复杂组合
};

/**
 * @brief 缓动曲线类型
 */
enum class EasingType {
    Linear,
    InQuad, OutQuad, InOutQuad,
    InCubic, OutCubic, InOutCubic,
    InQuart, OutQuart, InOutQuart,
    InQuint, OutQuint, InOutQuint,
    InBack, OutBack, InOutBack,
    InBounce, OutBounce, InOutBounce
};

/**
 * @brief 获取 Qt 缓动曲线
 */
QEasingCurve easingCurve(EasingType type);

} // namespace CFDesktop::Base

五、DPI 管理器 (DPIManager)

5.1 DPIManager 类接口

文件: include/CFDesktop/Base/DPIManager/DPIManager.h

#pragma once
#include <QObject>
#include <QRect>
#include "DisplayInfo.h"

namespace CFDesktop::Base {

/**
 * @brief DPI 管理器
 *
 * 提供分辨率无关的尺寸单位,支持多屏幕和热插拔。
 */
class DPIManager : public QObject {
    Q_OBJECT

public:
    static DPIManager* instance();

    /**
     * @brief 密度无关像素 (dp) 转换为物理像素
     *
     * 类 Android 的 dp 单位,在 160dpi 屏幕上 1dp = 1px
     */
    int dp(int value) const;

    /**
     * @brief 缩放无关像素 (sp) 转换为物理像素
     *
     * 用于字体大小,会跟随用户字体缩放设置
     */
    int sp(int value) const;

    /**
     * @brief 物理像素转换为 dp
     */
    int pxToDp(int pixels) const;

    /**
     * @brief 获取屏幕 DPI
     */
    int screenDPI() const;

    /**
     * @brief 获取设备像素比
     */
    qreal devicePixelRatio() const;

    /**
     * @brief 获取屏幕尺寸 (英寸)
     */
    QSizeF screenSizeInches() const;

    /**
     * @brief 获取屏幕逻辑分辨率
     */
    QSize logicalSize() const;

    /**
     * @brief 获取屏幕物理分辨率
     */
    QSize physicalSize() const;

    /**
     * @brief 是否为高 DPI 屏幕
     */
    bool isHighDPI() const;

    /**
     * @brief 注入屏幕参数(用于模拟器)
     */
    void injectScreenParameters(
        int dpi,
        qreal devicePixelRatio,
        const QSize& size
    );

    /**
     * @brief 清除注入的参数
     */
    void clearInjectedParameters();

signals:
    /**
     * @brief DPI 变化信号
     */
    void dpiChanged(int oldDpi, int newDpi);

    /**
     * @brief 屏幕变化信号
     */
    void screenChanged(const QRect& geometry);

private:
    DPIManager(QObject* parent = nullptr);
    ~DPIManager() = default;

    void detectScreenParameters();
    void updateDpi();

private:
    static DPIManager* s_instance;
    int m_dpi = 96;
    qreal m_devicePixelRatio = 1.0;
    QSize m_logicalSize;
    QSize m_physicalSize;
    bool m_hasInjectedParams = false;
};

/**
 * @brief 便捷函数
 */
inline int dp(int value) { return DPIManager::instance()->dp(value); }
inline int sp(int value) { return DPIManager::instance()->sp(value); }

} // namespace CFDesktop::Base

5.2 DPI 计算公式

int DPIManager::dp(int value) const {
    // 基准 DPI 为 160
    const qreal BASE_DPI = 160.0;
    return qRound(value * m_dpi / BASE_DPI * m_devicePixelRatio);
}

int DPIManager::sp(int value) const {
    // sp 考虑字体缩放因子
    const qreal BASE_DPI = 160.0;
    qreal fontScale = QApplication::font().pointSizeF() / 10.0;
    return qRound(value * m_dpi / BASE_DPI * m_devicePixelRatio * fontScale);
}

5.3 常用尺寸定义

namespace CFDesktop::Base::Sizes {
    // 间距 (使用 dp)
    inline int tiny() { return dp(2); }
    inline int small() { return dp(4); }
    inline int normal() { return dp(8); }
    inline int medium() { return dp(16); }
    inline int large() { return dp(24); }
    inline int xlarge() { return dp(32); }
    inline int xxlarge() { return dp(48); }

    // 圆角
    inline int radiusSmall() { return dp(2); }
    inline int radiusMedium() { return dp(4); }
    inline int radiusLarge() { return dp(8); }
    inline int radiusXLarge() { return dp(16); }

    // 控件尺寸
    inline int buttonHeight() { return dp(40); }
    inline int inputHeight() { return dp(36); }
    inline int iconSizeSmall() { return dp(16); }
    inline int iconSizeMedium() { return dp(24); }
    inline int iconSizeLarge() { return dp(48); }
}

六、配置中心 (ConfigStore)

6.1 ConfigStore 类接口

文件: include/CFDesktop/Base/ConfigStore/ConfigStore.h

#pragma once
#include <QObject>
#include <QString>
#include <QVariant>
#include <QSettings>
#include "ConfigNode.h"

namespace CFDesktop::Base {

/**
 * @brief 配置类型
 */
enum class ConfigType {
    System,     // 系统配置 (/etc/CFDesktop/config.conf)
    User,       // 用户配置 (~/.config/CFDesktop/config.conf)
    App,        // 应用配置
    Temp        // 临时配置 (内存)
};

/**
 * @brief 配置中心
 *
 * 提供层级化的配置存储,支持命名空间和变更监听。
 */
class ConfigStore : public QObject {
    Q_OBJECT

public:
    static ConfigStore* instance();

    /**
     * @brief 获取配置值
     * @param key 配置键,支持点分隔命名空间 (如 "ui.theme.name")
     * @param defaultValue 默认值
     */
    QVariant get(
        const QString& key,
        const QVariant& defaultValue = QVariant()
    ) const;

    /**
     * @brief 设置配置值
     * @param key 配置键
     * @param value 配置值
     * @param type 配置类型
     */
    void set(
        const QString& key,
        const QVariant& value,
        ConfigType type = ConfigType::User
    );

    /**
     * @brief 删除配置
     */
    void remove(const QString& key, ConfigType type = ConfigType::User);

    /**
     * @brief 检查配置是否存在
     */
    bool contains(const QString& key) const;

    /**
     * @brief 获取配置节点
     */
    ConfigNode node(const QString& path) const;

    /**
     * @brief 保存配置
     */
    void save(ConfigType type = ConfigType::User);

    /**
     * @brief 重新加载配置
     */
    void reload(ConfigType type = ConfigType::User);

    /**
     * @brief 设置配置变更监听
     * @param key 监听的键
     * @param receiver 接收对象
     * @param slot 槽函数
     */
    void watch(
        const QString& key,
        QObject* receiver,
        const char* slot
    );

signals:
    /**
     * @brief 配置变化信号
     */
    void configChanged(const QString& key, const QVariant& value);

private:
    ConfigStore(QObject* parent = nullptr);
    ~ConfigStore();

    void initialize();
    QString normalizeKey(const QString& key) const;
    QSettings* settingsForType(ConfigType type) const;

private:
    static ConfigStore* s_instance;
    QScopedPointer<QSettings> m_systemSettings;
    QScopedPointer<QSettings> m_userSettings;
    QHash<QString, QVariant> m_tempSettings;
    QMultiHash<QString, QPointer<QObject>> m_watchers;
};

/**
 * @brief 便捷访问函数
 */
template<typename T>
T getConfig(const QString& key, const T& defaultValue = T()) {
    return ConfigStore::instance()->get(key, QVariant::fromValue(defaultValue)).value<T>();
}

template<typename T>
void setConfig(const QString& key, const T& value) {
    ConfigStore::instance()->set(key, QVariant::fromValue(value));
}

} // namespace CFDesktop::Base

6.2 配置文件格式

系统配置: /etc/CFDesktop/config.conf

[General]
Version=1.0

[Hardware]
Tier=auto
MaxMemoryMB=512

[UI]
Theme=default
EnableAnimations=auto
RenderingBackend=auto

[Network]
AutoConnect=true
UpdateCheck=true

[Logging]
Level=Info
MaxFileSizeMB=10
MaxFiles=5

用户配置: ~/.config/CFDesktop/config.conf

[General]
Language=zh_CN

[UI]
Theme=dark
EnableAnimations=true
StatusBarPosition=top

[User]
Name=User
AutoLogin=false

七、日志系统 (Logger)

7.1 Logger 类接口

文件: include/CFDesktop/Base/Logger/Logger.h

#pragma once
#include <QObject>
#include <QString>
#include "LogMessage.h"

namespace CFDesktop::Base {

/**
 * @brief 日志等级
 */
enum class LogLevel {
    Trace = 0,
    Debug,
    Info,
    Warning,
    Error,
    Fatal
};

/**
 * @brief 日志输出抽象基类
 */
class LogSink {
public:
    virtual ~LogSink() = default;
    virtual void write(const LogMessage& message) = 0;
    virtual void flush() = 0;
};

/**
 * @brief 日志主类
 *
 * 提供统一的日志接口,支持多个输出目标。
 */
class Logger : public QObject {
    Q_OBJECT

public:
    static Logger* instance();

    /**
     * @brief 记录日志
     */
    void log(LogLevel level, const QString& tag, const QString& message);

    /**
     * @brief 添加日志输出
     */
    void addSink(LogSink* sink);

    /**
     * @brief 移除日志输出
     */
    void removeSink(LogSink* sink);

    /**
     * @brief 设置最低日志等级
     */
    void setMinLevel(LogLevel level);

    /**
     * @brief 获取最低日志等级
     */
    LogLevel minLevel() const;

    /**
     * @brief 设置日志标签过滤器
     *
     * 只有标签在列表中的日志才会被记录。
     * 空列表表示不过滤。
     */
    void setTagFilter(const QStringList& tags);

    /**
     * @brief 刷新所有日志输出
     */
    void flush();

    // 便捷方法
    void trace(const QString& tag, const QString& message);
    void debug(const QString& tag, const QString& message);
    void info(const QString& tag, const QString& message);
    void warning(const QString& tag, const QString& message);
    void error(const QString& tag, const QString& message);
    void fatal(const QString& tag, const QString& message);

signals:
    /**
     * @brief 日志写入信号
     */
    void messageLogged(const LogMessage& message);

private:
    Logger(QObject* parent = nullptr);
    ~Logger() = default;

    QString formatMessage(const LogMessage& message) const;
    QString levelToString(LogLevel level) const;

private:
    static Logger* s_instance;
    QList<LogSink*> m_sinks;
    LogLevel m_minLevel = LogLevel::Info;
    QStringList m_tagFilters;
    QMutex m_mutex;
};

// 便捷宏
#define LOG_TRACE(tag, msg) Logger::instance()->trace(tag, msg)
#define LOG_DEBUG(tag, msg) Logger::instance()->debug(tag, msg)
#define LOG_INFO(tag, msg)  Logger::instance()->info(tag, msg)
#define LOG_WARNING(tag, msg) Logger::instance()->warning(tag, msg)
#define LOG_ERROR(tag, msg) Logger::instance()->error(tag, msg)
#define LOG_FATAL(tag, msg) Logger::instance()->fatal(tag, msg)

} // namespace CFDesktop::Base

7.2 LogMessage 结构

namespace CFDesktop::Base {

/**
 * @brief 日志消息结构
 */
struct LogMessage {
    LogLevel level;              // 日志等级
    QString tag;                 // 标签
    QString message;             // 消息内容
    QDateTime timestamp;         // 时间戳
    QString threadId;            // 线程 ID
    QString sourceFile;          // 源文件
    int sourceLine;              // 源文件行号
    QString function;            // 函数名

    QString toString() const;
};

} // namespace CFDesktop::Base

7.3 LogSink 实现

FileSink

namespace CFDesktop::Base {

/**
 * @brief 文件日志输出
 */
class FileSink : public LogSink {
public:
    explicit FileSink(const QString& filePath);
    ~FileSink() override;

    void write(const LogMessage& message) override;
    void flush() override;

    void setMaxFileSize(int bytes);
    void setMaxFiles(int count);

private:
    void checkRotation();
    void rotate();

private:
    QFile m_file;
    QTextStream m_stream;
    int m_maxFileSize = 10 * 1024 * 1024;  // 10MB
    int m_maxFiles = 5;
    QMutex m_mutex;
};

} // namespace CFDesktop::Base

ConsoleSink

namespace CFDesktop::Base {

/**
 * @brief 控制台日志输出
 *
 * 支持彩色输出。
 */
class ConsoleSink : public LogSink {
public:
    explicit ConsoleSink(bool enableColor = true);
    ~ConsoleSink() override = default;

    void write(const LogMessage& message) override;
    void flush() override;

private:
    QString colorize(const QString& text, LogLevel level) const;

private:
    bool m_enableColor;
};

} // namespace CFDesktop::Base

NetworkSink

namespace CFDesktop::Base {

/**
 * @brief 网络日志输出
 *
 * 通过 UDP 发送日志到远程服务器。
 */
class NetworkSink : public LogSink {
public:
    explicit NetworkSink(const QString& host, quint16 port);
    ~NetworkSink() override;

    void write(const LogMessage& message) override;
    void flush() override;

private:
    QUdpSocket m_socket;
    QString m_host;
    quint16 m_port;
};

} // namespace CFDesktop::Base

7.4 日志配置

文件: configs/logging.conf

[General]
Level=Debug
# 过滤标签,空表示不过滤
TagFilters=HardwareProbe,ThemeEngine,AnimationManager

[Console]
Enabled=true
Color=true

[File]
Enabled=true
Path=/var/log/CFDesktop/desktop.log
MaxFileSizeMB=10
MaxFiles=5

[Network]
Enabled=false
Host=192.168.1.100
Port=514

八、详细任务清单

8.1 Week 1: 主题引擎

Day 1-2: 基础结构

  • [ ] 创建 ThemeEngine 类框架
  • [ ] 定义主题数据结构
  • [ ] 实现主题加载器
  • [ ] 创建默认主题包

Day 3: 变量系统

  • [ ] 实现变量解析器
  • [ ] 支持点分隔路径
  • [ ] 实现变量继承

Day 4: QSS 处理

  • [ ] 实现 QSS 变量替换
  • [ ] 实现 QSS 合并
  • [ ] 支持主题继承

Day 5: 集成与测试

  • [ ] 集成到应用
  • [ ] 编写单元测试
  • [ ] 性能优化

8.2 Week 2: 动画管理器

Day 1-2: 核心功能

  • [ ] 创建 AnimationManager 类
  • [ ] 实现基础动画创建
  • [ ] 实现 HWTier 降级逻辑

Day 3: 预定义动画

  • [ ] 实现淡入淡出
  • [ ] 实现滑动动画
  • [ ] 实现缩放动画
  • [ ] 实现旋转动画

Day 4: 组动画

  • [ ] 实现并行动画组
  • [ ] 实现串行动画组
  • [ ] 实现动画生命周期管理

Day 5: 测试与优化

  • [ ] 编写单元测试
  • [ ] 性能测试
  • [ ] 内存泄漏检查

8.3 Week 3: DPI 管理器与配置中心

Day 1-2: DPI 管理器

  • [ ] 创建 DPIManager 类
  • [ ] 实现屏幕检测
  • [ ] 实现 dp/sp 转换
  • [ ] 实现模拟器注入接口

Day 3-4: 配置中心

  • [ ] 创建 ConfigStore 类
  • [ ] 实现层级存储
  • [ ] 实现变更监听
  • [ ] 实现配置持久化

Day 5: 测试

  • [ ] 跨平台测试
  • [ ] 单元测试
  • [ ] 集成测试

8.4 Week 4: 日志系统与集成

Day 1-2: 日志系统

  • [ ] 创建 Logger 类
  • [ ] 实现 FileSink
  • [ ] 实现 ConsoleSink
  • [ ] 实现 NetworkSink

Day 3: 日志增强

  • [ ] 实现日志轮转
  • [ ] 实现标签过滤
  • [ ] 实现彩色输出

Day 4: 集成测试

  • [ ] 全模块集成
  • [ ] 端到端测试
  • [ ] 性能测试

Day 5: 文档与发布

  • [ ] API 文档
  • [ ] 使用示例
  • [ ] Code Review

九、验收标准

9.1 主题引擎

  • [ ] 支持动态切换主题
  • [ ] 支持变量继承
  • [ ] Low 档位自动禁用阴影/圆角/渐变
  • [ ] 热重载时间 < 100ms

9.2 动画管理器

  • [ ] Low 档位动画时长归零
  • [ ] 所有预定义动画正常工作
  • [ ] 无内存泄漏
  • [ ] 动画不阻塞主线程

9.3 DPI 管理器

  • [ ] dp/sp 转换准确
  • [ ] 支持模拟器注入
  • [ ] 热插拔屏幕自动适配

9.4 配置中心

  • [ ] 层级存储正常
  • [ ] 变更监听触发
  • [ ] 持久化正常

9.5 日志系统

  • [ ] 多 Sink 并发安全
  • [ ] 日志轮转正常
  • [ ] 性能影响 < 1%

十、下一步行动

完成 Phase 2 后,进入 Phase 3: 输入抽象层