diff --git a/assets/images/ic_edit.svg b/assets/images/ic_edit.svg new file mode 100644 index 000000000..c377533c3 --- /dev/null +++ b/assets/images/ic_edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 040e18258..875527c74 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -103,6 +103,7 @@ class ImagePaths { String get icEditIdentity => _getImagePath('ic_edit_identity.svg'); String get icDeleteDialogIdentity => _getImagePath('ic_delete_dialog_identity.svg'); String get icDeleteDialogFailed => _getImagePath('ic_delete_dialog_failed.svg'); + String get icEdit => _getImagePath('ic_edit.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/identity_creator/presentation/identity_creator_controller.dart b/lib/features/identity_creator/presentation/identity_creator_controller.dart index e4c32d1dc..506f88575 100644 --- a/lib/features/identity_creator/presentation/identity_creator_controller.dart +++ b/lib/features/identity_creator/presentation/identity_creator_controller.dart @@ -14,6 +14,7 @@ import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification import 'package:tmail_ui_user/features/mailbox_creator/domain/state/verify_name_view_state.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/extensions/validator_failure_extension.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/identity_action_type.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class IdentityCreatorController extends BaseController { @@ -36,6 +37,8 @@ class IdentityCreatorController extends BaseController { AccountId? accountId; UserProfile? userProfile; + IdentityActionType? actionType; + Identity? identity; String? _nameIdentity; String? _contentHtmlEditor; @@ -53,7 +56,11 @@ class IdentityCreatorController extends BaseController { @override void onReady() { _getArguments(); - _setDefaultValueForIdentity(); + if (actionType == IdentityActionType.edit && identity != null) { + _setUpValueFromIdentity(); + } else { + _setDefaultValueForIdentity(); + } super.onReady(); } @@ -77,6 +84,8 @@ class IdentityCreatorController extends BaseController { if (arguments is IdentityCreatorArguments) { accountId = arguments.accountId; userProfile = arguments.userProfile; + actionType = arguments.actionType; + identity = arguments.identity; } } @@ -86,13 +95,54 @@ class IdentityCreatorController extends BaseController { replyToOfIdentity.value = noneEmailAddress; if (userProfile != null && userProfile?.email.isNotEmpty == true) { - final userEmailAddress = EmailAddress(userProfile!.email, userProfile!.email); + final userEmailAddress = EmailAddress(null, userProfile!.email); listEmailAddressDefault.add(userEmailAddress); listEmailAddressOfReplyTo.add(userEmailAddress); emailOfIdentity.value = userEmailAddress; } } + void _setUpValueFromIdentity() { + Set listEmailAddress = {}; + listEmailAddress.add(noneEmailAddress); + + _nameIdentity = identity?.name ?? ''; + inputNameIdentityController.text = identity?.name ?? ''; + + if (identity?.replyTo?.isNotEmpty == true) { + replyToOfIdentity.value = identity!.replyTo!.first; + listEmailAddress.add(identity!.replyTo!.first); + } else { + replyToOfIdentity.value = noneEmailAddress; + } + + if (identity?.bcc?.isNotEmpty == true) { + bccOfIdentity.value = identity!.bcc!.first; + listEmailAddress.add(identity!.bcc!.first); + } else { + bccOfIdentity.value = noneEmailAddress; + } + + if (identity?.email?.isNotEmpty == true) { + emailOfIdentity.value = EmailAddress(null, identity?.email!); + listEmailAddress.add(EmailAddress(null, identity?.email!)); + } + + listEmailAddressOfReplyTo.value = listEmailAddress.toList(); + listEmailAddressDefault.value = listEmailAddress + .where((emailAddress) => emailAddress != noneEmailAddress) + .toList(); + + if (identity?.textSignature?.value.isNotEmpty == true) { + signaturePlainEditorController.text = identity?.textSignature?.value ?? ''; + } + + if (identity?.htmlSignature?.value.isNotEmpty == true) { + updateContentHtmlEditor(identity?.htmlSignature?.value ?? ''); + signatureHtmlEditorController.setText(identity?.htmlSignature?.value ?? ''); + } + } + void selectSignatureType(SignatureType newSignatureType) { signatureType.value = newSignatureType; } diff --git a/lib/features/identity_creator/presentation/identity_creator_view.dart b/lib/features/identity_creator/presentation/identity_creator_view.dart index 3de9c54cb..6c50b1241 100644 --- a/lib/features/identity_creator/presentation/identity_creator_view.dart +++ b/lib/features/identity_creator/presentation/identity_creator_view.dart @@ -7,6 +7,7 @@ import 'package:tmail_ui_user/features/identity_creator/presentation/identity_cr import 'package:tmail_ui_user/features/identity_creator/presentation/model/signature_type.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/widgets/identity_drop_list_field_builder.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/widgets/identity_input_field_builder.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/identity_action_type.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class IdentityCreatorView extends GetWidget { @@ -24,9 +25,16 @@ class IdentityCreatorView extends GetWidget { backgroundColor: Colors.white, body: SafeArea( child: ClipRRect( - borderRadius: _responsiveUtils.isMobile(context) && _responsiveUtils.isPortrait(context) - ? const BorderRadius.only(topRight: Radius.circular(14), topLeft: Radius.circular(14)) - : const BorderRadius.all(Radius.zero), + borderRadius: const BorderRadius.only(topRight: Radius.circular(14), topLeft: Radius.circular(14)), + child: _buildBodyMobile(context) + ), + ) + ), + landscapeMobile: Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.zero), child: _buildBodyMobile(context) ), ) @@ -418,29 +426,34 @@ class IdentityCreatorView extends GetWidget { )), const SizedBox(height: 24), Container( - alignment: Alignment.centerRight, + alignment: Alignment.center, color: Colors.white, child: Row( - mainAxisSize: MainAxisSize.min, children: [ - buildTextButton( - AppLocalizations.of(context).cancel, - textStyle: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 17, - color: AppColor.colorTextButton), - backgroundColor: AppColor.emailAddressChipColor, - width: 128, - height: 44, - radius: 10, - onTap: () => controller.closeView(context)), + Expanded( + child: buildTextButton( + AppLocalizations.of(context).cancel, + textStyle: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 17, + color: AppColor.colorTextButton), + backgroundColor: AppColor.emailAddressChipColor, + width: 128, + height: 44, + radius: 10, + onTap: () => controller.closeView(context)), + ), const SizedBox(width: 12), - buildTextButton( - AppLocalizations.of(context).create, - width: 128, - height: 44, - radius: 10, - onTap: () => controller.createNewIdentity(context)), + Expanded( + child: Obx(() => buildTextButton( + controller.actionType == IdentityActionType.create + ? AppLocalizations.of(context).create + : AppLocalizations.of(context).save, + width: 128, + height: 44, + radius: 10, + onTap: () => controller.createNewIdentity(context))), + ), ] ), ) diff --git a/lib/features/identity_creator/presentation/model/identity_creator_arguments.dart b/lib/features/identity_creator/presentation/model/identity_creator_arguments.dart index 177ddef4a..120b7fcfa 100644 --- a/lib/features/identity_creator/presentation/model/identity_creator_arguments.dart +++ b/lib/features/identity_creator/presentation/model/identity_creator_arguments.dart @@ -1,14 +1,25 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/identity_action_type.dart'; class IdentityCreatorArguments with EquatableMixin { final AccountId accountId; final UserProfile userProfile; + final IdentityActionType actionType; + final Identity? identity; - IdentityCreatorArguments(this.accountId, this.userProfile); + IdentityCreatorArguments( + this.accountId, + this.userProfile, + { + this.identity, + this.actionType = IdentityActionType.create + } + ); @override - List get props => [accountId, userProfile]; + List get props => [accountId, userProfile, identity, actionType]; } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/identity_action_type.dart b/lib/features/manage_account/presentation/model/identity_action_type.dart new file mode 100644 index 000000000..fcf4bce9a --- /dev/null +++ b/lib/features/manage_account/presentation/model/identity_action_type.dart @@ -0,0 +1,5 @@ + +enum IdentityActionType { + create, + edit +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/profiles/identities/identities_bindings.dart b/lib/features/manage_account/presentation/profiles/identities/identities_bindings.dart index 41c6cd728..7afc1ff09 100644 --- a/lib/features/manage_account/presentation/profiles/identities/identities_bindings.dart +++ b/lib/features/manage_account/presentation/profiles/identities/identities_bindings.dart @@ -8,6 +8,7 @@ import 'package:tmail_ui_user/features/manage_account/data/repository/manage_acc import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_identity_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_identity_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_identity_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart'; import 'package:uuid/uuid.dart'; @@ -28,6 +29,7 @@ class IdentitiesBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); } @@ -46,6 +48,7 @@ class IdentitiesBindings extends BaseBindings { Get.lazyPut(() => GetAllIdentitiesInteractor(Get.find())); Get.lazyPut(() => CreateNewIdentityInteractor(Get.find())); Get.lazyPut(() => DeleteIdentityInteractor(Get.find())); + Get.lazyPut(() => EditIdentityInteractor(Get.find())); } @override diff --git a/lib/features/manage_account/presentation/profiles/identities/identities_controller.dart b/lib/features/manage_account/presentation/profiles/identities/identities_controller.dart index 30fe64e6a..8132c5db5 100644 --- a/lib/features/manage_account/presentation/profiles/identities/identities_controller.dart +++ b/lib/features/manage_account/presentation/profiles/identities/identities_controller.dart @@ -10,13 +10,17 @@ import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/model/identity_creator_arguments.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_identity_request.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/model/edit_identity_request.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/create_new_identity_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/delete_identity_state.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/state/edit_identity_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_identity_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_identity_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_identity_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_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/identity_action_type.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -33,6 +37,7 @@ class IdentitiesController extends BaseController { final CreateNewIdentityInteractor _createNewIdentityInteractor; final Uuid _uuid; final DeleteIdentityInteractor _deleteIdentityInteractor; + final EditIdentityInteractor _editIdentityInteractor; final identitySelected = Rxn(); final listAllIdentities = [].obs; @@ -45,6 +50,7 @@ class IdentitiesController extends BaseController { this._deleteIdentityInteractor, this._createNewIdentityInteractor, this._uuid, + this._editIdentityInteractor, ); @override @@ -74,6 +80,8 @@ class IdentitiesController extends BaseController { _createNewIdentitySuccess(success); } else if (success is DeleteIdentitySuccess) { _deleteIdentitySuccess(success); + } else if (success is EditIdentitySuccess) { + _editIdentitySuccess(success); } } ); @@ -262,4 +270,38 @@ class IdentitiesController extends BaseController { .build()); } } + + void goToEditIdentity(Identity identity) async { + popBack(); + + final accountId = _accountDashBoardController.accountId.value; + final userProfile = _accountDashBoardController.userProfile.value; + if (accountId != null && userProfile != null) { + final newIdentity = await push( + AppRoutes.IDENTITY_CREATOR, + arguments: IdentityCreatorArguments( + accountId, + userProfile, + identity: identity, + actionType: IdentityActionType.edit)); + + log('IdentitiesController::goToEditIdentity(): $newIdentity'); + _editIdentityAction(accountId, newIdentity); + } + } + + void _editIdentityAction(AccountId accountId, EditIdentityRequest identityRequest) async { + consumeState(_editIdentityInteractor.execute(accountId, identityRequest)); + } + + void _editIdentitySuccess(EditIdentitySuccess success) { + if (currentOverlayContext != null && currentContext != null) { + _appToast.showToastWithIcon( + currentOverlayContext!, + message: AppLocalizations.of(currentContext!).you_are_changed_your_identity_successfully, + icon: _imagePaths.icSelected); + } + + _refreshAllIdentities(); + } } \ 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 6a070f044..4c2d9eef1 100644 --- a/lib/features/manage_account/presentation/profiles/identities/identities_view.dart +++ b/lib/features/manage_account/presentation/profiles/identities/identities_view.dart @@ -170,6 +170,15 @@ class IdentitiesView extends GetWidget with PopupMenuWidge List _popupMenuIdentityActionTiles(BuildContext context, Identity identity) { return [ + PopupMenuItem( + padding: EdgeInsets.zero, + child: popupItem(_imagePaths.icEdit, + AppLocalizations.of(context).edit_identity, + styleName: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 17, + color: Colors.black), + onCallbackAction: () => controller.goToEditIdentity(identity))), if (identity.mayDelete == true) PopupMenuItem( padding: EdgeInsets.zero, @@ -186,6 +195,7 @@ class IdentitiesView extends GetWidget with PopupMenuWidge List _bottomSheetIdentityActionTiles(BuildContext context, Identity identity) { return [ + _editIdentityActionTile(context, identity), if (identity.mayDelete == true) _deleteIdentityActionTile(context, identity), ]; @@ -207,4 +217,20 @@ class IdentitiesView extends GetWidget with PopupMenuWidge ..onActionClick((identity) => controller.openConfirmationDialogDeleteIdentityAction(context, identity))) .build(); } + + Widget _editIdentityActionTile(BuildContext context, Identity identity) { + return (IdentityBottomSheetActionTileBuilder( + const Key('edit_identity_action'), + SvgPicture.asset(_imagePaths.icEdit), + AppLocalizations.of(context).edit_identity, + identity, + iconLeftPadding: _responsiveUtils.isMobile(context) + ? const EdgeInsets.only(left: 12, right: 16) + : const EdgeInsets.only(right: 12), + iconRightPadding: _responsiveUtils.isMobile(context) + ? const EdgeInsets.only(right: 12) + : EdgeInsets.zero) + ..onActionClick((identity) => controller.goToEditIdentity(identity))) + .build(); + } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart b/lib/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart index fb5b9bcc5..ce0f871a3 100644 --- a/lib/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart +++ b/lib/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart @@ -42,22 +42,28 @@ class IdentityInfoTileBuilder extends StatelessWidget { padding: const EdgeInsets.only(left: 12, right: 8), child: Row(children: [ if (_identity?.mayDelete == false) - Expanded(child: Row(children: [ - Text(_identity?.name ?? '', - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 17, - color: Colors.black)), - const SizedBox(width: 10), - Expanded(child: Text( - '(${AppLocalizations.of(context).default_value})', - style: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 15, - color: AppColor.colorHintSearchBar))) + Expanded(child: Wrap(children: [ + Padding( + padding: const EdgeInsets.only(right: 10), + child: Text(_identity?.name ?? '', + maxLines: 1, + overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 17, + color: Colors.black))), + Text('(${AppLocalizations.of(context).default_value})', + maxLines: 1, + overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 15, + color: AppColor.colorHintSearchBar)) ])) else Expanded(child: Text(_identity?.name ?? '', + maxLines: 1, + overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis, style: const TextStyle( fontWeight: FontWeight.w500, fontSize: 17, diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 41dcc74c9..60e2a5aae 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-05-05T09:06:54.039059", + "@@last_modified": "2022-05-06T15:08:19.074758", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1174,6 +1174,18 @@ "placeholders_order": [], "placeholders": {} }, + "all_identities": "All identities", + "@all_identities": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "default_value": "Default", + "@default_value": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, "delete_identity": "Delete identity", "@delete_identity": { "type": "text", @@ -1197,5 +1209,23 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "edit_identity": "Edit identity", + "@edit_identity": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "you_are_changed_your_identity_successfully": "You’ve changed your identity successfully", + "@you_are_changed_your_identity_successfully": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "save": "Save", + "@save": { + "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 bcbc99991..fdade5b61 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1259,4 +1259,20 @@ class AppLocalizations { return Intl.message('Delete Failed', name: 'delete_failed'); } + + String get edit_identity { + return Intl.message('Edit identity', + name: 'edit_identity'); + } + + String get you_are_changed_your_identity_successfully { + return Intl.message('You’ve changed your identity successfully', + name: 'you_are_changed_your_identity_successfully'); + } + + String get save { + return Intl.message( + 'Save', + name: 'save'); + } } \ No newline at end of file