913ed26f8d
- Add PrivacySettings schema with can_sell field (default: false) - Move privacy toggle to GeneralSettingsScreen with clear labeling - Update l10n for zh/en/zh_hant with user-friendly copy - Clean up redundant PrivacyNotificationSettingsScreen - Update profile-protocol.md to reflect new privacy schema - Fix basedpyright warnings in user.py
182 lines
4.7 KiB
Dart
182 lines
4.7 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 = 'US',
|
|
});
|
|
|
|
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 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(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');
|
|
}
|