69b34bd723
- 后端 ProfileSettingsV1 添加 DivinationTutorialSettings 字段 - 前端三个起卦页面添加首次访问检测,自动弹出教程 - 教程展示后更新 settings 标记,避免重复弹出 - 使用本地状态管理避免并发更新覆盖问题 - Agent 系统提示添加时间上下文信息
165 lines
4.4 KiB
Dart
165 lines
4.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../../../l10n/app_localizations.dart';
|
|
|
|
String displayLanguageLabel(AppLocalizations l10n, String languageTag) {
|
|
return switch (languageTag) {
|
|
'en-US' => l10n.english,
|
|
'zh-Hant' => '繁體中文',
|
|
'zh-CN' => '简体中文',
|
|
_ => '简体中文',
|
|
};
|
|
}
|
|
|
|
class PreferenceSettings {
|
|
const PreferenceSettings({
|
|
this.interfaceLanguage = 'zh-CN',
|
|
this.aiLanguage = 'zh-CN',
|
|
this.timezone = 'Asia/Shanghai',
|
|
this.country = 'CN',
|
|
});
|
|
|
|
final String interfaceLanguage;
|
|
final String aiLanguage;
|
|
final String timezone;
|
|
final String country;
|
|
|
|
PreferenceSettings copyWith({
|
|
String? interfaceLanguage,
|
|
String? aiLanguage,
|
|
String? timezone,
|
|
String? country,
|
|
}) {
|
|
return PreferenceSettings(
|
|
interfaceLanguage: interfaceLanguage ?? this.interfaceLanguage,
|
|
aiLanguage: aiLanguage ?? this.aiLanguage,
|
|
timezone: timezone ?? this.timezone,
|
|
country: country ?? this.country,
|
|
);
|
|
}
|
|
}
|
|
|
|
class NotificationSettings {
|
|
const NotificationSettings({
|
|
this.allowNotifications = true,
|
|
this.allowVibration = true,
|
|
});
|
|
|
|
final bool allowNotifications;
|
|
final bool allowVibration;
|
|
|
|
NotificationSettings copyWith({
|
|
bool? allowNotifications,
|
|
bool? allowVibration,
|
|
}) {
|
|
return NotificationSettings(
|
|
allowNotifications: allowNotifications ?? this.allowNotifications,
|
|
allowVibration: allowVibration ?? this.allowVibration,
|
|
);
|
|
}
|
|
}
|
|
|
|
class DivinationTutorialSettings {
|
|
const DivinationTutorialSettings({
|
|
this.divinationEntryShown = true,
|
|
this.autoDivinationShown = true,
|
|
this.manualDivinationShown = true,
|
|
});
|
|
|
|
final bool divinationEntryShown;
|
|
final bool autoDivinationShown;
|
|
final bool manualDivinationShown;
|
|
|
|
DivinationTutorialSettings copyWith({
|
|
bool? divinationEntryShown,
|
|
bool? autoDivinationShown,
|
|
bool? manualDivinationShown,
|
|
}) {
|
|
return DivinationTutorialSettings(
|
|
divinationEntryShown: divinationEntryShown ?? this.divinationEntryShown,
|
|
autoDivinationShown: autoDivinationShown ?? this.autoDivinationShown,
|
|
manualDivinationShown:
|
|
manualDivinationShown ?? this.manualDivinationShown,
|
|
);
|
|
}
|
|
}
|
|
|
|
class ProfileSettingsV1 {
|
|
const ProfileSettingsV1({
|
|
this.version = 1,
|
|
this.displayName = '',
|
|
this.bio = '',
|
|
this.avatarPath,
|
|
this.avatarUrl,
|
|
this.preferences = const PreferenceSettings(),
|
|
this.privacy = const <String, Object?>{},
|
|
this.notification = const NotificationSettings(),
|
|
this.divinationTutorial = const DivinationTutorialSettings(),
|
|
});
|
|
|
|
final int version;
|
|
final String displayName;
|
|
final String bio;
|
|
final String? avatarPath;
|
|
final String? avatarUrl;
|
|
final PreferenceSettings preferences;
|
|
final Map<String, Object?> privacy;
|
|
final NotificationSettings notification;
|
|
final DivinationTutorialSettings divinationTutorial;
|
|
|
|
ProfileSettingsV1 copyWith({
|
|
int? version,
|
|
String? displayName,
|
|
String? bio,
|
|
String? avatarPath,
|
|
String? avatarUrl,
|
|
PreferenceSettings? preferences,
|
|
Map<String, Object?>? privacy,
|
|
NotificationSettings? notification,
|
|
DivinationTutorialSettings? divinationTutorial,
|
|
}) {
|
|
return ProfileSettingsV1(
|
|
version: version ?? this.version,
|
|
displayName: displayName ?? this.displayName,
|
|
bio: bio ?? this.bio,
|
|
avatarPath: avatarPath ?? this.avatarPath,
|
|
avatarUrl: avatarUrl ?? this.avatarUrl,
|
|
preferences: preferences ?? this.preferences,
|
|
privacy: privacy ?? this.privacy,
|
|
notification: notification ?? this.notification,
|
|
divinationTutorial: divinationTutorial ?? this.divinationTutorial,
|
|
);
|
|
}
|
|
|
|
factory ProfileSettingsV1.defaultsForLocale(Locale locale) {
|
|
final tag = languageTagFromLocale(locale);
|
|
return ProfileSettingsV1(
|
|
preferences: PreferenceSettings(interfaceLanguage: tag, aiLanguage: tag),
|
|
);
|
|
}
|
|
}
|
|
|
|
String languageTagFromLocale(Locale locale) {
|
|
switch (locale.languageCode) {
|
|
case 'en':
|
|
return 'en-US';
|
|
case 'zh':
|
|
if (locale.scriptCode == 'Hant') {
|
|
return 'zh-Hant';
|
|
}
|
|
return 'zh-CN';
|
|
default:
|
|
return 'zh-CN';
|
|
}
|
|
}
|
|
|
|
Locale localeFromLanguageTag(String tag) {
|
|
if (tag.toLowerCase().startsWith('en')) {
|
|
return const Locale('en');
|
|
}
|
|
if (tag == 'zh-Hant') {
|
|
return const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant');
|
|
}
|
|
return const Locale('zh');
|
|
}
|