TF-527 Display all identities

This commit is contained in:
dab246
2022-05-05 10:55:09 +07:00
committed by Dat H. Pham
parent 36e33b0866
commit 5dfd7a99a5
9 changed files with 159 additions and 49 deletions
@@ -21,7 +21,7 @@ class ManageAccountDashBoardController extends ReloadableController {
final GetUserProfileInteractor _getUserProfileInteractor;
final menuDrawerKey = GlobalKey<ScaffoldState>();
final menuDrawerKey = GlobalKey<ScaffoldState>(debugLabel: 'manage_account');
final appInformation = Rxn<PackageInfo>();
final userProfile = Rxn<UserProfile>();
@@ -25,9 +25,9 @@ class IdentitiesBindings extends BaseBindings {
void bindingsController() {
Get.lazyPut(() => IdentitiesController(
Get.find<GetAllIdentitiesInteractor>(),
Get.find<DeleteIdentityInteractor>(),
Get.find<CreateNewIdentityInteractor>(),
Get.find<Uuid>(),
Get.find<DeleteIdentityInteractor>(),
));
}
@@ -1,5 +1,6 @@
import 'package:core/core.dart';
import 'package:model/model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
@@ -20,8 +21,6 @@ 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';
import 'package:uuid/uuid.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 {
@@ -29,8 +28,6 @@ class IdentitiesController extends BaseController {
final _appToast = Get.find<AppToast>();
final _imagePaths = Get.find<ImagePaths>();
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
final _appToast = Get.find<AppToast>();
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
final CreateNewIdentityInteractor _createNewIdentityInteractor;
@@ -38,14 +35,14 @@ class IdentitiesController extends BaseController {
final DeleteIdentityInteractor _deleteIdentityInteractor;
final identitySelected = Rxn<Identity>();
final listIdentities = <Identity>[].obs;
final listAllIdentities = <Identity>[].obs;
final listSelectedIdentities = <Identity>[].obs;
final idIdentityAll = IdentityId(Id('all'));
IdentitiesController(
this._getAllIdentitiesInteractor,
this._deleteIdentityInteractor,
);
IdentitiesController(
this._getAllIdentitiesInteractor,
this._createNewIdentityInteractor,
this._uuid,
);
@@ -67,7 +64,10 @@ class IdentitiesController extends BaseController {
(success) {
if (success is GetAllIdentitiesSuccess) {
if (success.identities?.isNotEmpty == true) {
listIdentities.value = success.identities ?? [];
_addNewIdentityAsAll();
final newListIdentities = success.identities!;
newListIdentities.sortByMayDelete();
listAllIdentities.addAll(newListIdentities);
setIdentityDefault();
}
} else if (success is CreateNewIdentitySuccess) {
@@ -96,17 +96,47 @@ class IdentitiesController extends BaseController {
consumeState(_getAllIdentitiesInteractor.execute(accountId));
}
void _refreshAllIdentities() {
identitySelected.value = null;
listAllIdentities.clear();
listSelectedIdentities.clear();
final accountId = _accountDashBoardController.accountId.value;
if (accountId != null) {
_getAllIdentities(accountId);
}
}
void _addNewIdentityAsAll() {
if (currentContext != null) {
listAllIdentities.add(Identity(
id: idIdentityAll,
name: AppLocalizations.of(currentContext!).all_identities));
}
}
void setIdentityDefault() {
try {
final identityDefault = listIdentities.firstWhere((identity) => identity.mayDelete == false);
final identityDefault = listAllIdentities.firstWhere((identity) => identity.mayDelete == false);
selectIdentity(identityDefault);
} catch (exception) {
selectIdentity(listIdentities.first);
selectIdentity(listAllIdentities.first);
}
}
void selectIdentity(Identity? newIdentity) {
identitySelected.value = newIdentity;
if (newIdentity != null) {
_updateListSelectedIdentities(newIdentity);
}
}
void _updateListSelectedIdentities(Identity newIdentity) {
if (newIdentity.id == idIdentityAll) {
listSelectedIdentities.value = listAllIdentities.sublist(1);
} else {
listSelectedIdentities.value = [newIdentity];
}
}
void goToCreateNewIdentity() async {
@@ -138,10 +168,7 @@ class IdentitiesController extends BaseController {
icon: _imagePaths.icSelected);
}
final accountId = _accountDashBoardController.accountId.value;
if (accountId != null) {
_getAllIdentities(accountId);
}
_refreshAllIdentities();
}
void openConfirmationDialogDeleteIdentityAction(BuildContext context, Identity identity) {
@@ -209,10 +236,7 @@ class IdentitiesController extends BaseController {
icon: _imagePaths.icDeleteToast);
}
final accountId = _accountDashBoardController.accountId.value;
if (accountId != null) {
_getAllIdentities(accountId);
}
_refreshAllIdentities();
}
void _deleteIdentityFailure(DeleteIdentityFailure failure) {
@@ -2,16 +2,18 @@
import 'package:core/core.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.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/app_loader_mixin.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> with PopupMenuWidgetMixin {
class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidgetMixin, AppLoaderMixin {
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
@@ -30,17 +32,17 @@ class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidge
controller.identitySelected.value?.name ?? '',
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.normal, color: Colors.black),
maxLines: 1,
overflow: TextOverflow.ellipsis,
overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis,
)),
],
),
items: controller.listIdentities.map((item) => DropdownMenuItem<Identity>(
items: controller.listAllIdentities.map((item) => DropdownMenuItem<Identity>(
value: item,
child: Text(
item.name ?? '',
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.normal, color: Colors.black),
maxLines: 1,
overflow: TextOverflow.ellipsis,
overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis,
),
)).toList(),
value: controller.identitySelected.value,
@@ -68,7 +70,9 @@ class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidge
if (!_responsiveUtils.isMobile(context))
(ButtonBuilder(_imagePaths.icAddIdentity)
..key(const Key('button_new_identity'))
..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorTextButton))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppColor.colorTextButton))
..paddingIcon(const EdgeInsets.only(right: 8))
..iconColor(Colors.white)
..maxWidth(170)
@@ -86,16 +90,27 @@ class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidge
mobile: Scaffold(
body: Container(
margin: const EdgeInsets.only(top: 16, bottom: 16, right: 24),
child: SingleChildScrollView(child: Column(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buttonSelectIdentity,
Obx(() => IdentityInfoTileBuilder(_imagePaths, _responsiveUtils,
controller.identitySelected.value,
onMenuItemIdentityAction: (identity, position) =>
_openIdentityMenuAction(context, identity, position))),
const SizedBox(height: 24),
_buildLoadingView(),
Expanded(child: Obx(() => MasonryGridView.count(
key: const Key('list_identities'),
crossAxisSpacing: 24.0,
mainAxisSpacing: 24.0,
crossAxisCount: _responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context)
? 2 : 1,
itemCount: controller.listSelectedIdentities.length,
itemBuilder: (context, index) =>
IdentityInfoTileBuilder(_imagePaths, _responsiveUtils,
controller.listSelectedIdentities[index],
onMenuItemIdentityAction: (identity, position) =>
_openIdentityMenuAction(context, identity, position))
)))
]
))
)
),
floatingActionButton: _responsiveUtils.isMobile(context)
? FloatingActionButton(
@@ -106,23 +121,44 @@ class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidge
: null),
desktop: Container(
margin: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
child: SingleChildScrollView(child: Column(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: constraints.maxWidth / 2,
child: buttonSelectIdentity),
Obx(() => IdentityInfoTileBuilder(_imagePaths, _responsiveUtils,
controller.identitySelected.value,
maxWidth: constraints.maxWidth / 2,
onMenuItemIdentityAction: (identity, position) =>
_openIdentityMenuAction(context, identity, position))),
const SizedBox(height: 24),
_buildLoadingView(),
Expanded(child: Obx(() => MasonryGridView.count(
key: const Key('list_identities'),
crossAxisSpacing: 24.0,
mainAxisSpacing: 24.0,
crossAxisCount: _responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context)
? 2 : 1,
itemCount: controller.listSelectedIdentities.length,
itemBuilder: (context, index) =>
IdentityInfoTileBuilder(_imagePaths, _responsiveUtils,
controller.listSelectedIdentities[index],
onMenuItemIdentityAction: (identity, position) =>
_openIdentityMenuAction(context, identity, position))
)))
]
))
)
)
));
}
Widget _buildLoadingView() {
return Obx(() => controller.viewState.value.fold(
(failure) => const SizedBox.shrink(),
(success) => success is LoadingState
? Padding(
padding: const EdgeInsets.only(bottom: 24),
child: loadingWidget)
: const SizedBox.shrink()
));
}
void _openIdentityMenuAction(BuildContext context, Identity identity,
RelativeRect? position) {
if (_responsiveUtils.isScreenWithShortestSide(context)) {
@@ -12,7 +12,6 @@ class IdentityInfoTileBuilder extends StatelessWidget {
final ImagePaths _imagePaths;
final ResponsiveUtils _responsiveUtils;
final Identity? _identity;
final double? maxWidth;
final OnMenuItemIdentityAction? onMenuItemIdentityAction;
const IdentityInfoTileBuilder(
@@ -21,7 +20,6 @@ class IdentityInfoTileBuilder extends StatelessWidget {
this._identity,
{
Key? key,
this.maxWidth,
this.onMenuItemIdentityAction,
}
) : super(key: key);
@@ -39,14 +37,31 @@ class IdentityInfoTileBuilder extends StatelessWidget {
border: Border.all(color: AppColor.colorBorderIdentityInfo, width: 1),
color: Colors.white),
padding: const EdgeInsets.only(top: 12, bottom: 12),
margin: const EdgeInsets.only(top: 12),
width: maxWidth,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
padding: const EdgeInsets.only(left: 12, right: 8),
child: Row(children: [
Expanded(child: Text(_identity?.name ?? '',
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 17, color: Colors.black))),
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)))
]))
else
Expanded(child: Text(_identity?.name ?? '',
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 17,
color: Colors.black)),),
buildIconWebHasPosition(
context,
icon: SvgPicture.asset(_imagePaths.icMoreVertical, fit: BoxFit.fill),
@@ -80,7 +95,8 @@ class IdentityInfoTileBuilder extends StatelessWidget {
Expanded(child: Text(_identity?.email ?? '',
style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: AppColor.colorHintSearchBar)))
])),
if (_identity?.replyTo != null && _identity?.replyTo?.isNotEmpty == true) const SizedBox(height: 10),
if (_identity?.replyTo != null && _identity?.replyTo?.isNotEmpty == true)
const SizedBox(height: 10),
if (_identity?.replyTo != null && _identity?.replyTo?.isNotEmpty == true)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
@@ -92,9 +108,10 @@ 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?.bcc != null && _identity?.bcc?.isNotEmpty == true) const SizedBox(height: 6),
if (_identity?.bcc != null && _identity?.bcc?.isNotEmpty == true)
Padding(
const SizedBox(height: 6),
if (_identity?.bcc != null && _identity?.bcc?.isNotEmpty == true)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(children: [
Container(
@@ -1227,6 +1227,19 @@ class AppLocalizations {
name: 'you_have_created_a_new_identity');
}
String get all_identities {
return Intl.message(
'All identities',
name: 'all_identities');
}
String get default_value {
return Intl.message(
'Default',
name: 'default_value',
);
}
String get delete_identity {
return Intl.message('Delete identity',
name: 'delete_identity');
@@ -0,0 +1,17 @@
import 'package:jmap_dart_client/jmap/identities/identity.dart';
extension ListIdentitiesExtension on List<Identity> {
void sortByMayDelete() {
sort((identity1, identity2) {
if (identity1.mayDelete == false && identity2.mayDelete == true) {
return -1;
} if (identity1.mayDelete == true && identity2.mayDelete == false) {
return 1;
} else {
return 0;
}
});
}
}
+1
View File
@@ -55,6 +55,7 @@ export 'extensions/media_type_extension.dart';
export 'extensions/list_attachment_extension.dart';
export 'extensions/list_presentation_email_extension.dart';
export 'extensions/list_email_content_extension.dart';
export 'extensions/list_identities_extension.dart';
// Download
export 'download/download_task_id.dart';
+2
View File
@@ -146,6 +146,8 @@ dependencies:
dropdown_button2: 1.4.0
flutter_staggered_grid_view: 0.6.1
dev_dependencies:
flutter_test:
sdk: flutter