TF-537 Add presentation layer for delete a identity

This commit is contained in:
dab246
2022-05-05 15:08:14 +07:00
committed by Dat H. Pham
parent c40be824ff
commit 087a037de5
12 changed files with 342 additions and 35 deletions
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
mixin PopupMenuWidgetMixin {
Widget popupItem(String iconAction, String nameAction, {
Color? colorIcon,
TextStyle? styleName,
Function? onCallbackAction
}) {
return InkWell(
onTap: () => onCallbackAction?.call(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: SizedBox(
child: Row(children: [
SvgPicture.asset(iconAction, width: 20, height: 20, fit: BoxFit.fill, color: colorIcon),
const SizedBox(width: 12),
Expanded(child: Text(nameAction,
style: styleName ?? const TextStyle(
fontSize: 17,
fontWeight: FontWeight.normal,
color: Colors.black))),
])
),
)
);
}
}
@@ -6,6 +6,7 @@ import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/manag
import 'package:tmail_ui_user/features/manage_account/data/network/manage_account_api.dart';
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/delete_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';
@@ -19,7 +20,10 @@ class IdentitiesBindings extends BaseBindings {
@override
void bindingsController() {
Get.lazyPut(() => IdentitiesController(Get.find<GetAllIdentitiesInteractor>()));
Get.lazyPut(() => IdentitiesController(
Get.find<GetAllIdentitiesInteractor>(),
Get.find<DeleteIdentityInteractor>(),
));
}
@override
@@ -35,6 +39,7 @@ class IdentitiesBindings extends BaseBindings {
@override
void bindingsInteractor() {
Get.lazyPut(() => GetAllIdentitiesInteractor(Get.find<ManageAccountRepository>()));
Get.lazyPut(() => DeleteIdentityInteractor(Get.find<ManageAccountRepository>()));
}
@override
@@ -1,23 +1,36 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
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/manage_account/domain/state/delete_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/delete_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/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class IdentitiesController extends BaseController {
final _accountDashBoardController = Get.find<ManageAccountDashBoardController>();
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
final _appToast = Get.find<AppToast>();
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
final DeleteIdentityInteractor _deleteIdentityInteractor;
final identitySelected = Rxn<Identity>();
final listIdentities = <Identity>[].obs;
IdentitiesController(this._getAllIdentitiesInteractor);
IdentitiesController(
this._getAllIdentitiesInteractor,
this._deleteIdentityInteractor,
);
@override
void onInit() {
@@ -28,13 +41,19 @@ class IdentitiesController extends BaseController {
@override
void onDone() {
viewState.value.fold(
(failure) {},
(failure) {
if (failure is DeleteIdentityFailure) {
_deleteIdentityFailure(failure);
}
},
(success) {
if (success is GetAllIdentitiesSuccess) {
if (success.identities?.isNotEmpty == true) {
listIdentities.value = success.identities ?? [];
setIdentityDefault();
}
} else if (success is DeleteIdentitySuccess) {
_deleteIdentitySuccess(success);
}
}
);
@@ -69,4 +88,99 @@ class IdentitiesController extends BaseController {
void selectIdentity(Identity? newIdentity) {
identitySelected.value = newIdentity;
}
void openConfirmationDialogDeleteIdentityAction(BuildContext context, Identity identity) {
popBack();
if (_responsiveUtils.isScreenWithShortestSide(context)) {
(ConfirmationDialogActionSheetBuilder(context)
..messageText(AppLocalizations.of(context).message_confirmation_dialog_delete_identity)
..onCancelAction(AppLocalizations.of(context).cancel, () =>
popBack())
..onConfirmAction(AppLocalizations.of(context).delete, () =>
_deleteIdentityAction(identity)))
.show();
} else {
showDialog(
context: context,
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
builder: (BuildContext context) => (ConfirmDialogBuilder(_imagePaths)
..key(const Key('confirm_dialog_delete_identity'))
..title(AppLocalizations.of(context).delete_identity.capitalizeFirstEach)
..content(AppLocalizations.of(context).message_confirmation_dialog_delete_identity)
..addIcon(SvgPicture.asset(_imagePaths.icDeleteDialogIdentity, fit: BoxFit.fill))
..marginIcon(EdgeInsets.zero)
..styleTitle(const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: AppColor.colorActionDeleteConfirmDialog))
..styleContent(const TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: AppColor.colorContentEmail))
..colorCancelButton(AppColor.colorButtonCancelDialog)
..colorConfirmButton(AppColor.colorActionDeleteConfirmDialog)
..styleTextConfirmButton(const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: Colors.white))
..styleTextCancelButton(const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: AppColor.colorTextButton))
..onCloseButtonAction(() => popBack())
..onConfirmButtonAction(AppLocalizations.of(context).delete, () =>
_deleteIdentityAction(identity))
..onCancelButtonAction(AppLocalizations.of(context).cancel, () =>
popBack()))
.build());
}
}
void _deleteIdentityAction(Identity identity) {
popBack();
final accountId = _accountDashBoardController.accountId.value;
if (accountId != null && identity.id != null) {
consumeState(_deleteIdentityInteractor.execute(accountId, identity.id!));
}
}
void _deleteIdentitySuccess(DeleteIdentitySuccess success) {
if (currentOverlayContext != null && currentContext != null) {
_appToast.showToastWithIcon(
currentOverlayContext!,
message: AppLocalizations.of(currentContext!).identity_has_been_deleted,
icon: _imagePaths.icDeleteToast);
}
final accountId = _accountDashBoardController.accountId.value;
if (accountId != null) {
_getAllIdentities(accountId);
}
}
void _deleteIdentityFailure(DeleteIdentityFailure failure) {
if (currentContext != null) {
showDialog(
context: currentContext!,
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
builder: (BuildContext context) => (ConfirmDialogBuilder(_imagePaths)
..key(const Key('dialog_message_delete_identity_failed'))
..title(AppLocalizations.of(context).delete_failed)
..addIcon(SvgPicture.asset(_imagePaths.icDeleteDialogFailed, fit: BoxFit.fill))
..marginIcon(EdgeInsets.zero)
..styleTitle(const TextStyle(fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black))
..colorConfirmButton(AppColor.colorTextButton)
..paddingTitle(const EdgeInsets.symmetric(vertical: 12))
..styleTextConfirmButton(const TextStyle(fontSize: 17,
fontWeight: FontWeight.w500,
color: Colors.white))
..onCloseButtonAction(() => popBack())
..onConfirmButtonAction('${AppLocalizations.of(context).got_it}!', () => popBack()))
.build());
}
}
}
@@ -5,11 +5,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:tmail_ui_user/features/base/mixin/popup_menu_widget_mixin.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/identity_bottom_sheet_action_tile_builder.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class IdentitiesView extends GetWidget<IdentitiesController> {
class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidgetMixin {
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
@@ -87,9 +89,10 @@ class IdentitiesView extends GetWidget<IdentitiesController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buttonSelectIdentity,
Obx(() => IdentityInfoTileBuilder(context,
_imagePaths,
controller.identitySelected.value)),
Obx(() => IdentityInfoTileBuilder(_imagePaths, _responsiveUtils,
controller.identitySelected.value,
onMenuItemIdentityAction: (identity, position) =>
_openIdentityMenuAction(context, identity, position))),
]
))
),
@@ -108,13 +111,63 @@ class IdentitiesView extends GetWidget<IdentitiesController> {
SizedBox(
width: constraints.maxWidth / 2,
child: buttonSelectIdentity),
Obx(() => IdentityInfoTileBuilder(context,
_imagePaths,
Obx(() => IdentityInfoTileBuilder(_imagePaths, _responsiveUtils,
controller.identitySelected.value,
maxWidth: constraints.maxWidth / 2)),
maxWidth: constraints.maxWidth / 2,
onMenuItemIdentityAction: (identity, position) =>
_openIdentityMenuAction(context, identity, position))),
]
))
)
));
}
void _openIdentityMenuAction(BuildContext context, Identity identity,
RelativeRect? position) {
if (_responsiveUtils.isScreenWithShortestSide(context)) {
controller.openContextMenuAction(context, _bottomSheetIdentityActionTiles(context, identity));
} else {
controller.openPopupMenuAction(context, position, _popupMenuIdentityActionTiles(context, identity));
}
}
List<PopupMenuEntry> _popupMenuIdentityActionTiles(BuildContext context, Identity identity) {
return [
if (identity.mayDelete == true)
PopupMenuItem(
padding: EdgeInsets.zero,
child: popupItem(_imagePaths.icDeleteComposer,
AppLocalizations.of(context).delete_identity,
colorIcon: AppColor.colorActionDeleteConfirmDialog,
styleName: const TextStyle(
fontWeight: FontWeight.normal,
fontSize: 17,
color: AppColor.colorActionDeleteConfirmDialog),
onCallbackAction: () => controller.openConfirmationDialogDeleteIdentityAction(context, identity))),
];
}
List<Widget> _bottomSheetIdentityActionTiles(BuildContext context, Identity identity) {
return <Widget>[
if (identity.mayDelete == true)
_deleteIdentityActionTile(context, identity),
];
}
Widget _deleteIdentityActionTile(BuildContext context, Identity identity) {
return (IdentityBottomSheetActionTileBuilder(
const Key('delete_identity_action'),
SvgPicture.asset(_imagePaths.icDeleteComposer,
color: AppColor.colorActionDeleteConfirmDialog),
AppLocalizations.of(context).delete_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.openConfirmationDialogDeleteIdentityAction(context, identity)))
.build();
}
}
@@ -0,0 +1,49 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
class IdentityBottomSheetActionTileBuilder extends CupertinoActionSheetActionBuilder<Identity> {
final Identity identity;
final SvgPicture? actionSelected;
final Color? bgColor;
final EdgeInsets? iconLeftPadding;
final EdgeInsets? iconRightPadding;
IdentityBottomSheetActionTileBuilder(
Key key,
SvgPicture actionIcon,
String actionName,
this.identity,
{
this.actionSelected,
this.bgColor,
this.iconLeftPadding,
this.iconRightPadding,
}
) : super(key, actionIcon, actionName);
@override
Widget build() {
return Container(
color: bgColor ?? Colors.white,
child: CupertinoActionSheetAction(
key: key,
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Padding(
padding: iconLeftPadding ?? const EdgeInsets.only(left: 12, right: 16),
child: actionIcon),
Expanded(child: Text(actionName, textAlign: TextAlign.left, style: actionTextStyle())),
]),
onPressed: () {
if (onCupertinoActionSheetActionClick != null) {
onCupertinoActionSheetActionClick!(identity);
}
},
),
);
}
}
@@ -5,18 +5,25 @@ import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnMenuItemIdentityAction = Function(Identity identity, RelativeRect? positon);
class IdentityInfoTileBuilder extends StatelessWidget {
final BuildContext _context;
final ImagePaths _imagePaths;
final ResponsiveUtils _responsiveUtils;
final Identity? _identity;
final double? maxWidth;
final OnMenuItemIdentityAction? onMenuItemIdentityAction;
const IdentityInfoTileBuilder(
this._context,
this._imagePaths,
this._responsiveUtils,
this._identity,
{Key? key, this.maxWidth}
{
Key? key,
this.maxWidth,
this.onMenuItemIdentityAction,
}
) : super(key: key);
@override
@@ -40,9 +47,19 @@ class IdentityInfoTileBuilder extends StatelessWidget {
child: Row(children: [
Expanded(child: Text(_identity?.name ?? '',
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 17, color: Colors.black))),
buildIconWeb(
buildIconWebHasPosition(
context,
icon: SvgPicture.asset(_imagePaths.icMoreVertical, fit: BoxFit.fill),
onTap: () => {})
onTap: () {
if (_responsiveUtils.isScreenWithShortestSide(context)) {
onMenuItemIdentityAction?.call(_identity!, null);
}
},
onTapDown: (position) {
if (!_responsiveUtils.isScreenWithShortestSide(context)) {
onMenuItemIdentityAction?.call(_identity!, position);
}
})
])),
const SizedBox(height: 10),
const Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2),
@@ -75,24 +92,6 @@ class IdentityInfoTileBuilder extends StatelessWidget {
Expanded(child: Text(_identity?.replyTo?.listEmailAddressToString(isFullEmailAddress: true) ?? '',
style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: AppColor.colorHintSearchBar)))
])),
if (_identity?.cc != null && _identity?.cc?.isNotEmpty == true) const SizedBox(height: 6),
if (_identity?.cc != null && _identity?.cc?.isNotEmpty == true)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(children: [
Container(
width: 40,
padding: const EdgeInsets.only(left: 10),
child: Text(AppLocalizations.of(_context).cc_email_address_prefix,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline,
color: AppColor.colorTextButton))),
const SizedBox(width: 4),
Expanded(child: Text(_identity?.cc?.listEmailAddressToString(isFullEmailAddress: true) ?? '',
style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: AppColor.colorHintSearchBar)))
])),
if (_identity?.bcc != null && _identity?.bcc?.isNotEmpty == true) const SizedBox(height: 6),
if (_identity?.bcc != null && _identity?.bcc?.isNotEmpty == true)
Padding(
@@ -101,7 +100,7 @@ class IdentityInfoTileBuilder extends StatelessWidget {
Container(
padding: const EdgeInsets.only(left: 6),
width: 40,
child: Text(AppLocalizations.of(_context).bcc_email_address_prefix,
child: Text(AppLocalizations.of(context).bcc_email_address_prefix,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
+25 -1
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2022-04-26T09:31:06.288489",
"@@last_modified": "2022-05-05T15:05:07.334710",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -1125,5 +1125,29 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"delete_identity": "Delete identity",
"@delete_identity": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"message_confirmation_dialog_delete_identity": "Are you sure you want to delete this identity?",
"@message_confirmation_dialog_delete_identity": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"identity_has_been_deleted": "Identity has been deleted",
"@identity_has_been_deleted": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"delete_failed": "Delete Failed",
"@delete_failed": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
@@ -1178,4 +1178,24 @@ class AppLocalizations {
return Intl.message('New Identity',
name: 'new_identity');
}
String get delete_identity {
return Intl.message('Delete identity',
name: 'delete_identity');
}
String get message_confirmation_dialog_delete_identity {
return Intl.message('Are you sure you want to delete this identity?',
name: 'message_confirmation_dialog_delete_identity');
}
String get identity_has_been_deleted {
return Intl.message('Identity has been deleted',
name: 'identity_has_been_deleted');
}
String get delete_failed {
return Intl.message('Delete Failed',
name: 'delete_failed');
}
}