Able to set account preffered language

This commit is contained in:
LittleSheep 2025-05-17 21:41:13 +08:00
parent 641fcb4419
commit 7ccaf737a9
10 changed files with 330 additions and 243 deletions

View File

@ -151,8 +151,10 @@
"statusActivityTitle": "{} is {} {}", "statusActivityTitle": "{} is {} {}",
"statusActivityEndedTitle": "{} is {} {} until {}", "statusActivityEndedTitle": "{} is {} {} until {}",
"appSettings": "App Settings", "appSettings": "App Settings",
"accountSettings": "Account Settings",
"settings": "Settings", "settings": "Settings",
"language": "Language", "language": "Language",
"accountLanguageHint": "This language will be used for email and push notifications.",
"settingsDisplayLanguage": "Display Language", "settingsDisplayLanguage": "Display Language",
"languageFollowSystem": "Follow System", "languageFollowSystem": "Follow System",
"postsCreatedCount": "Posts", "postsCreatedCount": "Posts",

View File

@ -25,6 +25,7 @@ class AppRouter extends RootStackRouter {
AutoRoute(page: LoginRoute.page, path: '/auth/login'), AutoRoute(page: LoginRoute.page, path: '/auth/login'),
AutoRoute(page: CreateAccountRoute.page, path: '/auth/create-account'), AutoRoute(page: CreateAccountRoute.page, path: '/auth/create-account'),
AutoRoute(page: MyselfProfileRoute.page, path: '/account/me'), AutoRoute(page: MyselfProfileRoute.page, path: '/account/me'),
AutoRoute(page: AccountSettingsRoute.page, path: '/account/settings'),
AutoRoute( AutoRoute(
page: MyselfEventCalendarRoute.page, page: MyselfEventCalendarRoute.page,
path: '/account/me/calendar', path: '/account/me/calendar',

File diff suppressed because it is too large Load Diff

View File

@ -111,7 +111,13 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
fontSize: 9, fontSize: 9,
color: color:
isSameDay(selectedDay.value, day) isSameDay(selectedDay.value, day)
? Theme.of(context).colorScheme.onPrimary ? Theme.of(
context,
).colorScheme.onPrimaryContainer
: isSameDay(DateTime.now(), day)
? Theme.of(
context,
).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.onSurface, : Theme.of(context).colorScheme.onSurface,
), ),
), ),

View File

