refactor: 完成AppTypography Token化重构,统一UI样式调用

1. 将AppTypography从静态常量类重构为ThemeExtension+静态实例模式,支持全局响应式字体调整
2. 批量替换全量代码中的AppTypography.of(context)调用为静态直接调用
3. 移除多余的rank_provider、canvas_style_middleware导入和preload静态方法
4. 修复多处UI文本样式不一致的问题,统一字体样式调用逻辑
This commit is contained in:
Developer
2026-05-24 09:29:06 +08:00
parent 09d68cd6aa
commit 6da28be851
250 changed files with 2811 additions and 2802 deletions

View File

@@ -85,7 +85,6 @@ enum AppPermission {
CupertinoIcons.location_fill,
'用于获取天气信息和节气提醒,仅使用粗略位置(城市级),不获取精确位置,不会后台追踪。',
Color(0xFF007AFF),
group: PermissionGroup.optional,
usageScenes: ['天气信息 — 当前城市天气', '节气提醒 — 当地节气推送'],
),
bluetooth(
@@ -94,7 +93,6 @@ enum AppPermission {
CupertinoIcons.bluetooth,
'用于文件传输助手的蓝牙配对和设备发现,仅在您使用文件传输功能时请求。',
Color(0xFF5AC8FA),
group: PermissionGroup.optional,
usageScenes: ['文件传输 — 蓝牙配对', '设备发现 — 附近设备搜索'],
),
nearbyDevices(
@@ -103,7 +101,6 @@ enum AppPermission {
CupertinoIcons.antenna_radiowaves_left_right,
'用于文件传输助手的局域网设备发现和连接,仅在您使用文件传输功能时请求。',
Color(0xFF64D2FF),
group: PermissionGroup.optional,
usageScenes: ['文件传输 — 局域网发现', '设备连接 — WiFi直连'],
),
microphone(
@@ -112,7 +109,6 @@ enum AppPermission {
CupertinoIcons.mic_fill,
'用于语音朗读句子、语音搜索、AI对话语音输入。仅在您主动使用语音功能时请求不会后台录音。',
Color(0xFFFF3B30),
group: PermissionGroup.optional,
usageScenes: ['语音朗读 — 朗读句子', '语音搜索 — 语音输入关键词', 'AI对话 — 语音输入消息'],
),
storage(
@@ -121,7 +117,6 @@ enum AppPermission {
CupertinoIcons.folder_fill,
'用于保存编辑的卡片、壁纸到本地导出字体文件和数据。Android 12及以下版本需要此权限。',
Color(0xFFFF9500),
group: PermissionGroup.optional,
usageScenes: ['保存卡片 — 导出到本地', '字体管理 — 下载字体文件', '数据导出 — 导出用户数据'],
),
network(

View File

@@ -1,4 +1,4 @@
/// ============================================================
/// ============================================================
/// 闲言APP — 主题系统
/// 创建时间: 2026-04-20
/// 更新时间: 2026-05-24
@@ -555,6 +555,8 @@ class AppTheme {
fontFamily: extension.fontFamily,
);
AppTypography.instance = typo;
return ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
@@ -562,7 +564,7 @@ class AppTheme {
// ---- 字体 ----
fontFamily: extension.fontFamily,
textTheme: _buildTextTheme(colorScheme, typo),
textTheme: _buildTextTheme(colorScheme),
// ---- Cupertino 交互 ----
cupertinoOverrideTheme: CupertinoThemeData(
@@ -571,16 +573,22 @@ class AppTheme {
barBackgroundColor: extension.bgElevated,
textTheme: CupertinoTextThemeData(
primaryColor: colorScheme.primary,
textStyle: typo.body.copyWith(color: colorScheme.onSurface),
navTitleTextStyle: typo.title3.copyWith(color: colorScheme.onSurface),
navLargeTitleTextStyle: typo.title1.copyWith(
textStyle: AppTypography.body.copyWith(color: colorScheme.onSurface),
navTitleTextStyle: AppTypography.title3.copyWith(
color: colorScheme.onSurface,
),
navActionTextStyle: typo.subhead.copyWith(color: colorScheme.primary),
actionTextStyle: typo.subhead.copyWith(color: colorScheme.primary),
tabLabelTextStyle: typo.caption1,
pickerTextStyle: typo.body,
dateTimePickerTextStyle: typo.body,
navLargeTitleTextStyle: AppTypography.title1.copyWith(
color: colorScheme.onSurface,
),
navActionTextStyle: AppTypography.subhead.copyWith(
color: colorScheme.primary,
),
actionTextStyle: AppTypography.subhead.copyWith(
color: colorScheme.primary,
),
tabLabelTextStyle: AppTypography.caption1,
pickerTextStyle: AppTypography.body,
dateTimePickerTextStyle: AppTypography.body,
),
),
@@ -594,7 +602,9 @@ class AppTheme {
centerTitle: true,
backgroundColor: colorScheme.surface.withValues(alpha: 0.85),
foregroundColor: colorScheme.onSurface,
titleTextStyle: typo.title3.copyWith(color: colorScheme.onSurface),
titleTextStyle: AppTypography.title3.copyWith(
color: colorScheme.onSurface,
),
),
// ---- 底部导航栏 ----
@@ -640,7 +650,7 @@ class AppTheme {
borderRadius: AppRadius.mdBorder,
borderSide: BorderSide(color: colorScheme.primary, width: 1.5),
),
hintStyle: typo.body.copyWith(color: extension.textHint),
hintStyle: AppTypography.body.copyWith(color: extension.textHint),
),
// ---- 按钮 ----
@@ -648,7 +658,7 @@ class AppTheme {
style: FilledButton.styleFrom(
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
textStyle: typo.callout,
textStyle: AppTypography.callout,
shape: RoundedRectangleBorder(borderRadius: AppRadius.mdBorder),
minimumSize: const Size(double.infinity, 48),
),
@@ -657,7 +667,7 @@ class AppTheme {
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: colorScheme.primary,
textStyle: typo.callout,
textStyle: AppTypography.callout,
shape: RoundedRectangleBorder(borderRadius: AppRadius.mdBorder),
side: BorderSide(color: colorScheme.primary, width: 1.2),
minimumSize: const Size(double.infinity, 48),
@@ -667,7 +677,9 @@ class AppTheme {
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: colorScheme.primary,
textStyle: typo.subhead.copyWith(fontWeight: FontWeight.w500),
textStyle: AppTypography.subhead.copyWith(
fontWeight: FontWeight.w500,
),
),
),
@@ -699,7 +711,9 @@ class AppTheme {
chipTheme: ChipThemeData(
backgroundColor: extension.bgSecondary,
selectedColor: colorScheme.primary.withValues(alpha: 0.15),
labelStyle: typo.caption1.copyWith(color: colorScheme.onSurface),
labelStyle: AppTypography.caption1.copyWith(
color: colorScheme.onSurface,
),
shape: RoundedRectangleBorder(borderRadius: AppRadius.fullBorder),
side: BorderSide.none,
padding: const EdgeInsets.symmetric(
@@ -731,22 +745,29 @@ class AppTheme {
// TextTheme
// ============================================================
static TextTheme _buildTextTheme(
ColorScheme colorScheme,
AppTypography typo,
) {
static TextTheme _buildTextTheme(ColorScheme colorScheme) {
return TextTheme(
displayLarge: typo.display.copyWith(color: colorScheme.onSurface),
headlineLarge: typo.title1.copyWith(color: colorScheme.onSurface),
headlineMedium: typo.title2.copyWith(color: colorScheme.onSurface),
headlineSmall: typo.title3.copyWith(color: colorScheme.onSurface),
titleLarge: typo.headline.copyWith(color: colorScheme.onSurface),
bodyLarge: typo.body.copyWith(color: colorScheme.onSurface),
bodyMedium: typo.subhead.copyWith(color: colorScheme.onSurface),
bodySmall: typo.footnote.copyWith(color: colorScheme.onSurface),
labelLarge: typo.callout.copyWith(color: colorScheme.onSurface),
labelMedium: typo.caption1.copyWith(color: colorScheme.onSurface),
labelSmall: typo.caption2.copyWith(color: colorScheme.onSurface),
displayLarge: AppTypography.display.copyWith(
color: colorScheme.onSurface,
),
headlineLarge: AppTypography.title1.copyWith(
color: colorScheme.onSurface,
),
headlineMedium: AppTypography.title2.copyWith(
color: colorScheme.onSurface,
),
headlineSmall: AppTypography.title3.copyWith(
color: colorScheme.onSurface,
),
titleLarge: AppTypography.headline.copyWith(color: colorScheme.onSurface),
bodyLarge: AppTypography.body.copyWith(color: colorScheme.onSurface),
bodyMedium: AppTypography.subhead.copyWith(color: colorScheme.onSurface),
bodySmall: AppTypography.footnote.copyWith(color: colorScheme.onSurface),
labelLarge: AppTypography.callout.copyWith(color: colorScheme.onSurface),
labelMedium: AppTypography.caption1.copyWith(
color: colorScheme.onSurface,
),
labelSmall: AppTypography.caption2.copyWith(color: colorScheme.onSurface),
);
}
}

View File

@@ -1,27 +1,33 @@
/// ============================================================
/// 闲言APP — 字体令牌 (ThemeExtension)
/// 闲言APP — 字体令牌 (ThemeExtension + 静态实例)
/// 创建时间: 2026-04-20
/// 更新时间: 2026-05-24
/// 作用: 统一字体大小/字重定义,响应 fontScale/fontWeight 变化
/// 上次更新: 静态常量类重构为 ThemeExtension支持动态字体缩放与字重调整
/// 上次更新: 静态 getter 委托给 instance无需 context 也能响应主题变化
/// ============================================================
import 'dart:ui';
import 'package:flutter/material.dart';
/// 字体令牌 — ThemeExtension 实现
/// 字体令牌 — ThemeExtension + 静态实例
///
/// 通过 [of] 获取当前主题下的 AppTypography 实例,
/// 自动应用 fontScale / fontWeight / fontFamily
/// 无需手动乘算或覆盖字重。
/// 访问方式:
/// - `AppTypography.xxx` — 静态 getter委托给 [instance],无需 context
/// - `AppTypography.of(context)` — 从 ThemeExtension 获取完整实例
///
/// 静态 getter 自动应用 fontScale / fontWeight / fontFamily
/// 类似 iOS Dynamic Type切换字号/字重即时生效。
class AppTypography extends ThemeExtension<AppTypography> {
const AppTypography({
AppTypography({
this.fontScale = 1.0,
this.fontWeight = FontWeight.w400,
this.fontFamily = 'Inter',
});
/// 全局实例 — 主题构建时自动更新
static AppTypography instance = AppTypography();
/// 字体缩放倍率
final double fontScale;
@@ -31,44 +37,22 @@ class AppTypography extends ThemeExtension<AppTypography> {
/// 字体族
final String fontFamily;
// ---- 基准字号 (静态常量,供无 context 场景使用) ----
// ---- 基准字号 (静态常量) ----
/// 大标题 (启动页品牌字) 34sp Bold
static const double fontDisplay = 34.0;
/// 页面主标题 28sp Bold
static const double fontTitle1 = 28.0;
/// 区块标题 22sp Bold
static const double fontTitle2 = 22.0;
/// 导航栏标题 20sp Semibold
static const double fontTitle3 = 20.0;
/// 列表标题 18sp Semibold
static const double fontHeadline = 18.0;
/// 正文内容 16sp Regular
static const double fontBody = 16.0;
/// 强调文字 16sp Medium
static const double fontCallout = 16.0;
/// 辅助说明 14sp Regular
static const double fontSubhead = 14.0;
/// 脚注 13sp Regular
static const double fontFootnote = 13.0;
/// 标签/提示 12sp Regular
static const double fontCaption1 = 12.0;
/// 极小文字 11sp Regular
static const double fontCaption2 = 11.0;
// ---- 字重调整 ----
/// 根据基准字重偏移量调整目标字重
FontWeight _adjustWeight(FontWeight target) {
final diff = fontWeight.value - FontWeight.w400.value;
final newValue = (target.value + diff).clamp(100, 900);
@@ -76,84 +60,73 @@ class AppTypography extends ThemeExtension<AppTypography> {
return FontWeight.values[idx.clamp(0, 8)];
}
// ---- TextStyle 实例方法 (自动应用 fontScale + fontWeight) ----
// ---- TextStyle 静态 getter (委托给 instance无需 context) ----
/// 大标题 34sp Bold
TextStyle get display => TextStyle(
fontSize: fontDisplay * fontScale,
fontWeight: _adjustWeight(FontWeight.bold),
fontFamily: fontFamily,
);
static TextStyle get display => TextStyle(
fontSize: fontDisplay * instance.fontScale,
fontWeight: instance._adjustWeight(FontWeight.bold),
fontFamily: instance.fontFamily,
);
/// 页面主标题 28sp Bold
TextStyle get title1 => TextStyle(
fontSize: fontTitle1 * fontScale,
fontWeight: _adjustWeight(FontWeight.bold),
fontFamily: fontFamily,
);
static TextStyle get title1 => TextStyle(
fontSize: fontTitle1 * instance.fontScale,
fontWeight: instance._adjustWeight(FontWeight.bold),
fontFamily: instance.fontFamily,
);
/// 区块标题 22sp Bold
TextStyle get title2 => TextStyle(
fontSize: fontTitle2 * fontScale,
fontWeight: _adjustWeight(FontWeight.bold),
fontFamily: fontFamily,
);
static TextStyle get title2 => TextStyle(
fontSize: fontTitle2 * instance.fontScale,
fontWeight: instance._adjustWeight(FontWeight.bold),
fontFamily: instance.fontFamily,
);
/// 导航栏标题 20sp Semibold
TextStyle get title3 => TextStyle(
fontSize: fontTitle3 * fontScale,
fontWeight: _adjustWeight(FontWeight.w600),
fontFamily: fontFamily,
);
static TextStyle get title3 => TextStyle(
fontSize: fontTitle3 * instance.fontScale,
fontWeight: instance._adjustWeight(FontWeight.w600),
fontFamily: instance.fontFamily,
);
/// 列表标题 18sp Semibold
TextStyle get headline => TextStyle(
fontSize: fontHeadline * fontScale,
fontWeight: _adjustWeight(FontWeight.w600),
fontFamily: fontFamily,
);
static TextStyle get headline => TextStyle(
fontSize: fontHeadline * instance.fontScale,
fontWeight: instance._adjustWeight(FontWeight.w600),
fontFamily: instance.fontFamily,
);
/// 正文 16sp Regular
TextStyle get body => TextStyle(
fontSize: fontBody * fontScale,
fontWeight: fontWeight,
fontFamily: fontFamily,
);
static TextStyle get body => TextStyle(
fontSize: fontBody * instance.fontScale,
fontWeight: instance.fontWeight,
fontFamily: instance.fontFamily,
);
/// 强调文字 16sp Medium
TextStyle get callout => TextStyle(
fontSize: fontCallout * fontScale,
fontWeight: _adjustWeight(FontWeight.w500),
fontFamily: fontFamily,
);
static TextStyle get callout => TextStyle(
fontSize: fontCallout * instance.fontScale,
fontWeight: instance._adjustWeight(FontWeight.w500),
fontFamily: instance.fontFamily,
);
/// 辅助说明 14sp Regular
TextStyle get subhead => TextStyle(
fontSize: fontSubhead * fontScale,
fontWeight: fontWeight,
fontFamily: fontFamily,
);
static TextStyle get subhead => TextStyle(
fontSize: fontSubhead * instance.fontScale,
fontWeight: instance.fontWeight,
fontFamily: instance.fontFamily,
);
/// 脚注 13sp Regular
TextStyle get footnote => TextStyle(
fontSize: fontFootnote * fontScale,
fontWeight: fontWeight,
fontFamily: fontFamily,
);
static TextStyle get footnote => TextStyle(
fontSize: fontFootnote * instance.fontScale,
fontWeight: instance.fontWeight,
fontFamily: instance.fontFamily,
);
/// 标签 12sp Regular
TextStyle get caption1 => TextStyle(
fontSize: fontCaption1 * fontScale,
fontWeight: fontWeight,
fontFamily: fontFamily,
);
static TextStyle get caption1 => TextStyle(
fontSize: fontCaption1 * instance.fontScale,
fontWeight: instance.fontWeight,
fontFamily: instance.fontFamily,
);
/// 极小文字 11sp Regular
TextStyle get caption2 => TextStyle(
fontSize: fontCaption2 * fontScale,
fontWeight: fontWeight,
fontFamily: fontFamily,
);
static TextStyle get caption2 => TextStyle(
fontSize: fontCaption2 * instance.fontScale,
fontWeight: instance.fontWeight,
fontFamily: instance.fontFamily,
);
// ---- ThemeExtension 实现 ----
@@ -183,8 +156,7 @@ class AppTypography extends ThemeExtension<AppTypography> {
// ---- 便捷访问 ----
/// 从 BuildContext 获取当前主题的 AppTypography 实例
static AppTypography of(BuildContext context) {
return Theme.of(context).extension<AppTypography>() ?? const AppTypography();
return Theme.of(context).extension<AppTypography>() ?? instance;
}
}