TF-527 Display all identities
This commit is contained in:
@@ -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>();
|
||||
|
||||
+1
-1
@@ -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>(),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
+43
-19
@@ -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)) {
|
||||
|
||||
+27
-10
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
@@ -146,6 +146,8 @@ dependencies:
|
||||
|
||||
dropdown_button2: 1.4.0
|
||||
|
||||
flutter_staggered_grid_view: 0.6.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
Reference in New Issue
Block a user