@ -0,0 +1,18 @@
import 'package:auto_route/annotations.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/widgets/app_scaffold.dart';
@RoutePage()
class AccountSettingsScreen extends HookConsumerWidget {
const AccountSettingsScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return AppScaffold(
appBar: AppBar(title: Text('accountSettings').tr()),
body: SingleChildScrollView(child: Column(children: [])),
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:croppy/croppy.dart' hide cropImage; import 'package:croppy/croppy.dart' hide cropImage;
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
@ -15,6 +16,8 @@ import 'package:island/widgets/content/cloud_files.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
const kServerSupportedLanguages = {'en-US': 'en-us', 'zh-CN': 'zh-hans'};
@RoutePage() @RoutePage()
class UpdateProfileScreen extends HookConsumerWidget { class UpdateProfileScreen extends HookConsumerWidget {
const UpdateProfileScreen({super.key}); const UpdateProfileScreen({super.key});
@ -94,6 +97,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
final formKeyBasicInfo = useMemoized(GlobalKey<FormState>.new, const []); final formKeyBasicInfo = useMemoized(GlobalKey<FormState>.new, const []);
final usernameController = useTextEditingController(text: user.value!.name); final usernameController = useTextEditingController(text: user.value!.name);
final nicknameController = useTextEditingController(text: user.value!.nick); final nicknameController = useTextEditingController(text: user.value!.nick);
final language = useState(user.value!.language);
void updateBasicInfo() async { void updateBasicInfo() async {
if (!formKeyBasicInfo.currentState!.validate()) return; if (!formKeyBasicInfo.currentState!.validate()) return;
@ -106,6 +110,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
data: { data: {
'name': usernameController.text, 'name': usernameController.text,
'nick': nicknameController.text, 'nick': nicknameController.text,
'language': language.value,
}, },
); );
final userNotifier = ref.read(userInfoProvider.notifier); final userNotifier = ref.read(userInfoProvider.notifier);
@ -161,9 +166,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
child: Container( child: Container(
color: Theme.of(context).colorScheme.surfaceContainerHigh, color: Theme.of(context).colorScheme.surfaceContainerHigh,
child: child:
user.value!.profile.background != null user.value!.profile.backgroundId != null
? CloudFileWidget( ? CloudImageWidget(
item: user.value!.profile.background!, fileId: user.value!.profile.backgroundId!,
fit: BoxFit.cover, fit: BoxFit.cover,
) )
: const SizedBox.shrink(), : const SizedBox.shrink(),
@ -196,7 +201,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
Form( Form(
key: formKeyBasicInfo, key: formKeyBasicInfo,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 16, spacing: 16,
children: [ children: [
TextFormField( TextFormField(
@ -216,6 +221,34 @@ class UpdateProfileScreen extends HookConsumerWidget {
onTapOutside: onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(), (_) => FocusManager.instance.primaryFocus?.unfocus(),
), ),
DropdownButtonFormField2<String>(
decoration: InputDecoration(
labelText: 'language'.tr(),
helperText: 'accountLanguageHint'.tr(),
),
items: [
...kServerSupportedLanguages.values.map(
(e) => DropdownMenuItem(value: e, child: Text(e)),
),
if (!kServerSupportedLanguages.containsValue(
language.value,
))
DropdownMenuItem(
value: language.value,
child: Text(language.value),
),
],
value: language.value,
onChanged: (value) {
language.value = value ?? language.value;
},
customButton: Row(
children: [
Expanded(child: Text(language.value)),
Icon(Symbols.arrow_drop_down),
],
),
),
Align( Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: TextButton.icon( child: TextButton.icon(

View File

@ -7,6 +7,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/route.gr.dart'; import 'package:island/route.gr.dart';
import 'package:island/screens/account/me/update.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
@ -56,7 +57,11 @@ class CreateAccountScreen extends HookConsumerWidget {
'nick': nicknameController.text, 'nick': nicknameController.text,
'email': emailController.text, 'email': emailController.text,
'password': passwordController.text, 'password': passwordController.text,
'language': EasyLocalization.of(context)!.currentLocale.toString(), 'language':
kServerSupportedLanguages[EasyLocalization.of(
context,
)!.currentLocale.toString()] ??
'en-us',
'captcha_token': captchaTk, 'captcha_token': captchaTk,
}, },
); );

View File

@ -36,7 +36,7 @@ class CreatorHubScreen extends HookConsumerWidget {
publishers.value?.firstOrNull, publishers.value?.firstOrNull,
); );
final publishersMenu = publishers.when( final List<DropdownMenuItem<SnPublisher>> publishersMenu = publishers.when(
data: data:
(data) => (data) =>
data data
@ -92,10 +92,12 @@ class CreatorHubScreen extends HookConsumerWidget {
}, },
selectedItemBuilder: (context) { selectedItemBuilder: (context) {
return [ return [
ProfilePictureWidget( ...publishersMenu.map(
radius: 16, (e) => ProfilePictureWidget(
fileId: currentPublisher.value?.pictureId, radius: 16,
).center().padding(right: 8), fileId: e.value?.pictureId,
).center().padding(right: 8),
),
]; ];
}, },
buttonStyleData: ButtonStyleData( buttonStyleData: ButtonStyleData(

View File

@ -8,6 +8,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/activity.dart'; import 'package:island/models/activity.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart';
import 'package:island/route.gr.dart'; import 'package:island/route.gr.dart';
import 'package:island/screens/auth/captcha.dart'; import 'package:island/screens/auth/captcha.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
@ -58,6 +59,8 @@ class CheckInWidget extends HookConsumerWidget {
data: jsonEncode(captchaTk), data: jsonEncode(captchaTk),
); );
ref.invalidate(checkInResultTodayProvider); ref.invalidate(checkInResultTodayProvider);
final userNotifier = ref.read(userInfoProvider.notifier);
userNotifier.fetchUser();
return; return;
} }
} }

View File

@ -38,7 +38,7 @@ class PostItem extends HookConsumerWidget {
final user = ref.watch(userInfoProvider); final user = ref.watch(userInfoProvider);
final isAuthor = useMemoized( final isAuthor = useMemoized(
() => user.hasValue && user.value!.id == item.publisher.accountId, () => user.hasValue && user.value?.id == item.publisher.accountId,
[user], [user],
); );