b9617ae152
- 后端 Schema 将 interface_language 和 ai_language 合并为 language - 前端设置界面只保留一个语言选项 - AI 回复语言统一使用 language 设置 - 更新协议文档 - 新增数据库迁移脚本
174 lines
4.4 KiB
Dart
174 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.language = 'zh-CN',
|
|
this.timezone = 'Asia/Shanghai',
|
|
});
|
|
|
|
final String language;
|
|
final String timezone;
|
|
|
|
PreferenceSettings copyWith({
|
|
String? language,
|
|
String? timezone,
|
|
}) {
|
|
return PreferenceSettings(
|
|
language: language ?? this.language,
|
|
timezone: timezone ?? this.timezone,
|
|
);
|
|
}
|
|
}
|
|
|
|
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 PrivacySettings {
|
|
const PrivacySettings({
|
|
this.canSell = false,
|
|
this.profileVisibility = 'public',
|
|
});
|
|
|
|
final bool canSell;
|
|
final String profileVisibility;
|
|
|
|
PrivacySettings copyWith({bool? canSell, String? profileVisibility}) {
|
|
return PrivacySettings(
|
|
canSell: canSell ?? this.canSell,
|
|
profileVisibility: profileVisibility ?? this.profileVisibility,
|
|
);
|
|
}
|
|
}
|
|
|
|
class ProfileSettingsV1 {
|
|
const ProfileSettingsV1({
|
|
this.version = 1,
|
|
this.displayName = '',
|
|
this.bio = '',
|
|
this.avatarPath,
|
|
this.avatarUrl,
|
|
this.preferences = const PreferenceSettings(),
|
|
this.privacy = const PrivacySettings(),
|
|
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 PrivacySettings privacy;
|
|
final NotificationSettings notification;
|
|
final DivinationTutorialSettings divinationTutorial;
|
|
|
|
ProfileSettingsV1 copyWith({
|
|
int? version,
|
|
String? displayName,
|
|
String? bio,
|
|
String? avatarPath,
|
|
String? avatarUrl,
|
|
PreferenceSettings? preferences,
|
|
PrivacySettings? 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(language: 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');
|
|
}
|