diff --git a/lib/features/manage_account/presentation/language_and_region/extensions/locale_extension.dart b/lib/features/manage_account/presentation/language_and_region/extensions/locale_extension.dart index d10ee439b..0264e4106 100644 --- a/lib/features/manage_account/presentation/language_and_region/extensions/locale_extension.dart +++ b/lib/features/manage_account/presentation/language_and_region/extensions/locale_extension.dart @@ -14,6 +14,8 @@ extension LocaleExtension on Locale { return AppLocalizations.of(context).languageVietnamese; case 'ru': return AppLocalizations.of(context).languageRussian; + case 'ar': + return AppLocalizations.of(context).languageArabic; default: return ''; } diff --git a/lib/features/manage_account/presentation/language_and_region/language_and_region_controller.dart b/lib/features/manage_account/presentation/language_and_region/language_and_region_controller.dart index 75eb548d5..c78de2260 100644 --- a/lib/features/manage_account/presentation/language_and_region/language_and_region_controller.dart +++ b/lib/features/manage_account/presentation/language_and_region/language_and_region_controller.dart @@ -1,6 +1,7 @@ import 'dart:ui'; +import 'package:core/utils/app_logger.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/save_language_state.dart'; @@ -13,6 +14,7 @@ class LanguageAndRegionController extends BaseController { final listSupportedLanguages = [].obs; final languageSelected = LocalizationService.defaultLocale.obs; + final isLanguageMenuOverlayOpen = RxBool(false); LanguageAndRegionController(this._saveLanguageInteractor); @@ -37,6 +39,7 @@ class LanguageAndRegionController extends BaseController { listSupportedLanguages.value = LocalizationService.supportedLocales; final currentLocale = Get.locale; + log('LanguageAndRegionController::_setUpSupportedLanguages():currentLocale: $currentLocale'); if (currentLocale != null) { languageSelected.value = currentLocale; } else { @@ -45,6 +48,7 @@ class LanguageAndRegionController extends BaseController { } void selectLanguage(Locale? selectedLocale) { + isLanguageMenuOverlayOpen.value = false; languageSelected.value = selectedLocale ?? LocalizationService.defaultLocale; _saveLanguage(languageSelected.value); } @@ -52,4 +56,8 @@ class LanguageAndRegionController extends BaseController { void _saveLanguage(Locale localeCurrent) { consumeState(_saveLanguageInteractor.execute(localeCurrent)); } + + void toggleLanguageMenuOverlay() { + isLanguageMenuOverlayOpen.toggle(); + } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/language_and_region/language_and_region_view.dart b/lib/features/manage_account/presentation/language_and_region/language_and_region_view.dart index ea50c8467..eb79140a4 100644 --- a/lib/features/manage_account/presentation/language_and_region/language_and_region_view.dart +++ b/lib/features/manage_account/presentation/language_and_region/language_and_region_view.dart @@ -1,9 +1,10 @@ -import 'package:core/core.dart'; +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_controller.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/widgets/change_language_widget.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/widgets/change_language_button_widget.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/widgets/language_and_region_header_widget.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart'; @@ -43,7 +44,7 @@ class LanguageAndRegionView extends GetWidget { children: [ const LanguageAndRegionHeaderWidget(), const SizedBox(height: 22), - Expanded(child: ChangeLanguageWidget()) + Expanded(child: ChangeLanguageButtonWidget()) ] ), ), diff --git a/lib/features/manage_account/presentation/language_and_region/widgets/change_language_button_widget.dart b/lib/features/manage_account/presentation/language_and_region/widgets/change_language_button_widget.dart new file mode 100644 index 000000000..4f18cac8b --- /dev/null +++ b/lib/features/manage_account/presentation/language_and_region/widgets/change_language_button_widget.dart @@ -0,0 +1,131 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/presentation/utils/style_utils.dart'; +import 'package:core/presentation/views/responsive/responsive_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/extensions/locale_extension.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/widgets/language_menu_overlay.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class ChangeLanguageButtonWidget extends StatelessWidget { + + final _controller = Get.find(); + final _responsiveUtils = Get.find(); + final _imagePaths = Get.find(); + + ChangeLanguageButtonWidget({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (context, constraints) { + return ResponsiveWidget( + responsiveUtils: _responsiveUtils, + mobile: Scaffold( + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitleLanguageWidget(context), + const SizedBox(height: 8), + _buildLanguageMenu(context, constraints.maxWidth) + ] + ) + ), + desktop: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitleLanguageWidget(context), + const SizedBox(height: 8), + SizedBox( + width: constraints.maxWidth / 2, + child: _buildLanguageMenu(context, constraints.maxWidth / 2) + ), + ] + ) + ); + }); + } + + Widget _buildTitleLanguageWidget(BuildContext context) { + return Text( + AppLocalizations.of(context).language, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.normal, + color: AppColor.colorContentEmail + ) + ); + } + + Widget _buildLanguageMenu(BuildContext context, double maxWidth) { + return Obx(() => PortalTarget( + visible: _controller.isLanguageMenuOverlayOpen.isTrue, + portalFollower: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _controller.toggleLanguageMenuOverlay() + ), + child: PortalTarget( + anchor: const Aligned( + follower: Alignment.topRight, + target: Alignment.bottomRight, + widthFactor: 1, + backup: Aligned( + follower: Alignment.topRight, + target: Alignment.bottomRight, + widthFactor: 1, + ), + ), + portalFollower: Obx(() => LanguageRegionOverlay( + listSupportedLanguages: _controller.listSupportedLanguages, + localeSelected: _controller.languageSelected.value, + maxWidth: maxWidth, + onSelectLanguageAction: _controller.selectLanguage, + )), + visible: _controller.isLanguageMenuOverlayOpen.isTrue, + child: _buildDropDownMenuButton(context, maxWidth) + ) + )); + } + + Widget _buildDropDownMenuButton(BuildContext context, double maxWidth) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: () => _controller.toggleLanguageMenuOverlay(), + borderRadius: const BorderRadius.all(Radius.circular(10)), + child: Container( + height: 44, + width: maxWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: AppColor.colorInputBorderCreateMailbox, + width: 0.5, + ), + color: AppColor.colorItemSelected, + ), + padding: const EdgeInsets.only(left: 12, right: 10), + child: Row(children: [ + Expanded(child: Text( + _controller.languageSelected.value.getLanguageName(context), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black + ), + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + )), + SvgPicture.asset(_imagePaths.icDropDown) + ]), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/language_and_region/widgets/change_language_widget.dart b/lib/features/manage_account/presentation/language_and_region/widgets/change_language_widget.dart deleted file mode 100644 index 4b26260da..000000000 --- a/lib/features/manage_account/presentation/language_and_region/widgets/change_language_widget.dart +++ /dev/null @@ -1,59 +0,0 @@ - -import 'package:core/core.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_controller.dart'; -import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; - -class ChangeLanguageWidget extends StatelessWidget { - - final _controller = Get.find(); - final _responsiveUtils = Get.find(); - - ChangeLanguageWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final titleLanguageWidget = Text( - AppLocalizations.of(context).language, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.normal, - color: AppColor.colorContentEmail)); - - final dropDownMenuSelectLanguage = Row(children: [ - Expanded(child: Obx(() => - DropDownButtonWidget( - items: _controller.listSupportedLanguages, - itemSelected: _controller.languageSelected.value, - onChanged: (newLanguage) => - _controller.selectLanguage(newLanguage), - supportSelectionIcon: true))), - ]); - - return LayoutBuilder(builder: (context, constraints) { - return ResponsiveWidget( - responsiveUtils: _responsiveUtils, - mobile: Scaffold( - body: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - titleLanguageWidget, - const SizedBox(height: 8), - dropDownMenuSelectLanguage - ] - )), - desktop: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - titleLanguageWidget, - const SizedBox(height: 8), - SizedBox( - width: constraints.maxWidth / 2, - child: dropDownMenuSelectLanguage - ), - ])); - }); - } -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/language_and_region/widgets/language_menu_overlay.dart b/lib/features/manage_account/presentation/language_and_region/widgets/language_menu_overlay.dart new file mode 100644 index 000000000..341c118ba --- /dev/null +++ b/lib/features/manage_account/presentation/language_and_region/widgets/language_menu_overlay.dart @@ -0,0 +1,65 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/widgets/lanuage_item_widget.dart'; + +class LanguageRegionOverlay extends StatelessWidget { + + final List listSupportedLanguages; + final Locale localeSelected; + final double? maxWidth; + final OnSelectLanguageAction onSelectLanguageAction; + + const LanguageRegionOverlay({ + Key? key, + required this.listSupportedLanguages, + required this.localeSelected, + required this.onSelectLanguageAction, + this.maxWidth, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + constraints: BoxConstraints(maxHeight: _getHeightOverlay(context)), + width: maxWidth, + margin: const EdgeInsets.only(top: 4, bottom: 24), + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: const [ + BoxShadow( + color: AppColor.colorShadowBgContentEmail, + blurRadius: 24, + offset: Offset(0, 8)), + BoxShadow( + color: AppColor.colorShadowBgContentEmail, + blurRadius: 2, + offset: Offset.zero), + ] + ), + child: ListView.builder( + shrinkWrap: true, + itemCount: listSupportedLanguages.length, + itemBuilder: (context, index) => LanguageItemWidget( + localeSelected: localeSelected, + localeCurrent: listSupportedLanguages[index], + onSelectLanguageAction: onSelectLanguageAction + ) + ), + ); + } + + double _getHeightOverlay(BuildContext context) { + final responsiveUtils = Get.find(); + const double maxHeightTopBar = 80; + const double maxHeightTitleLanguage = 200; + const double paddingBottom = 16; + final currentHeight = responsiveUtils.getSizeScreenHeight(context); + double maxHeightForm = currentHeight - maxHeightTopBar - maxHeightTitleLanguage - paddingBottom; + return maxHeightForm; + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/language_and_region/widgets/lanuage_item_widget.dart b/lib/features/manage_account/presentation/language_and_region/widgets/lanuage_item_widget.dart new file mode 100644 index 000000000..a8ea596fc --- /dev/null +++ b/lib/features/manage_account/presentation/language_and_region/widgets/lanuage_item_widget.dart @@ -0,0 +1,59 @@ + +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/style_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/extensions/locale_extension.dart'; + +typedef OnSelectLanguageAction = Function(Locale? localeSelected); + +class LanguageItemWidget extends StatelessWidget { + + final Locale localeSelected; + final Locale localeCurrent; + final OnSelectLanguageAction onSelectLanguageAction; + + const LanguageItemWidget({ + super.key, + required this.localeCurrent, + required this.localeSelected, + required this.onSelectLanguageAction, + }); + + @override + Widget build(BuildContext context) { + final imagePaths = Get.find(); + + return Material( + color: Colors.transparent, + child: InkWell( + onTap: () => onSelectLanguageAction.call(localeCurrent), + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), + child: Row(children: [ + Expanded(child: Text( + localeCurrent.getLanguageName(context), + style: const TextStyle( + fontSize: 17, + fontWeight: FontWeight.normal, + color: Colors.black + ), + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + )), + if (localeCurrent == localeSelected) + SvgPicture.asset( + imagePaths.icChecked, + width: 20, + height: 20, + fit: BoxFit.fill + ) + ]), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 5cb999f2e..0270456b4 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-03-03T11:59:08.917209", + "@@last_modified": "2023-03-10T13:53:08.023350", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1572,6 +1572,12 @@ "placeholders_order": [], "placeholders": {} }, + "languageArabic": "Arabic", + "@languageArabic": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, "messageDialogSendEmailUploadingAttachment": "Your message could not be sent because it uploading attachment", "@messageDialogSendEmailUploadingAttachment": { "type": "text", diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 41bb2acca..4585a467e 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1603,6 +1603,12 @@ class AppLocalizations { name: 'languageRussian'); } + String get languageArabic { + return Intl.message( + 'Arabic', + name: 'languageArabic'); + } + String get messageDialogSendEmailUploadingAttachment { return Intl.message( 'Your message could not be sent because it uploading attachment', diff --git a/lib/main/localizations/localization_service.dart b/lib/main/localizations/localization_service.dart index 3f2b195d0..05943cdb5 100644 --- a/lib/main/localizations/localization_service.dart +++ b/lib/main/localizations/localization_service.dart @@ -14,14 +14,16 @@ class LocalizationService extends Translations { 'fr', 'en', 'vi', - 'ru' + 'ru', + 'ar' ]; static const List supportedLocales = [ Locale('fr', 'FR'), Locale('en', 'US'), Locale('vi', 'VN'), - Locale('ru', 'RU') + Locale('ru', 'RU'), + Locale('ar', 'TN') ]; static final locale = _getLocaleFromLanguage();