From aa139eb1126daf764e22891dc239ae29b73f1f59 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 17 Aug 2022 17:37:18 +0700 Subject: [PATCH] TF-801 Add presentation layer for get all vacation --- assets/images/ic_configuration.svg | 3 + assets/images/ic_profiles.svg | 4 +- assets/images/ic_sign_out.svg | 3 + .../extensions/color_extension.dart | 1 + .../presentation/resources/image_paths.dart | 2 + .../base/widget/border_button_field.dart | 83 ++++ .../configuration/configuration_bindings.dart | 38 ++ .../configuration_controller.dart | 11 + .../configuration/configuration_view.dart | 81 ++++ .../vacation/vacation_bindings.dart | 34 ++ .../vacation/vacation_controller.dart | 162 +++++++ .../configuration/vacation/vacation_view.dart | 454 ++++++++++++++++++ .../vacation_input_decoration_builder.dart | 37 ++ .../email_rules/email_rules_view.dart | 6 +- .../extensions/datetime_extension.dart | 23 + .../language_and_region_view.dart | 4 +- .../manage_account_dashboard_bindings.dart | 2 + .../manage_account_dashboard_controller.dart | 5 +- .../manage_account_dashboard_view.dart | 3 + .../menu/manage_account_menu_controller.dart | 4 + .../menu/manage_account_menu_view.dart | 2 +- .../account_menu_item_tile_builder.dart | 33 +- .../presentation/model/account_menu_item.dart | 8 +- .../model/configuration_tab_type.dart | 13 + .../model/vacation/date_type.dart | 17 + .../model/vacation/vacation_presentation.dart | 47 ++ .../vacation/vacation_responder_status.dart | 17 + .../profiles/identities/identities_view.dart | 5 +- .../profiles/profiles_bindings.dart | 1 - .../presentation/profiles/profiles_view.dart | 2 +- lib/l10n/intl_messages.arb | 80 ++- lib/main/localizations/app_localizations.dart | 91 ++++ pubspec.yaml | 2 + 33 files changed, 1240 insertions(+), 38 deletions(-) create mode 100644 assets/images/ic_configuration.svg create mode 100644 assets/images/ic_sign_out.svg create mode 100644 lib/features/base/widget/border_button_field.dart create mode 100644 lib/features/manage_account/presentation/configuration/configuration_bindings.dart create mode 100644 lib/features/manage_account/presentation/configuration/configuration_controller.dart create mode 100644 lib/features/manage_account/presentation/configuration/configuration_view.dart create mode 100644 lib/features/manage_account/presentation/configuration/vacation/vacation_bindings.dart create mode 100644 lib/features/manage_account/presentation/configuration/vacation/vacation_controller.dart create mode 100644 lib/features/manage_account/presentation/configuration/vacation/vacation_view.dart create mode 100644 lib/features/manage_account/presentation/configuration/vacation/widgets/vacation_input_decoration_builder.dart create mode 100644 lib/features/manage_account/presentation/extensions/datetime_extension.dart create mode 100644 lib/features/manage_account/presentation/model/configuration_tab_type.dart create mode 100644 lib/features/manage_account/presentation/model/vacation/date_type.dart create mode 100644 lib/features/manage_account/presentation/model/vacation/vacation_presentation.dart create mode 100644 lib/features/manage_account/presentation/model/vacation/vacation_responder_status.dart diff --git a/assets/images/ic_configuration.svg b/assets/images/ic_configuration.svg new file mode 100644 index 000000000..745286afd --- /dev/null +++ b/assets/images/ic_configuration.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_profiles.svg b/assets/images/ic_profiles.svg index e3ccfc17e..73751c9f1 100644 --- a/assets/images/ic_profiles.svg +++ b/assets/images/ic_profiles.svg @@ -1,3 +1,3 @@ - - + + diff --git a/assets/images/ic_sign_out.svg b/assets/images/ic_sign_out.svg new file mode 100644 index 000000000..7bcc58e90 --- /dev/null +++ b/assets/images/ic_sign_out.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 294bf552a..4503f362d 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -137,6 +137,7 @@ extension AppColor on Color { static const colorBorderListForwardsFilter = Color(0xFFE7E8EC); static const colorBackgroundFieldConditionRulesFilter = Color(0xFFF2F3F5); static const colorDividerRuleFilter = Color(0xFFE7E8EC); + static const colorIconTextField = Color(0xFFB8C1CC); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 23f7892d3..772712f70 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -153,6 +153,8 @@ class ImagePaths { String get icEditRuleMobile => _getImagePath('ic_edit_rule_mobile.svg'); String get icDeleteRuleMobile => _getImagePath('ic_delete_rule_mobile.svg'); String get icDeleteEmailForward => _getImagePath('ic_delete_email_forward.svg'); + String get icVacation => _getImagePath('ic_vacation.svg'); + String get icSignOut => _getImagePath('ic_sign_out.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/base/widget/border_button_field.dart b/lib/features/base/widget/border_button_field.dart new file mode 100644 index 000000000..d350df417 --- /dev/null +++ b/lib/features/base/widget/border_button_field.dart @@ -0,0 +1,83 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +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/extensions/datetime_extension.dart'; + +typedef OnTapActionCallback = Function(T? value); + +class BorderButtonField extends StatelessWidget { + + final T? value; + final OnTapActionCallback? tapActionCallback; + final Widget? icon; + final TextStyle? textStyle; + final MouseCursor? mouseCursor; + final String? hintText; + + const BorderButtonField({ + super.key, + this.value, + this.tapActionCallback, + this.icon, + this.textStyle, + this.mouseCursor, + this.hintText, + }); + + @override + Widget build(BuildContext context) { + final _imagePaths = Get.find(); + + return InkWell( + onTap: () => tapActionCallback?.call(value), + mouseCursor: mouseCursor, + child: Container( + height: 44, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: AppColor.colorInputBorderCreateMailbox, + width: 1), + color: Colors.white), + padding: const EdgeInsets.only(left: 12, right: 10), + child: Row(children: [ + Expanded(child: Text( + _getName(context, value), + style: _getTextStyle(value), + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + )), + icon ?? SvgPicture.asset(_imagePaths.icDropDown) + ]), + ), + ); + } + + TextStyle? _getTextStyle(T? value) { + if (hintText != null && value == null) { + return const TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: AppColor.colorHintInputCreateMailbox); + } + return textStyle ?? const TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black); + } + + String _getName(BuildContext context, T? value) { + if (value is DateTime) { + return value.formatDate(locale: Localizations.localeOf(context).toLanguageTag()); + } + if (value is TimeOfDay) { + return value.formatTime(context); + } + return hintText ?? ''; + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/configuration/configuration_bindings.dart b/lib/features/manage_account/presentation/configuration/configuration_bindings.dart new file mode 100644 index 000000000..232018bc9 --- /dev/null +++ b/lib/features/manage_account/presentation/configuration/configuration_bindings.dart @@ -0,0 +1,38 @@ +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/base_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/configuration_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/vacation/vacation_bindings.dart'; + +class ConfigurationBindings extends BaseBindings { + + @override + void dependencies() { + super.dependencies(); + VacationBindings().dependencies(); + } + + @override + void bindingsController() { + Get.lazyPut(() => ConfigurationController()); + } + + @override + void bindingsDataSource() { + } + + @override + void bindingsDataSourceImpl() { + } + + @override + void bindingsInteractor() { + } + + @override + void bindingsRepository() { + } + + @override + void bindingsRepositoryImpl() { + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/configuration/configuration_controller.dart b/lib/features/manage_account/presentation/configuration/configuration_controller.dart new file mode 100644 index 000000000..c5d766365 --- /dev/null +++ b/lib/features/manage_account/presentation/configuration/configuration_controller.dart @@ -0,0 +1,11 @@ + +import 'package:tmail_ui_user/features/base/base_controller.dart'; + +class ConfigurationController extends BaseController { + + @override + void onDone() {} + + @override + void onError(error) {} +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/configuration/configuration_view.dart b/lib/features/manage_account/presentation/configuration/configuration_view.dart new file mode 100644 index 000000000..a085080df --- /dev/null +++ b/lib/features/manage_account/presentation/configuration/configuration_view.dart @@ -0,0 +1,81 @@ + +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/configuration_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/vacation/vacation_view.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/configuration_tab_type.dart'; + +class ConfigurationView extends GetWidget { + + final _responsiveUtils = Get.find(); + + ConfigurationView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: _responsiveUtils.isWebDesktop(context) + ? AppColor.colorBgDesktop + : Colors.white, + body: Container( + margin: _responsiveUtils.isWebDesktop(context) + ? const EdgeInsets.all(24) + : EdgeInsets.zero, + color: _responsiveUtils.isWebDesktop(context) ? null : Colors.white, + decoration: _responsiveUtils.isWebDesktop(context) + ? BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all(color: AppColor.colorBorderBodyThread, width: 1), + color: Colors.white) + : null, + child: ClipRRect( + borderRadius: BorderRadius.circular( + _responsiveUtils.isWebDesktop(context) ? 20 : 0), + child: Padding( + padding: const EdgeInsets.only( + left: BuildUtils.isWeb ? 10 : 0, + right: 10, + bottom: 10), + child: DefaultTabController( + initialIndex: 0, + length: 1, + child: Scaffold( + appBar: TabBar( + unselectedLabelColor: AppColor.colorTextButtonHeaderThread, + unselectedLabelStyle: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: AppColor.colorTextButtonHeaderThread), + labelStyle: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: AppColor.primaryColor), + labelColor: AppColor.primaryColor, + indicatorSize: TabBarIndicatorSize.label, + isScrollable: true, + indicator: const CustomIndicator( + indicatorHeight: 4, + indicatorColor: AppColor.primaryColor, + indicatorSize: CustomIndicatorSize.full), + onTap: (index) {}, + tabs: ConfigurationTabType.values + .map((tab) => Tab(text: tab.getTitle(context))) + .toList() + ), + body: Column(children: [ + const Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), + Expanded(child: TabBarView( + children: [ + VacationView(), + ], + )) + ]), + ) + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/configuration/vacation/vacation_bindings.dart b/lib/features/manage_account/presentation/configuration/vacation/vacation_bindings.dart new file mode 100644 index 000000000..8f3adbfeb --- /dev/null +++ b/lib/features/manage_account/presentation/configuration/vacation/vacation_bindings.dart @@ -0,0 +1,34 @@ +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/base_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_vacation_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/vacation/vacation_controller.dart'; + +class VacationBindings extends BaseBindings { + + @override + void bindingsController() { + Get.lazyPut(() => VacationController(Get.find())); + } + + @override + void bindingsDataSource() { + } + + @override + void bindingsDataSourceImpl() { + } + + @override + void bindingsInteractor() { + Get.lazyPut(() => GetAllVacationInteractor(Get.find())); + } + + @override + void bindingsRepository() { + } + + @override + void bindingsRepositoryImpl() { + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/configuration/vacation/vacation_controller.dart b/lib/features/manage_account/presentation/configuration/vacation/vacation_controller.dart new file mode 100644 index 000000000..20a693075 --- /dev/null +++ b/lib/features/manage_account/presentation/configuration/vacation/vacation_controller.dart @@ -0,0 +1,162 @@ +import 'package:core/utils/app_logger.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/mail/vacation/vacation_response.dart'; +import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_vacation_state.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_vacation_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/vacation/date_type.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/vacation/vacation_presentation.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/vacation/vacation_responder_status.dart'; + +class VacationController extends BaseController { + + final _accountDashBoardController = Get.find(); + + final GetAllVacationInteractor _getAllVacationInteractor; + + final vacationPresentation = VacationPresentation.initialize().obs; + + final TextEditingController messageBodyEditorController = TextEditingController(); + + VacationResponse? currentVacation; + + VacationController(this._getAllVacationInteractor); + + @override + void onReady() { + _getAllVacation(); + super.onReady(); + } + + @override + void onDone() { + viewState.value.fold( + (failure) => null, + (success) { + if (success is GetAllVacationSuccess) { + _handleGetAllVacationSuccess(success); + } + } + ); + } + + @override + void onError(error) {} + + void _getAllVacation() { + final accountId = _accountDashBoardController.accountId.value; + if (accountId != null) { + consumeState(_getAllVacationInteractor.execute(accountId)); + } + } + + void _handleGetAllVacationSuccess(GetAllVacationSuccess success) { + if (success.listVacationResponse?.isNotEmpty == true) { + currentVacation = success.listVacationResponse!.first; + log('VacationController::_handleGetAllVacationSuccess(): $currentVacation'); + + final vacationStatus = currentVacation?.isEnabled; + final startDate = currentVacation?.fromDate?.value; + final endDate = currentVacation?.toDate?.value; + final messageBody = currentVacation?.htmlBody ?? currentVacation?.textBody; + final startTime = startDate != null + ? TimeOfDay.fromDateTime(startDate) + : null; + final endTime = endDate != null + ? TimeOfDay.fromDateTime(endDate) + : null; + final vacationStopEnabled = endDate != null; + + if (messageBody != null) { + messageBodyEditorController.text = messageBody; + } + + updateVacationPresentation( + newStatus: vacationStatus == true + ? VacationResponderStatus.activated + : VacationResponderStatus.deactivated, + startDate: startDate, + startTime: startTime, + endDate: endDate, + endTime: endTime, + vacationStopEnabled: vacationStopEnabled, + ); + } + } + + bool get isVacationDeactivated => + vacationPresentation.value.status == VacationResponderStatus.deactivated; + + bool get isVacationStopEnabled => vacationPresentation.value.vacationStopEnabled; + + bool get canChangeEndDate => !isVacationDeactivated && isVacationStopEnabled; + + void updateVacationPresentation({ + VacationResponderStatus? newStatus, + DateTime? startDate, + TimeOfDay? startTime, + DateTime? endDate, + TimeOfDay? endTime, + bool? vacationStopEnabled, + }) { + final currentVacation = vacationPresentation.value; + final newVacation = currentVacation.copyWidth( + status: newStatus, + startDate: startDate, + startTime: startTime, + endDate: endDate, + endTime: endTime, + vacationStopEnabled: vacationStopEnabled); + vacationPresentation.value = newVacation; + } + + void selectDate(BuildContext context, DateType dateType, DateTime? currentDate) async { + final datePicked = await showDatePicker( + context: context, + initialDate: currentDate ?? DateTime.now(), + initialDatePickerMode: DatePickerMode.day, + firstDate: DateTime(1900), + lastDate: DateTime(2100), + locale: Localizations.localeOf(context) + ); + + if (datePicked == null) { + return; + } + + if (dateType == DateType.start) { + updateVacationPresentation(startDate: datePicked); + } else { + updateVacationPresentation(endDate: datePicked); + } + } + + void selectTime(BuildContext context, DateType dateType, TimeOfDay? currentTime) async { + final timePicked = await showTimePicker( + context: context, + initialTime: currentTime ?? TimeOfDay.now(), + ); + + if (timePicked == null) { + return; + } + + if (dateType == DateType.start) { + updateVacationPresentation(startTime: timePicked); + } else { + updateVacationPresentation(endTime: timePicked); + } + } + + void saveVacation(BuildContext context) { + + } + + @override + void onClose() { + messageBodyEditorController.dispose(); + super.onClose(); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/configuration/vacation/vacation_view.dart b/lib/features/manage_account/presentation/configuration/vacation/vacation_view.dart new file mode 100644 index 000000000..5af8199b6 --- /dev/null +++ b/lib/features/manage_account/presentation/configuration/vacation/vacation_view.dart @@ -0,0 +1,454 @@ + +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/widget/border_button_field.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/vacation/vacation_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/vacation/widgets/vacation_input_decoration_builder.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/vacation/date_type.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/vacation/vacation_responder_status.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:toggle_switch/toggle_switch.dart'; + +class VacationView extends GetWidget { + + final _responsiveUtils = Get.find(); + + VacationView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: Container( + width: double.infinity, + color: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16), + child: ResponsiveWidget( + responsiveUtils: _responsiveUtils, + desktop: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(children: [ + Container( + width: 200, + color: Colors.white, + child: Text( + AppLocalizations.of(context).vacationResponder, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black))), + const SizedBox(width: 16), + ToggleSwitch( + minWidth: 150.0, + cornerRadius: 20.0, + activeBgColors: const [[Colors.green], [Colors.redAccent]], + activeFgColor: Colors.white, + inactiveBgColor: Colors.grey, + inactiveFgColor: Colors.white, + initialLabelIndex: 1, + totalSwitches: VacationResponderStatus.values.length, + labels: VacationResponderStatus.values + .map((status) => status.getTitle(context)) + .toList(), + radiusStyle: true, + onToggle: (index) { + log('VacationView::build():ToggleSwitch:index: $index'); + final newStatus = index == 0 + ? VacationResponderStatus.activated + : VacationResponderStatus.deactivated; + controller.updateVacationPresentation(newStatus: newStatus); + }, + ), + ]), + const SizedBox(height: 20), + Obx(() => AbsorbPointer( + absorbing: controller.isVacationDeactivated, + child: Row(children: [ + Container( + width: 200, + color: Colors.white, + child: Text( + AppLocalizations.of(context).startDate, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0)))), + const SizedBox(width: 16), + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.startDate, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).startDate, + icon: const Icon( + Icons.date_range, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectDate(context, DateType.start, value)))), + const SizedBox(width: 16), + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.startTime, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).noStartTime, + icon: const Icon( + Icons.timer, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectTime(context, DateType.start, value)))), + ]), + )), + const SizedBox(height: 20), + Obx(() => AbsorbPointer( + absorbing: controller.isVacationDeactivated, + child: Container( + width: 200, + color: Colors.white, + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + activeColor: AppColor.primaryColor.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0), + controlAffinity: ListTileControlAffinity.leading, + value: controller.vacationPresentation.value.vacationStopEnabled, + onChanged: (value) => + controller.updateVacationPresentation(vacationStopEnabled: value), + title: Text(AppLocalizations.of(context).vacationStopsAt, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0))), + ), + ), + )), + Obx(() => AbsorbPointer( + absorbing: !controller.canChangeEndDate, + child: Row(children: [ + Container( + width: 200, + color: Colors.white, + child: Text( + AppLocalizations.of(context).endDate, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + !controller.canChangeEndDate ? 0.5 : 1.0)))), + const SizedBox(width: 16), + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.endDate, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + !controller.canChangeEndDate ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).noEndDate, + icon: const Icon( + Icons.date_range, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectDate(context, DateType.end, value)))), + const SizedBox(width: 16), + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.endTime, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + !controller.canChangeEndDate ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).noEndTime, + icon: const Icon( + Icons.timer, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectTime(context, DateType.end, value)))), + ]) + )), + const SizedBox(height: 20), + Obx(() => AbsorbPointer( + absorbing: controller.isVacationDeactivated, + child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Container( + width: 200, + color: Colors.white, + child: Text( + AppLocalizations.of(context).messageBody, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0)))), + const SizedBox(width: 16), + Expanded(child: _buildMessageBodyWidget( + context, + controller.isVacationDeactivated ? 0.5 : 1.0)) + ]), + )), + const SizedBox(height: 20), + Align( + alignment: Alignment.centerRight, + child: buildTextButton( + AppLocalizations.of(context).save, + width: 128, + height: 44, + radius: 10, + onTap: () => controller.saveVacation(context)), + ) + ] + ), + ), + mobile: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_responsiveUtils.isPortraitMobile(context)) + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + AppLocalizations.of(context).vacationResponder, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black)), + const SizedBox(height: 16), + ToggleSwitch( + minWidth: 150.0, + cornerRadius: 20.0, + activeBgColors: const [[Colors.green], [Colors.redAccent]], + activeFgColor: Colors.white, + inactiveBgColor: Colors.grey, + inactiveFgColor: Colors.white, + initialLabelIndex: 1, + totalSwitches: VacationResponderStatus.values.length, + labels: VacationResponderStatus.values + .map((status) => status.getTitle(context)) + .toList(), + radiusStyle: true, + onToggle: (index) { + log('VacationView::build():ToggleSwitch:index: $index'); + final newStatus = index == 0 + ? VacationResponderStatus.activated + : VacationResponderStatus.deactivated; + controller.updateVacationPresentation(newStatus: newStatus); + }, + ) + ]) + else + Row(children: [ + Expanded( + child: Text( + AppLocalizations.of(context).vacationResponder, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black)), + ), + const SizedBox(width: 16), + ToggleSwitch( + minWidth: 150.0, + cornerRadius: 20.0, + activeBgColors: const [[Colors.green], [Colors.redAccent]], + activeFgColor: Colors.white, + inactiveBgColor: Colors.grey, + inactiveFgColor: Colors.white, + initialLabelIndex: 1, + totalSwitches: VacationResponderStatus.values.length, + labels: VacationResponderStatus.values + .map((status) => status.getTitle(context)) + .toList(), + radiusStyle: true, + onToggle: (index) { + log('VacationView::build():ToggleSwitch:index: $index'); + final newStatus = index == 0 + ? VacationResponderStatus.activated + : VacationResponderStatus.deactivated; + controller.updateVacationPresentation(newStatus: newStatus); + }, + ) + ]), + const SizedBox(height: 20), + Obx(() => AbsorbPointer( + absorbing: controller.isVacationDeactivated, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + AppLocalizations.of(context).startDate, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0))), + const SizedBox(height: 16), + Row(children: [ + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.startDate, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).startDate, + icon: const Icon( + Icons.date_range, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectDate(context, DateType.start, value)))), + const SizedBox(width: 16), + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.startTime, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).noStartTime, + icon: const Icon( + Icons.timer, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectTime(context, DateType.start, value)))) + ]), + ]), + )), + const SizedBox(height: 20), + Obx(() => AbsorbPointer( + absorbing: controller.isVacationDeactivated, + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + activeColor: AppColor.primaryColor.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0), + controlAffinity: ListTileControlAffinity.leading, + value: controller.vacationPresentation.value.vacationStopEnabled, + onChanged: (value) => + controller.updateVacationPresentation(vacationStopEnabled: value), + title: Text(AppLocalizations.of(context).vacationStopsAt, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0))), + ), + )), + Obx(() => AbsorbPointer( + absorbing: !controller.canChangeEndDate, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + AppLocalizations.of(context).endDate, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + !controller.canChangeEndDate ? 0.5 : 1.0))), + const SizedBox(height: 16), + Row(children: [ + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.endDate, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + !controller.canChangeEndDate ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).noEndDate, + icon: const Icon( + Icons.date_range, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectDate(context, DateType.end, value)))), + const SizedBox(width: 16), + Expanded(child: Obx(() => BorderButtonField( + value: controller.vacationPresentation.value.endTime, + mouseCursor: SystemMouseCursors.text, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + !controller.canChangeEndDate ? 0.5 : 1.0)), + hintText: AppLocalizations.of(context).noEndTime, + icon: const Icon( + Icons.timer, + color: AppColor.colorIconTextField, + size: 20), + tapActionCallback: (value) => + controller.selectTime(context, DateType.end, value)))) + ]), + ]) + )), + const SizedBox(height: 20), + Obx(() => AbsorbPointer( + absorbing: controller.isVacationDeactivated, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + AppLocalizations.of(context).messageBody, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity( + controller.isVacationDeactivated ? 0.5 : 1.0))), + const SizedBox(height: 16), + _buildMessageBodyWidget( + context, + controller.isVacationDeactivated ? 0.5 : 1.0) + ]), + )), + const SizedBox(height: 20), + Align( + alignment: Alignment.centerRight, + child: buildTextButton( + AppLocalizations.of(context).save, + width: 128, + height: 44, + radius: 10, + onTap: () => controller.saveVacation(context)), + ) + ] + ), + ), + ), + ), + ); + } + + Widget _buildMessageBodyWidget(BuildContext context, double opacity) { + return (TextFieldBuilder() + ..key(const Key('message_body_editor')) + ..cursorColor(Colors.black) + ..addController(controller.messageBodyEditorController) + ..textStyle(TextStyle( + fontWeight: FontWeight.normal, + color: Colors.black.withOpacity(opacity), + fontSize: 16)) + ..textDecoration((VacationInputDecorationBuilder() + ..setContentPadding(const EdgeInsets.symmetric( + vertical: BuildUtils.isWeb ? 16 : 12, + horizontal: 12)) + ..setHintStyle(TextStyle( + color: AppColor.colorHintInputCreateMailbox.withOpacity(opacity), + fontSize: 16)) + ..setHintText(AppLocalizations.of(context).hintMessageBodyVacation)) + .build()) + ..minLines(8) + ..maxLines(null)) + .build(); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/configuration/vacation/widgets/vacation_input_decoration_builder.dart b/lib/features/manage_account/presentation/configuration/vacation/widgets/vacation_input_decoration_builder.dart new file mode 100644 index 000000000..e6c30590e --- /dev/null +++ b/lib/features/manage_account/presentation/configuration/vacation/widgets/vacation_input_decoration_builder.dart @@ -0,0 +1,37 @@ + +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; + +class VacationInputDecorationBuilder extends InputDecorationBuilder { + + @override + InputDecoration build() { + return InputDecoration( + enabledBorder: enabledBorder ?? const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(width: 1, color: AppColor.colorInputBorderCreateMailbox)), + focusedBorder: enabledBorder ?? const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(width: 1, color: AppColor.colorTextButton)), + errorBorder: errorBorder ?? const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(width: 1, color: AppColor.colorInputBorderErrorVerifyName)), + focusedErrorBorder: errorBorder ?? const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(width: 1, color: AppColor.colorInputBorderErrorVerifyName)), + prefixText: prefixText, + labelText: labelText, + floatingLabelBehavior: FloatingLabelBehavior.never, + labelStyle: labelStyle ?? const TextStyle(color: Colors.black, fontSize: 16), + hintText: hintText, + isDense: true, + hintStyle: hintStyle ?? const TextStyle(color: AppColor.colorHintInputCreateMailbox, fontSize: 16), + contentPadding: contentPadding ?? const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + errorText: errorText, + errorStyle: errorTextStyle ?? const TextStyle(color: AppColor.colorInputBorderErrorVerifyName, fontSize: 13), + filled: true, + fillColor: errorText?.isNotEmpty == true + ? AppColor.colorInputBackgroundErrorVerifyName + : Colors.white); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/email_rules/email_rules_view.dart b/lib/features/manage_account/presentation/email_rules/email_rules_view.dart index f9bb4196d..a246ab374 100644 --- a/lib/features/manage_account/presentation/email_rules/email_rules_view.dart +++ b/lib/features/manage_account/presentation/email_rules/email_rules_view.dart @@ -44,9 +44,9 @@ class EmailRulesView extends GetWidget with AppLoaderMixin return const EdgeInsets.only(left: 16, top: 16, right: 24, bottom: 24); } else if (_responsiveUtils.isTabletLarge(context) || _responsiveUtils.isTablet(context)) { - return const EdgeInsets.only(right: 32, top: 16, bottom: 16); + return const EdgeInsets.only(right: 24, top: 16, bottom: 16); } else { - return const EdgeInsets.only(right: 32, top: 16, bottom: 16); + return const EdgeInsets.only(right: 24, top: 16, bottom: 16); } } else { if (_responsiveUtils.isDesktop(context) || @@ -55,7 +55,7 @@ class EmailRulesView extends GetWidget with AppLoaderMixin _responsiveUtils.isTablet(context)) { return const EdgeInsets.only(right: 32, top: 16, bottom: 16); } else { - return const EdgeInsets.only(top: 16, bottom: 16, right: 28, left: 20); + return const EdgeInsets.only(right: 18, top: 16, bottom: 16, left: 10); } } } diff --git a/lib/features/manage_account/presentation/extensions/datetime_extension.dart b/lib/features/manage_account/presentation/extensions/datetime_extension.dart new file mode 100644 index 000000000..9d6eb6a3c --- /dev/null +++ b/lib/features/manage_account/presentation/extensions/datetime_extension.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +extension DateTimeExtension on DateTime? { + + String formatDate({String pattern = 'yyyy/MM/dd', String locale = 'en_US'}) { + if (this != null) { + return DateFormat(pattern, locale).format(this!.toLocal()); + } else { + return ''; + } + } +} + +extension TimeOfDayExtension on TimeOfDay? { + + String formatTime(BuildContext context) { + if (this != null) { + return this!.format(context); + } + return ''; + } +} \ 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 a77195b69..2b7355424 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 @@ -21,7 +21,7 @@ class LanguageAndRegionView extends GetWidget { body: Container( width: double.infinity, margin: _responsiveUtils.isWebDesktop(context) - ? const EdgeInsets.only(left: 48, right: 24, top: 24, bottom: 24) + ? const EdgeInsets.all(24) : EdgeInsets.zero, color: _responsiveUtils.isWebDesktop(context) ? null : Colors.white, decoration: _responsiveUtils.isWebDesktop(context) @@ -37,7 +37,7 @@ class LanguageAndRegionView extends GetWidget { padding: EdgeInsets.only( left: _responsiveUtils.isWebDesktop(context) ? 24 : 10, top: 24, - right: 24), + right: BuildUtils.isWeb ? 24 : 18), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart index c38500ce5..ecf5f3244 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart @@ -26,6 +26,7 @@ import 'package:tmail_ui_user/features/manage_account/data/network/manage_accoun import 'package:tmail_ui_user/features/manage_account/data/repository/manage_account_repository_impl.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/configuration_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/manage_account_menu_bindings.dart'; @@ -39,6 +40,7 @@ class ManageAccountDashBoardBindings extends BaseBindings { ManageAccountMenuBindings().dependencies(); ProfileBindings().dependencies(); LanguageAndRegionBindings().dependencies(); + ConfigurationBindings().dependencies(); } @override diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart index 57d9f9220..c6ae709bd 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart @@ -23,15 +23,12 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class ManageAccountDashBoardController extends ReloadableController { - final _responsiveUtils = Get.find(); - final menuDrawerKey = GlobalKey(debugLabel: 'manage_account'); final appInformation = Rxn(); final userProfile = Rxn(); final accountId = Rxn(); final accountMenuItemSelected = AccountMenuItem.profiles.obs; - final sessionCurrent = Rxn(); ManageAccountDashBoardController( @@ -116,7 +113,7 @@ class ManageAccountDashBoardController extends ReloadableController { ForwardBindings().dependencies(); } accountMenuItemSelected.value = newAccountMenuItem; - if (currentContext != null && !_responsiveUtils.isDesktop(currentContext!)) { + if (isMenuDrawerOpen) { closeMenuDrawer(); } } diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_view.dart b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart index 4dea253e7..e56d06ec8 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_view.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/configuration/configuration_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/email_rules_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/forward/forward_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_view.dart'; @@ -160,6 +161,8 @@ class ManageAccountDashBoardView extends GetWidget([ AccountMenuItem.profiles, AccountMenuItem.languageAndRegion, + AccountMenuItem.vacation, ]); void _initWorker() { @@ -51,6 +52,9 @@ class ManageAccountMenuController extends BaseController { listAccountMenuItem.add( AccountMenuItem.languageAndRegion, ); + listAccountMenuItem.add( + AccountMenuItem.vacation, + ); } @override diff --git a/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart b/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart index 16b816e66..5797db41c 100644 --- a/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart +++ b/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart @@ -99,7 +99,7 @@ class ManageAccountMenuView extends GetWidget { child: InkWell( onTap: () => controller.dashBoardController.logoutAction(), child: Row(children: [ - SvgPicture.asset(_imagePaths.icLogout, fit: BoxFit.fill), + SvgPicture.asset(_imagePaths.icSignOut, fit: BoxFit.fill), const SizedBox(width: 12), Expanded(child: Text(AppLocalizations.of(context).sign_out, style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.black))) diff --git a/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart b/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart index 400ed74d1..96a184f9f 100644 --- a/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart +++ b/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart @@ -25,31 +25,26 @@ class AccountMenuItemTileBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - return InkWell( - onTap: () => onSelectAccountMenuItemAction?.call(_menuItem), - child: Theme( - data: ThemeData( - splashColor: Colors.transparent, - highlightColor: Colors.transparent), + return Padding( + padding: const EdgeInsets.only(top: 6), + child: InkWell( + onTap: () => onSelectAccountMenuItemAction?.call(_menuItem), child: Container( key: const Key('account_menu_item_tile'), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: backgroundColorItem), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - child: MediaQuery( - data: const MediaQueryData(padding: EdgeInsets.zero), - child: Column(children: [ - Row(children: [ - SvgPicture.asset(_menuItem.getIcon(_imagePaths), width: 28, height: 28, fit: BoxFit.fill), - const SizedBox(width: 12), - Expanded(child: Text(_menuItem.getName(context), - style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.black))) - ]), - ]) - ) - ) - )); + child: Column(children: [ + Row(children: [ + SvgPicture.asset(_menuItem.getIcon(_imagePaths)), + const SizedBox(width: 12), + Expanded(child: Text(_menuItem.getName(context), + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.black))) + ]), + ]) + )), + ); } Color get backgroundColorItem { diff --git a/lib/features/manage_account/presentation/model/account_menu_item.dart b/lib/features/manage_account/presentation/model/account_menu_item.dart index 507e9187d..acd62177b 100644 --- a/lib/features/manage_account/presentation/model/account_menu_item.dart +++ b/lib/features/manage_account/presentation/model/account_menu_item.dart @@ -8,9 +8,7 @@ enum AccountMenuItem { languageAndRegion, emailRules, forward, -} - -extension AccountMenuItemExtension on AccountMenuItem { + vacation; String getIcon(ImagePaths imagePaths) { switch(this) { @@ -22,6 +20,8 @@ extension AccountMenuItemExtension on AccountMenuItem { return imagePaths.icEmailRules; case AccountMenuItem.forward: return imagePaths.icForward; + case AccountMenuItem.configuration: + return imagePaths.icConfiguration; } } @@ -35,6 +35,8 @@ extension AccountMenuItemExtension on AccountMenuItem { return AppLocalizations.of(context).emailRules; case AccountMenuItem.forward: return AppLocalizations.of(context).forwarding; + case AccountMenuItem.configuration: + return AppLocalizations.of(context).configuration; } } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/configuration_tab_type.dart b/lib/features/manage_account/presentation/model/configuration_tab_type.dart new file mode 100644 index 000000000..0c1807081 --- /dev/null +++ b/lib/features/manage_account/presentation/model/configuration_tab_type.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +enum ConfigurationTabType { + vacation; + + String getTitle(BuildContext context) { + switch(this) { + case ConfigurationTabType.vacation: + return AppLocalizations.of(context).vacation; + } + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/vacation/date_type.dart b/lib/features/manage_account/presentation/model/vacation/date_type.dart new file mode 100644 index 000000000..f259d067f --- /dev/null +++ b/lib/features/manage_account/presentation/model/vacation/date_type.dart @@ -0,0 +1,17 @@ + +import 'package:flutter/widgets.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +enum DateType { + start, + end; + + String getTitle(BuildContext context) { + switch(this) { + case DateType.start: + return AppLocalizations.of(context).startDate; + case DateType.end: + return AppLocalizations.of(context).endDate; + } + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/vacation/vacation_presentation.dart b/lib/features/manage_account/presentation/model/vacation/vacation_presentation.dart new file mode 100644 index 000000000..5911e2dc3 --- /dev/null +++ b/lib/features/manage_account/presentation/model/vacation/vacation_presentation.dart @@ -0,0 +1,47 @@ + +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/vacation/vacation_responder_status.dart'; + +class VacationPresentation { + final VacationResponderStatus status; + final DateTime? startDate; + final TimeOfDay? startTime; + final DateTime? endDate; + final TimeOfDay? endTime; + final String? messageBody; + final bool vacationStopEnabled; + + VacationPresentation({ + this.status = VacationResponderStatus.deactivated, + this.startDate, + this.startTime, + this.endDate, + this.endTime, + this.messageBody, + this.vacationStopEnabled = false, + }); + + factory VacationPresentation.initialize() { + return VacationPresentation(); + } + + VacationPresentation copyWidth({ + VacationResponderStatus? status, + DateTime? startDate, + TimeOfDay? startTime, + DateTime? endDate, + TimeOfDay? endTime, + String? messageBody, + bool? vacationStopEnabled, + }) { + return VacationPresentation( + status: status ?? this.status, + startDate: startDate ?? this.startDate, + startTime: startTime ?? this.startTime, + endDate: endDate ?? this.endDate, + endTime: endTime ?? this.endTime, + messageBody: messageBody ?? this.messageBody, + vacationStopEnabled: vacationStopEnabled ?? this.vacationStopEnabled + ); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/vacation/vacation_responder_status.dart b/lib/features/manage_account/presentation/model/vacation/vacation_responder_status.dart new file mode 100644 index 000000000..c42e03a65 --- /dev/null +++ b/lib/features/manage_account/presentation/model/vacation/vacation_responder_status.dart @@ -0,0 +1,17 @@ + +import 'package:flutter/widgets.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +enum VacationResponderStatus { + activated, + deactivated; + + String getTitle(BuildContext context) { + switch(this) { + case VacationResponderStatus.activated: + return AppLocalizations.of(context).activated; + case VacationResponderStatus.deactivated: + return AppLocalizations.of(context).deactivated; + } + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/profiles/identities/identities_view.dart b/lib/features/manage_account/presentation/profiles/identities/identities_view.dart index d3fb497b3..bb8ebec33 100644 --- a/lib/features/manage_account/presentation/profiles/identities/identities_view.dart +++ b/lib/features/manage_account/presentation/profiles/identities/identities_view.dart @@ -51,7 +51,10 @@ class IdentitiesView extends GetWidget with PopupMenuWidge responsiveUtils: _responsiveUtils, mobile: Scaffold( body: Container( - margin: const EdgeInsets.only(top: 16, bottom: 16, right: 24), + margin: const EdgeInsets.only( + top: 16, + bottom: 16, + right: BuildUtils.isWeb ? 24 : 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/features/manage_account/presentation/profiles/profiles_bindings.dart b/lib/features/manage_account/presentation/profiles/profiles_bindings.dart index 6bfdb5ae1..95d4381c7 100644 --- a/lib/features/manage_account/presentation/profiles/profiles_bindings.dart +++ b/lib/features/manage_account/presentation/profiles/profiles_bindings.dart @@ -1,6 +1,5 @@ import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/email_rules_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/profiles/profiles_controller.dart'; diff --git a/lib/features/manage_account/presentation/profiles/profiles_view.dart b/lib/features/manage_account/presentation/profiles/profiles_view.dart index 344fcc588..0449b2d98 100644 --- a/lib/features/manage_account/presentation/profiles/profiles_view.dart +++ b/lib/features/manage_account/presentation/profiles/profiles_view.dart @@ -20,7 +20,7 @@ class ProfilesView extends GetWidget { : Colors.white, body: Container( margin: _responsiveUtils.isWebDesktop(context) - ? const EdgeInsets.only(left: 48, right: 24, top: 24, bottom: 24) + ? const EdgeInsets.all(24) : EdgeInsets.zero, color: _responsiveUtils.isWebDesktop(context) ? null : Colors.white, decoration: _responsiveUtils.isWebDesktop(context) diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 62eb18ff5..7b009576d 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-08-18T10:12:35.405050", + "@@last_modified": "2022-08-17T17:27:40.386002", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1903,5 +1903,83 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "vacation": "Vacation", + "@vacation": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "configuration": "Configuration", + "@configuration": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "vacationResponder": "Vacation responder", + "@vacationResponder": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "activated": "Activated", + "@activated": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "deactivated": "Deactivated", + "@deactivated": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "startDate": "Start date", + "@startDate": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "endDate": "End date", + "@endDate": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "vacationStopsAt": "Vacation stops at", + "@vacationStopsAt": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "messageBody": "Message body", + "@messageBody": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "hintMessageBodyVacation": "Start writing your vacation message here", + "@hintMessageBodyVacation": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "noStartTime": "No start time", + "@noStartTime": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "noEndTime": "No end time", + "@noEndTime": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "noEndDate": "No end date", + "@noEndDate": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index c9f3d9551..65b15c9c0 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1959,4 +1959,95 @@ class AppLocalizations { name: 'forwarding', ); } + + String get vacation { + return Intl.message( + 'Vacation', + name: 'vacation', + ); + } + + String get configuration { + return Intl.message( + 'Configuration', + name: 'configuration', + ); + } + + String get vacationResponder { + return Intl.message( + 'Vacation responder', + name: 'vacationResponder', + ); + } + + String get activated { + return Intl.message( + 'Activated', + name: 'activated', + ); + } + + String get deactivated { + return Intl.message( + 'Deactivated', + name: 'deactivated', + ); + } + + String get startDate { + return Intl.message( + 'Start date', + name: 'startDate', + ); + } + + String get endDate { + return Intl.message( + 'End date', + name: 'endDate', + ); + } + + String get vacationStopsAt { + return Intl.message( + 'Vacation stops at', + name: 'vacationStopsAt', + ); + } + + String get messageBody { + return Intl.message( + 'Message body', + name: 'messageBody', + ); + } + + String get hintMessageBodyVacation { + return Intl.message( + 'Start writing your vacation message here', + name: 'hintMessageBodyVacation', + ); + } + + String get noStartTime { + return Intl.message( + 'No start time', + name: 'noStartTime', + ); + } + + String get noEndTime { + return Intl.message( + 'No end time', + name: 'noEndTime', + ); + } + + String get noEndDate { + return Intl.message( + 'No end date', + name: 'noEndDate', + ); + } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 375d57299..703689ece 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -187,6 +187,8 @@ dependencies: byte_converter: 1.3.0 + toggle_switch: 2.0.1 + dev_dependencies: flutter_test: sdk: flutter