本次提交包含多项迭代优化和问题修复: 1. 新增缩略图图片组件、数字格式化工具类,补充多语言翻译类型与本地化支持 2. 优化底部导航栏主题色统一使用动态accent色值 3. 修复多处图表动画、路由跳转、API请求相关问题 4. 简化服务器公告文案,调整默认分屏状态为关闭 5. 新增安卓/iOS桌面快捷方式配置 6. 重构多处状态管理类使用SafeNotifierInit统一异常保护 7. 替换硬编码蓝色为主题色,更新版本号获取方式为动态读取 8. 优化缓存预加载逻辑,移除无用代码 9. 调整默认设置项,优化用户体验细节
260 lines
8.8 KiB
Dart
260 lines
8.8 KiB
Dart
// ============================================================
|
||
// 闲言APP — 快速卡片创作状态管理
|
||
// 创建时间: 2026-04-26
|
||
// 更新时间: 2026-05-31
|
||
// 作用: QuickCardSheet 专用状态 — 扩展自 MiniEditor
|
||
// 上次更新: 增加showWeather/locationText/usernameText/weatherText字段,完善空壳功能
|
||
// ============================================================
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
||
import 'package:xianyan/core/theme/app_colors.dart';
|
||
import 'package:xianyan/editor/models/editor_models.dart';
|
||
|
||
enum BarStyle { none, top, bottom, both }
|
||
|
||
enum CardPresetStyle {
|
||
none,
|
||
frostedGlass,
|
||
liquidGlass,
|
||
gradient,
|
||
meteor,
|
||
pureWhite,
|
||
}
|
||
|
||
enum ExportFormat { png, jpg }
|
||
|
||
class QuickCardState {
|
||
const QuickCardState({
|
||
required this.text,
|
||
this.fontSize = 28.0,
|
||
this.textColor = Colors.white,
|
||
this.fontFamily = 'Inter',
|
||
this.colorDepth = 0.5,
|
||
this.cardRatio = CanvasAspectRatio.ratio4_3,
|
||
this.barStyle = BarStyle.both,
|
||
this.background = const BackgroundLayer(
|
||
type: BackgroundType.gradient,
|
||
gradientColors: [LightColors.primary, LightColors.primaryDark],
|
||
gradientBegin: Alignment.topLeft,
|
||
gradientEnd: Alignment.bottomRight,
|
||
),
|
||
this.pinyinEnabled = true,
|
||
this.hapticEnabled = false,
|
||
this.autoPlayEnabled = false,
|
||
this.alwaysOnEnabled = false,
|
||
this.soundEnabled = false,
|
||
this.ttsEnabled = false,
|
||
this.appNameEnabled = true,
|
||
this.exportFormat = ExportFormat.png,
|
||
this.qrCodeEnabled = false,
|
||
this.presetStyle = CardPresetStyle.none,
|
||
this.textOffset = Offset.zero,
|
||
this.showTime = false,
|
||
this.showLocation = false,
|
||
this.showUsername = false,
|
||
this.showWeather = false,
|
||
this.locationText = '未知',
|
||
this.usernameText = '匿名',
|
||
this.weatherText = '',
|
||
this.autoPlayProgress = 1.0,
|
||
});
|
||
|
||
final String text;
|
||
final double fontSize;
|
||
final Color textColor;
|
||
final String fontFamily;
|
||
final double colorDepth;
|
||
final CanvasAspectRatio cardRatio;
|
||
final BarStyle barStyle;
|
||
final BackgroundLayer background;
|
||
final bool pinyinEnabled;
|
||
final bool hapticEnabled;
|
||
final bool autoPlayEnabled;
|
||
final bool alwaysOnEnabled;
|
||
final bool soundEnabled;
|
||
final bool ttsEnabled;
|
||
final bool appNameEnabled;
|
||
final ExportFormat exportFormat;
|
||
final bool qrCodeEnabled;
|
||
final CardPresetStyle presetStyle;
|
||
final Offset textOffset;
|
||
final bool showTime;
|
||
final bool showLocation;
|
||
final bool showUsername;
|
||
final bool showWeather;
|
||
final String locationText;
|
||
final String usernameText;
|
||
final String weatherText;
|
||
final double autoPlayProgress;
|
||
|
||
bool get hasBottomInfo =>
|
||
showTime || showLocation || showUsername || showWeather;
|
||
|
||
QuickCardState copyWith({
|
||
String? text,
|
||
double? fontSize,
|
||
Color? textColor,
|
||
String? fontFamily,
|
||
double? colorDepth,
|
||
CanvasAspectRatio? cardRatio,
|
||
BarStyle? barStyle,
|
||
BackgroundLayer? background,
|
||
bool? pinyinEnabled,
|
||
bool? hapticEnabled,
|
||
bool? autoPlayEnabled,
|
||
bool? alwaysOnEnabled,
|
||
bool? soundEnabled,
|
||
bool? ttsEnabled,
|
||
bool? appNameEnabled,
|
||
ExportFormat? exportFormat,
|
||
bool? qrCodeEnabled,
|
||
CardPresetStyle? presetStyle,
|
||
Offset? textOffset,
|
||
bool? showTime,
|
||
bool? showLocation,
|
||
bool? showUsername,
|
||
bool? showWeather,
|
||
String? locationText,
|
||
String? usernameText,
|
||
String? weatherText,
|
||
double? autoPlayProgress,
|
||
}) {
|
||
return QuickCardState(
|
||
text: text ?? this.text,
|
||
fontSize: fontSize ?? this.fontSize,
|
||
textColor: textColor ?? this.textColor,
|
||
fontFamily: fontFamily ?? this.fontFamily,
|
||
colorDepth: colorDepth ?? this.colorDepth,
|
||
cardRatio: cardRatio ?? this.cardRatio,
|
||
barStyle: barStyle ?? this.barStyle,
|
||
background: background ?? this.background,
|
||
pinyinEnabled: pinyinEnabled ?? this.pinyinEnabled,
|
||
hapticEnabled: hapticEnabled ?? this.hapticEnabled,
|
||
autoPlayEnabled: autoPlayEnabled ?? this.autoPlayEnabled,
|
||
alwaysOnEnabled: alwaysOnEnabled ?? this.alwaysOnEnabled,
|
||
soundEnabled: soundEnabled ?? this.soundEnabled,
|
||
ttsEnabled: ttsEnabled ?? this.ttsEnabled,
|
||
appNameEnabled: appNameEnabled ?? this.appNameEnabled,
|
||
exportFormat: exportFormat ?? this.exportFormat,
|
||
qrCodeEnabled: qrCodeEnabled ?? this.qrCodeEnabled,
|
||
presetStyle: presetStyle ?? this.presetStyle,
|
||
textOffset: textOffset ?? this.textOffset,
|
||
showTime: showTime ?? this.showTime,
|
||
showLocation: showLocation ?? this.showLocation,
|
||
showUsername: showUsername ?? this.showUsername,
|
||
showWeather: showWeather ?? this.showWeather,
|
||
locationText: locationText ?? this.locationText,
|
||
usernameText: usernameText ?? this.usernameText,
|
||
weatherText: weatherText ?? this.weatherText,
|
||
autoPlayProgress: autoPlayProgress ?? this.autoPlayProgress,
|
||
);
|
||
}
|
||
}
|
||
|
||
// ─── StateNotifier ───
|
||
|
||
class QuickCardNotifier extends Notifier<QuickCardState> {
|
||
@override
|
||
QuickCardState build() => const QuickCardState(text: '在此输入文字');
|
||
|
||
void updateText(String text) => state = state.copyWith(text: text);
|
||
void updateFontSize(double size) => state = state.copyWith(fontSize: size);
|
||
void updateTextColor(Color color) => state = state.copyWith(textColor: color);
|
||
void updateFontFamily(String family) =>
|
||
state = state.copyWith(fontFamily: family);
|
||
void updateColorDepth(double depth) =>
|
||
state = state.copyWith(colorDepth: depth);
|
||
void updateCardRatio(CanvasAspectRatio ratio) =>
|
||
state = state.copyWith(cardRatio: ratio);
|
||
void updateBarStyle(BarStyle style) =>
|
||
state = state.copyWith(barStyle: style);
|
||
void updateBackground(BackgroundLayer bg) =>
|
||
state = state.copyWith(background: bg);
|
||
void updateTextOffset(Offset offset) =>
|
||
state = state.copyWith(textOffset: offset);
|
||
|
||
void togglePinyin(bool v) => state = state.copyWith(pinyinEnabled: v);
|
||
void toggleHaptic(bool v) => state = state.copyWith(hapticEnabled: v);
|
||
void toggleAutoPlay(bool v) => state = state.copyWith(autoPlayEnabled: v);
|
||
void toggleAlwaysOn(bool v) => state = state.copyWith(alwaysOnEnabled: v);
|
||
void toggleSound(bool v) => state = state.copyWith(soundEnabled: v);
|
||
void toggleTts(bool v) => state = state.copyWith(ttsEnabled: v);
|
||
void toggleAppName(bool v) => state = state.copyWith(appNameEnabled: v);
|
||
void toggleQrCode(bool v) => state = state.copyWith(qrCodeEnabled: v);
|
||
void toggleShowTime(bool v) => state = state.copyWith(showTime: v);
|
||
void toggleShowLocation(bool v) => state = state.copyWith(showLocation: v);
|
||
void toggleShowUsername(bool v) => state = state.copyWith(showUsername: v);
|
||
void setExportFormat(ExportFormat f) =>
|
||
state = state.copyWith(exportFormat: f);
|
||
|
||
void applyPreset(CardPresetStyle preset) {
|
||
switch (preset) {
|
||
case CardPresetStyle.frostedGlass:
|
||
state = state.copyWith(
|
||
presetStyle: preset,
|
||
background: const BackgroundLayer(solidColor: Color(0xFF2C2C2E)),
|
||
textColor: Colors.white,
|
||
colorDepth: 0.3,
|
||
barStyle: BarStyle.both,
|
||
);
|
||
case CardPresetStyle.liquidGlass:
|
||
state = state.copyWith(
|
||
presetStyle: preset,
|
||
background: const BackgroundLayer(
|
||
type: BackgroundType.gradient,
|
||
gradientBegin: Alignment.topLeft,
|
||
gradientEnd: Alignment.bottomRight,
|
||
),
|
||
textColor: Colors.white,
|
||
colorDepth: 0.5,
|
||
barStyle: BarStyle.both,
|
||
);
|
||
case CardPresetStyle.gradient:
|
||
state = state.copyWith(
|
||
presetStyle: preset,
|
||
background: const BackgroundLayer(
|
||
type: BackgroundType.gradient,
|
||
gradientBegin: Alignment.topLeft,
|
||
gradientEnd: Alignment.bottomRight,
|
||
),
|
||
textColor: Colors.white,
|
||
colorDepth: 0.7,
|
||
barStyle: BarStyle.bottom,
|
||
);
|
||
case CardPresetStyle.meteor:
|
||
state = state.copyWith(
|
||
presetStyle: preset,
|
||
background: const BackgroundLayer(
|
||
type: BackgroundType.gradient,
|
||
gradientColors: [
|
||
Color(0xFF0f0c29),
|
||
Color(0xFF302b63),
|
||
Color(0xFF24243e),
|
||
],
|
||
),
|
||
textColor: const Color(0xFFE0E0FF),
|
||
colorDepth: 0.8,
|
||
barStyle: BarStyle.none,
|
||
);
|
||
case CardPresetStyle.pureWhite:
|
||
state = state.copyWith(
|
||
presetStyle: preset,
|
||
background: const BackgroundLayer(solidColor: Color(0xFFF8F8FA)),
|
||
textColor: const Color(0xFF1A1A2E),
|
||
colorDepth: 0.0,
|
||
barStyle: BarStyle.bottom,
|
||
);
|
||
case CardPresetStyle.none:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ─── Provider ───
|
||
|
||
final quickCardProvider = NotifierProvider<QuickCardNotifier, QuickCardState>(
|
||
QuickCardNotifier.new,
|
||
);
|