diff --git a/frontend/appflowy_flutter/integration_test/settings/user_icon_test.dart b/frontend/appflowy_flutter/integration_test/settings/user_icon_test.dart new file mode 100644 index 0000000000..492e97f28a --- /dev/null +++ b/frontend/appflowy_flutter/integration_test/settings/user_icon_test.dart @@ -0,0 +1,54 @@ +import 'package:appflowy/workspace/application/settings/prelude.dart'; +import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart'; +import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import '../util/util.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('Settings: user icon tests', () { + testWidgets('select icon, select default option', (tester) async { + await tester.initializeAppFlowy(); + + await tester.tapGoButton(); + tester.expectToSeeHomePage(); + await tester.openSettings(); + + await tester.openSettingsPage(SettingsPage.user); + + final userAvatarFinder = find.descendant( + of: find.byType(SettingsUserView), + matching: find.byType(UserAvatar), + ); + + // Open icon picker dialog + await tester.tap(userAvatarFinder); + await tester.pumpAndSettle(); + + // Select first option that isn't default + await tester.tap(find.byType(IconOption).first); + await tester.pumpAndSettle(); + + UserAvatar userAvatar = tester.widget(userAvatarFinder) as UserAvatar; + expect(userAvatar.iconUrl, isNotEmpty); + + // Open icon picker dialog again + await tester.tap(userAvatarFinder); + await tester.pumpAndSettle(); + + // Tap the default option + await tester.tap( + find.descendant( + of: find.byType(IconGallery), + matching: find.byType(UserAvatar), + ), + ); + await tester.pumpAndSettle(); + + userAvatar = tester.widget(userAvatarFinder) as UserAvatar; + expect(userAvatar.iconUrl, isEmpty); + }); + }); +} diff --git a/frontend/appflowy_flutter/lib/workspace/application/user/settings_user_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/user/settings_user_bloc.dart index 853148899c..806b244244 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/user/settings_user_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/user/settings_user_bloc.dart @@ -43,6 +43,15 @@ class SettingsUserViewBloc extends Bloc<SettingsUserEvent, SettingsUserState> { ); }); }, + removeUserIcon: () { + // Empty Icon URL = No icon + _userService.updateUserProfile(iconUrl: "").then((result) { + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }); + }, updateUserOpenAIKey: (openAIKey) { _userService.updateUserProfile(openAIKey: openAIKey).then((result) { result.fold( @@ -105,8 +114,9 @@ class SettingsUserEvent with _$SettingsUserEvent { const factory SettingsUserEvent.initial() = _Initial; const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName; const factory SettingsUserEvent.updateUserEmail(String email) = _UpdateEmail; - const factory SettingsUserEvent.updateUserIcon(String iconUrl) = + const factory SettingsUserEvent.updateUserIcon({required String iconUrl}) = _UpdateUserIcon; + const factory SettingsUserEvent.removeUserIcon() = _RemoveUserIcon; const factory SettingsUserEvent.updateUserOpenAIKey(String openAIKey) = _UpdateUserOpenaiKey; const factory SettingsUserEvent.didReceiveUserProfile( diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart index f9c38ecbd2..b708845890 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart @@ -1,11 +1,9 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart'; import 'package:appflowy/startup/startup.dart'; -import 'package:appflowy/util/color_generator/color_generator.dart'; import 'package:appflowy/workspace/application/menu/menu_user_bloc.dart'; import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart'; -import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart'; -import 'package:flowy_infra/size.dart'; +import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart' @@ -34,7 +32,10 @@ class SidebarUser extends StatelessWidget { builder: (context, state) => Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - _buildAvatar(context, state), + UserAvatar( + iconUrl: state.userProfile.iconUrl, + name: state.userProfile.name, + ), const HSpace(10), Expanded( child: _buildUserName(context, state), @@ -46,50 +47,6 @@ class SidebarUser extends StatelessWidget { ); } - Widget _buildAvatar(BuildContext context, MenuUserState state) { - String iconUrl = state.userProfile.iconUrl; - if (iconUrl.isEmpty) { - iconUrl = defaultUserAvatar; - final String name = _userName(state.userProfile); - final Color color = ColorGenerator().generateColorFromString(name); - const initialsCount = 2; - // Taking the first letters of the name components and limiting to 2 elements - final nameInitials = name - .split(' ') - .where((element) => element.isNotEmpty) - .take(initialsCount) - .map((element) => element[0].toUpperCase()) - .join(''); - return Container( - width: 28, - height: 28, - alignment: Alignment.center, - decoration: BoxDecoration( - color: color, - shape: BoxShape.circle, - ), - child: FlowyText.semibold( - nameInitials, - color: Colors.white, - fontSize: nameInitials.length == initialsCount ? 12 : 14, - ), - ); - } - return SizedBox.square( - dimension: 25, - child: ClipRRect( - borderRadius: Corners.s5Border, - child: CircleAvatar( - backgroundColor: Colors.transparent, - child: FlowySvg( - FlowySvgData('emoji/$iconUrl'), - blendMode: null, - ), - ), - ), - ); - } - Widget _buildUserName(BuildContext context, MenuUserState state) { final String name = _userName(state.userProfile); return FlowyText.medium( diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart index 1692b5aeac..8bd91b6b21 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -9,10 +9,14 @@ import 'package:appflowy/user/application/auth/auth_service.dart'; import 'package:appflowy/util/debounce.dart'; import 'package:appflowy/workspace/application/user/settings_user_bloc.dart'; import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; +import 'package:appflowy/workspace/presentation/widgets/flowy_tooltip.dart'; +import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; +import 'package:collection/collection.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/size.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -49,21 +53,16 @@ class SettingsUserView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - _renderUserNameInput(context), - + _buildUserIconSetting(context), if (isSupabaseEnabled) ...[ - const VSpace(20), + const VSpace(12), UserEmailInput(user.email) ], - - const VSpace(20), - _renderCurrentIcon(context), - const VSpace(20), + const VSpace(12), _renderCurrentOpenaiKey(context), - const VSpace(20), - // _renderHistoricalUser(context), + const VSpace(12), _renderLoginOrLogoutButton(context, state), - const VSpace(20), + const VSpace(12), ], ), ), @@ -71,6 +70,115 @@ class SettingsUserView extends StatelessWidget { ); } + Row _buildUserIconSetting(BuildContext context) { + return Row( + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _showIconPickerDialog(context), + child: FlowyHover( + style: const HoverStyle.transparent(), + builder: (context, onHover) { + Widget avatar = UserAvatar( + iconUrl: user.iconUrl, + name: user.name, + isLarge: true, + ); + + if (onHover) { + avatar = _avatarOverlay( + context: context, + hasIcon: user.iconUrl.isNotEmpty, + child: avatar, + ); + } + + return avatar; + }, + ), + ), + const HSpace(12), + Flexible(child: _renderUserNameInput(context)), + ], + ); + } + + Future<void> _showIconPickerDialog(BuildContext context) { + return showDialog( + context: context, + builder: (dialogContext) => SimpleDialog( + title: FlowyText.medium( + LocaleKeys.settings_user_selectAnIcon.tr(), + fontSize: FontSizes.s16, + ), + children: [ + SizedBox( + height: 300, + width: 300, + child: IconGallery( + defaultOption: _defaultIconOption(context), + selectedIcon: user.iconUrl, + onSelectIcon: (iconUrl, isSelected) { + if (isSelected) { + return Navigator.of(context).pop(); + } + + context + .read<SettingsUserViewBloc>() + .add(SettingsUserEvent.updateUserIcon(iconUrl: iconUrl)); + Navigator.of(context).pop(); + }, + ), + ), + ], + ), + ); + } + + // Returns a Widget that is the Default Option for the + // Icon Gallery, enabling users to choose the auto-generated + // icon again. + Widget _defaultIconOption(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + context + .read<SettingsUserViewBloc>() + .add(const SettingsUserEvent.removeUserIcon()); + Navigator.of(context).pop(); + }, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6), + color: user.iconUrl.isEmpty + ? Theme.of(context).colorScheme.primary + : Colors.transparent, + ), + child: FlowyHover( + style: HoverStyle( + hoverColor: user.iconUrl.isEmpty + ? Colors.transparent + : Theme.of(context).colorScheme.tertiaryContainer, + ), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: DecoratedBox( + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: UserAvatar( + iconUrl: "", + name: user.name, + isLarge: true, + ), + ), + ), + ), + ), + ); + } + /// Renders either a login or logout button based on the user's authentication status, or nothing if Supabase is not enabled. /// /// This function checks the current user's authentication type and Supabase @@ -86,9 +194,7 @@ class SettingsUserView extends StatelessWidget { // If the user is logged in locally, render a third-party login button. if (state.userProfile.authType == AuthTypePB.Local) { - return SettingThirdPartyLogin( - didLogin: didLogin, - ); + return SettingThirdPartyLogin(didLogin: didLogin); } return SettingLogoutButton(user: user, didLogout: didLogout); @@ -100,20 +206,49 @@ class SettingsUserView extends StatelessWidget { return UserNameInput(name); } - Widget _renderCurrentIcon(BuildContext context) { - String iconUrl = - context.read<SettingsUserViewBloc>().state.userProfile.iconUrl; - if (iconUrl.isEmpty) { - iconUrl = defaultUserAvatar; - } - return _CurrentIcon(iconUrl); - } - Widget _renderCurrentOpenaiKey(BuildContext context) { final String openAIKey = context.read<SettingsUserViewBloc>().state.userProfile.openaiKey; return _OpenaiKeyInput(openAIKey); } + + Widget _avatarOverlay({ + required BuildContext context, + required bool hasIcon, + required Widget child, + }) => + FlowyTooltip.delayedTooltip( + message: LocaleKeys.settings_user_tooltipSelectIcon.tr(), + child: Stack( + children: [ + Container( + width: 56, + height: 56, + foregroundDecoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .primary + .withOpacity(hasIcon ? 0.8 : 0.5), + shape: BoxShape.circle, + ), + child: child, + ), + const Positioned( + top: 0, + left: 0, + bottom: 0, + right: 0, + child: Center( + child: SizedBox( + width: 32, + height: 32, + child: FlowySvg(FlowySvgs.emoji_s), + ), + ), + ), + ], + ), + ); } @visibleForTesting @@ -317,69 +452,19 @@ class _OpenaiKeyInputState extends State<_OpenaiKeyInput> { } } -class _CurrentIcon extends StatelessWidget { - final String iconUrl; - const _CurrentIcon(this.iconUrl, {Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - void setIcon(String iconUrl) { - context - .read<SettingsUserViewBloc>() - .add(SettingsUserEvent.updateUserIcon(iconUrl)); - Navigator.of(context).pop(); - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - LocaleKeys.settings_user_icon.tr(), - style: Theme.of(context).textTheme.titleSmall!.copyWith( - fontWeight: FontWeight.w500, - fontSize: 13, - ), - ), - InkWell( - borderRadius: Corners.s6Border, - hoverColor: Theme.of(context).colorScheme.secondaryContainer, - onTap: () { - showDialog( - context: context, - builder: (BuildContext context) { - return SimpleDialog( - title: FlowyText.medium( - LocaleKeys.settings_user_selectAnIcon.tr(), - fontSize: FontSizes.s16, - ), - children: [ - SizedBox( - height: 300, - width: 300, - child: IconGallery(setIcon), - ) - ], - ); - }, - ); - }, - child: Container( - margin: const EdgeInsets.fromLTRB(0, 5, 5, 5), - child: FlowySvg( - FlowySvgData('emoji/$iconUrl'), - size: _iconSize, - blendMode: null, - ), - ), - ), - ], - ); - } -} +typedef SelectIconCallback = void Function(String iconUrl, bool isSelected); class IconGallery extends StatelessWidget { - final Function setIcon; - const IconGallery(this.setIcon, {Key? key}) : super(key: key); + final String selectedIcon; + final SelectIconCallback onSelectIcon; + final Widget? defaultOption; + + const IconGallery({ + super.key, + required this.selectedIcon, + required this.onSelectIcon, + this.defaultOption, + }); Future<List<String>> _getIcons(BuildContext context) async { final manifestContent = @@ -403,23 +488,29 @@ class IconGallery extends StatelessWidget { return FutureBuilder<List<String>>( future: _getIcons(context), builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) { - if (snapshot.hasData) { + if (snapshot.hasData && snapshot.data!.isNotEmpty) { return GridView.count( padding: const EdgeInsets.all(20), crossAxisCount: 5, - children: (snapshot.data ?? []).map((String iconUrl) { - return IconOption( - FlowySvgData('emoji/$iconUrl'), - iconUrl, - setIcon, - ); - }).toList(), - ); - } else { - return const Center( - child: CircularProgressIndicator(), + mainAxisSpacing: 4, + crossAxisSpacing: 4, + children: [ + if (defaultOption != null) defaultOption!, + ...snapshot.data! + .mapIndexed( + (int index, String iconUrl) => IconOption( + emoji: FlowySvgData('emoji/$iconUrl'), + iconUrl: iconUrl, + onSelectIcon: onSelectIcon, + isSelected: iconUrl == selectedIcon, + ), + ) + .toList(), + ], ); } + + return const Center(child: CircularProgressIndicator()); }, ); } @@ -428,21 +519,34 @@ class IconGallery extends StatelessWidget { class IconOption extends StatelessWidget { final FlowySvgData emoji; final String iconUrl; - final Function setIcon; + final SelectIconCallback onSelectIcon; + final bool isSelected; - IconOption(this.emoji, this.iconUrl, this.setIcon, {Key? key}) - : super(key: ValueKey(emoji)); + IconOption({ + required this.emoji, + required this.iconUrl, + required this.onSelectIcon, + required this.isSelected, + }) : super(key: ValueKey(emoji)); @override Widget build(BuildContext context) { return InkWell( - borderRadius: Corners.s6Border, + borderRadius: Corners.s8Border, hoverColor: Theme.of(context).colorScheme.tertiaryContainer, - onTap: () => setIcon(iconUrl), - child: FlowySvg( - emoji, - size: _iconSize, - blendMode: null, + onTap: () => onSelectIcon(iconUrl, isSelected), + child: DecoratedBox( + decoration: BoxDecoration( + color: isSelected + ? Theme.of(context).colorScheme.primary + : Colors.transparent, + borderRadius: Corners.s8Border, + ), + child: FlowySvg( + emoji, + size: _iconSize, + blendMode: null, + ), ), ); } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/flowy_tooltip.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/flowy_tooltip.dart new file mode 100644 index 0000000000..ad3b456093 --- /dev/null +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/flowy_tooltip.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +const _tooltipWaitDuration = Duration(milliseconds: 300); + +class FlowyTooltip { + static Tooltip delayedTooltip({ + String? message, + InlineSpan? richMessage, + bool? preferBelow, + Widget? child, + }) { + return Tooltip( + waitDuration: _tooltipWaitDuration, + message: message, + richMessage: richMessage, + preferBelow: preferBelow, + child: child, + ); + } +} diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/user_avatar.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/user_avatar.dart new file mode 100644 index 0000000000..c8882397ed --- /dev/null +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/user_avatar.dart @@ -0,0 +1,82 @@ +import 'package:appflowy/generated/flowy_svgs.g.dart'; +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/util/color_generator/color_generator.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/size.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/material.dart'; + +const double _smallSize = 28; +const double _largeSize = 56; + +class UserAvatar extends StatelessWidget { + const UserAvatar({ + super.key, + required this.iconUrl, + required this.name, + this.isLarge = false, + }); + + final String iconUrl; + final String name; + final bool isLarge; + + @override + Widget build(BuildContext context) { + final size = isLarge ? _largeSize : _smallSize; + + if (iconUrl.isEmpty) { + final String nameOrDefault = _userName(name); + final Color color = ColorGenerator().generateColorFromString(name); + const initialsCount = 2; + + // Taking the first letters of the name components and limiting to 2 elements + final nameInitials = nameOrDefault + .split(' ') + .where((element) => element.isNotEmpty) + .take(initialsCount) + .map((element) => element[0].toUpperCase()) + .join(''); + + return Container( + width: size, + height: size, + alignment: Alignment.center, + decoration: BoxDecoration( + color: color, + shape: BoxShape.circle, + ), + child: FlowyText.semibold( + nameInitials, + color: Colors.white, + fontSize: isLarge + ? nameInitials.length == initialsCount + ? 20 + : 26 + : nameInitials.length == initialsCount + ? 12 + : 14, + ), + ); + } + + return SizedBox.square( + dimension: size, + child: ClipRRect( + borderRadius: Corners.s5Border, + child: CircleAvatar( + backgroundColor: Colors.transparent, + child: FlowySvg( + FlowySvgData('emoji/$iconUrl'), + blendMode: null, + ), + ), + ), + ); + } + + /// Return the user name, if the user name is empty, + /// return the default user name. + String _userName(String name) => + name.isEmpty ? LocaleKeys.defaultUsername.tr() : name; +} diff --git a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/hover.dart b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/hover.dart index ec18ac4d7d..6180b40c7b 100644 --- a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/hover.dart +++ b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/hover.dart @@ -118,6 +118,15 @@ class HoverStyle { this.hoverColor, this.foregroundColorOnHover, }); + + const HoverStyle.transparent({ + this.borderColor = Colors.transparent, + this.borderWidth = 0, + this.borderRadius = const BorderRadius.all(Radius.circular(6)), + this.contentMargin = EdgeInsets.zero, + this.backgroundColor = Colors.transparent, + this.foregroundColorOnHover, + }) : hoverColor = Colors.transparent; } class FlowyHoverContainer extends StatelessWidget { diff --git a/frontend/resources/translations/ar-SA.json b/frontend/resources/translations/ar-SA.json index bdc8bbed84..57ec5a4399 100644 --- a/frontend/resources/translations/ar-SA.json +++ b/frontend/resources/translations/ar-SA.json @@ -258,7 +258,6 @@ }, "user": { "name": "اسم", - "icon": "أيقونة", "selectAnIcon": "حدد أيقونة", "pleaseInputYourOpenAIKey": "الرجاء إدخال مفتاح OpenAI الخاص بك" } diff --git a/frontend/resources/translations/ca-ES.json b/frontend/resources/translations/ca-ES.json index 295fe727c6..6a7fd8952e 100644 --- a/frontend/resources/translations/ca-ES.json +++ b/frontend/resources/translations/ca-ES.json @@ -240,7 +240,6 @@ }, "user": { "name": "Nom", - "icon": "Icona", "selectAnIcon": "Seleccioneu una icona", "pleaseInputYourOpenAIKey": "si us plau, introduïu la vostra clau OpenAI" } diff --git a/frontend/resources/translations/de-DE.json b/frontend/resources/translations/de-DE.json index 011ce8b13d..3c5d455820 100644 --- a/frontend/resources/translations/de-DE.json +++ b/frontend/resources/translations/de-DE.json @@ -249,7 +249,6 @@ }, "user": { "name": "Name", - "icon": "Symbol", "selectAnIcon": "Wählen Sie ein Symbol aus", "pleaseInputYourOpenAIKey": "Bitte geben Sie Ihren OpenAI-Schlüssel ein" } diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 0e525bc45f..aef1f545c6 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -331,7 +331,7 @@ "user": { "name": "Name", "email": "Email", - "icon": "Icon", + "tooltipSelectIcon": "Select icon", "selectAnIcon": "Select an icon", "pleaseInputYourOpenAIKey": "please input your OpenAI key", "clickToLogout": "Click to logout the current user" diff --git a/frontend/resources/translations/es-VE.json b/frontend/resources/translations/es-VE.json index 68b81f2c80..7b305e5f74 100644 --- a/frontend/resources/translations/es-VE.json +++ b/frontend/resources/translations/es-VE.json @@ -246,7 +246,6 @@ }, "user": { "name": "Nombre", - "icon": "Icono", "selectAnIcon": "Seleccione un icono", "pleaseInputYourOpenAIKey": "por favor ingrese su clave OpenAI" } diff --git a/frontend/resources/translations/eu-ES.json b/frontend/resources/translations/eu-ES.json index fc7e809e08..5333e47f23 100644 --- a/frontend/resources/translations/eu-ES.json +++ b/frontend/resources/translations/eu-ES.json @@ -258,7 +258,6 @@ }, "user": { "name": "Izena", - "icon": "Ikonoa", "selectAnIcon": "Hautatu ikono bat", "pleaseInputYourOpenAIKey": "mesedez sartu zure OpenAI gakoa" } diff --git a/frontend/resources/translations/fa.json b/frontend/resources/translations/fa.json index 424ffc5846..cc60bcb0e0 100644 --- a/frontend/resources/translations/fa.json +++ b/frontend/resources/translations/fa.json @@ -296,7 +296,6 @@ }, "user": { "name": "نام", - "icon": "آیکون", "selectAnIcon": "انتخاب یک آیکون", "pleaseInputYourOpenAIKey": "لطفا کلید OpenAI خود را وارد کنید", "clickToLogout": "برای خروج از کاربر فعلی کلیک کنید" diff --git a/frontend/resources/translations/fr-CA.json b/frontend/resources/translations/fr-CA.json index ace3de14a4..fe3af70958 100644 --- a/frontend/resources/translations/fr-CA.json +++ b/frontend/resources/translations/fr-CA.json @@ -240,7 +240,6 @@ }, "user": { "name": "Nom", - "icon": "Icône", "selectAnIcon": "Sélectionnez une icône", "pleaseInputYourOpenAIKey": "veuillez entrer votre clé OpenAI" } diff --git a/frontend/resources/translations/fr-FR.json b/frontend/resources/translations/fr-FR.json index 12f507cd89..98164d55a9 100644 --- a/frontend/resources/translations/fr-FR.json +++ b/frontend/resources/translations/fr-FR.json @@ -250,7 +250,6 @@ }, "user": { "name": "Nom", - "icon": "Icône", "selectAnIcon": "Sélectionnez une icône", "pleaseInputYourOpenAIKey": "veuillez entrer votre clé OpenAI" } diff --git a/frontend/resources/translations/hu-HU.json b/frontend/resources/translations/hu-HU.json index 1d7a2f5876..9a953e70fc 100644 --- a/frontend/resources/translations/hu-HU.json +++ b/frontend/resources/translations/hu-HU.json @@ -240,7 +240,6 @@ }, "user": { "name": "Név", - "icon": "Ikon", "selectAnIcon": "Válasszon ki egy ikont", "pleaseInputYourOpenAIKey": "kérjük, adja meg OpenAI kulcsát" } diff --git a/frontend/resources/translations/id-ID.json b/frontend/resources/translations/id-ID.json index 700c85da6b..3530f7ac14 100644 --- a/frontend/resources/translations/id-ID.json +++ b/frontend/resources/translations/id-ID.json @@ -246,7 +246,6 @@ }, "user": { "name": "Nama", - "icon": "Ikon", "selectAnIcon": "Pilih ikon", "pleaseInputYourOpenAIKey": "silakan masukkan kunci OpenAI Anda" } diff --git a/frontend/resources/translations/it-IT.json b/frontend/resources/translations/it-IT.json index 7f16b2740b..79f234019a 100644 --- a/frontend/resources/translations/it-IT.json +++ b/frontend/resources/translations/it-IT.json @@ -241,7 +241,6 @@ }, "user": { "name": "Nome", - "icon": "Icona", "selectAnIcon": "Seleziona un'icona", "pleaseInputYourOpenAIKey": "inserisci la tua chiave OpenAI" }, @@ -608,4 +607,4 @@ "deleteContentTitle": "Sei sicuro di voler eliminare {pageType}?", "deleteContentCaption": "se elimini questo {pageType}, puoi ripristinarlo dal cestino." } -} +} \ No newline at end of file diff --git a/frontend/resources/translations/ja-JP.json b/frontend/resources/translations/ja-JP.json index 7d92b02cb4..5eeffb1bd6 100644 --- a/frontend/resources/translations/ja-JP.json +++ b/frontend/resources/translations/ja-JP.json @@ -240,7 +240,6 @@ }, "user": { "name": "名前", - "icon": "アイコン", "selectAnIcon": "アイコンを選択してください", "pleaseInputYourOpenAIKey": "OpenAI キーを入力してください" } diff --git a/frontend/resources/translations/ko-KR.json b/frontend/resources/translations/ko-KR.json index 44eee7a7b8..d529c415f8 100644 --- a/frontend/resources/translations/ko-KR.json +++ b/frontend/resources/translations/ko-KR.json @@ -252,7 +252,6 @@ }, "user": { "name": "이름", - "icon": "상", "selectAnIcon": "아이콘을 선택하세요", "pleaseInputYourOpenAIKey": "OpenAI 키를 입력하십시오" } diff --git a/frontend/resources/translations/pl-PL.json b/frontend/resources/translations/pl-PL.json index 8b6cbaf18a..b57c3024bb 100644 --- a/frontend/resources/translations/pl-PL.json +++ b/frontend/resources/translations/pl-PL.json @@ -240,7 +240,6 @@ }, "user": { "name": "Nazwa", - "icon": "Ikona", "selectAnIcon": "Wybierz ikonę", "pleaseInputYourOpenAIKey": "wprowadź swój klucz OpenAI" } diff --git a/frontend/resources/translations/pt-BR.json b/frontend/resources/translations/pt-BR.json index c3a38e37f1..d605edbe29 100644 --- a/frontend/resources/translations/pt-BR.json +++ b/frontend/resources/translations/pt-BR.json @@ -291,7 +291,6 @@ }, "user": { "name": "Nome", - "icon": "Ícone", "selectAnIcon": "Escolha um ícone", "pleaseInputYourOpenAIKey": "por favor insira sua chave OpenAI", "email": "E-mail", diff --git a/frontend/resources/translations/pt-PT.json b/frontend/resources/translations/pt-PT.json index 26f954fbba..89f20f73dc 100644 --- a/frontend/resources/translations/pt-PT.json +++ b/frontend/resources/translations/pt-PT.json @@ -269,7 +269,6 @@ }, "user": { "name": "Nome", - "icon": "Ícone", "selectAnIcon": "Selecione um ícone", "pleaseInputYourOpenAIKey": "por favor insira sua chave OpenAI", "email": "E-mail", diff --git a/frontend/resources/translations/ru-RU.json b/frontend/resources/translations/ru-RU.json index af67e82109..e36aae8e58 100644 --- a/frontend/resources/translations/ru-RU.json +++ b/frontend/resources/translations/ru-RU.json @@ -265,7 +265,6 @@ }, "user": { "name": "Имя", - "icon": "Иконка", "selectAnIcon": "Выбрать иконку", "pleaseInputYourOpenAIKey": "Введите токен OpenAI" } diff --git a/frontend/resources/translations/sv.json b/frontend/resources/translations/sv.json index f476c293b2..f4ae8d7ac6 100644 --- a/frontend/resources/translations/sv.json +++ b/frontend/resources/translations/sv.json @@ -250,7 +250,6 @@ }, "user": { "name": "namn", - "icon": "Ikon", "selectAnIcon": "Välj en ikon", "pleaseInputYourOpenAIKey": "vänligen ange din OpenAI-nyckel" } @@ -597,4 +596,4 @@ "deleteContentTitle": "Är du säker på att du vill ta bort {pageType}?", "deleteContentCaption": "om du tar bort denna {pageType} kan du återställa den från papperskorgen." } -} +} \ No newline at end of file diff --git a/frontend/resources/translations/tr-TR.json b/frontend/resources/translations/tr-TR.json index fe7ba37440..a4f9f47b71 100644 --- a/frontend/resources/translations/tr-TR.json +++ b/frontend/resources/translations/tr-TR.json @@ -240,7 +240,6 @@ }, "user": { "name": "İsim", - "icon": "Simge", "selectAnIcon": "Bir simge seçin", "pleaseInputYourOpenAIKey": "lütfen OpenAI anahtarınızı girin" } diff --git a/frontend/resources/translations/ur.json b/frontend/resources/translations/ur.json index 040745745f..836eae6e09 100644 --- a/frontend/resources/translations/ur.json +++ b/frontend/resources/translations/ur.json @@ -331,7 +331,6 @@ "user": { "name": "نام", "email": "ای میل", - "icon": "آئیکن", "selectAnIcon": "آئیکن منتخب کریں", "pleaseInputYourOpenAIKey": "براہ کرم اپنی OpenAI کی درج کریں", "clickToLogout": "موجودہ صارف سے لاگ آؤٹ کرنے کے لیے کلک کریں" diff --git a/frontend/resources/translations/zh-CN.json b/frontend/resources/translations/zh-CN.json index 0b374fb2df..7c4ca91be1 100644 --- a/frontend/resources/translations/zh-CN.json +++ b/frontend/resources/translations/zh-CN.json @@ -267,7 +267,6 @@ }, "user": { "name": "名字", - "icon": "图标", "selectAnIcon": "选择一个图标", "pleaseInputYourOpenAIKey": "请输入您的 OpenAI 密钥" } diff --git a/frontend/resources/translations/zh-TW.json b/frontend/resources/translations/zh-TW.json index b637da3a4c..2e73f1d740 100644 --- a/frontend/resources/translations/zh-TW.json +++ b/frontend/resources/translations/zh-TW.json @@ -258,7 +258,6 @@ }, "user": { "name": "名稱", - "icon": "圖標", "selectAnIcon": "選擇圖標", "pleaseInputYourOpenAIKey": "請輸入你的 OpenAI 密鑰" }