TF-4068 Change profile (set identity as default) in setting
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
|
||||
import 'package:jmap_dart_client/jmap/identities/identity.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/exceptions/null_session_or_accountid_exception.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/edit_default_identity_state.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/identity_extension.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/identities/identities_controller.dart';
|
||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||
|
||||
extension VerifyDefaultIdentitySupportedExtension on IdentitiesController {
|
||||
bool get isDefaultIdentitySupported {
|
||||
final accountId = accountDashBoardController.accountId.value;
|
||||
final session = accountDashBoardController.sessionCurrent;
|
||||
if (session != null && accountId != null) {
|
||||
return [CapabilityIdentifier.jamesSortOrder].isSupported(
|
||||
session,
|
||||
accountId,
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void changeIdentityAsDefault(Identity identity) {
|
||||
final accountId = accountDashBoardController.accountId.value;
|
||||
final session = accountDashBoardController.sessionCurrent;
|
||||
|
||||
if (session != null && accountId != null && identity.id != null) {
|
||||
editIdentityAction(
|
||||
session,
|
||||
accountId,
|
||||
EditIdentityRequest.fromIdentityWithoutPublicAssets(
|
||||
identity.asDefault(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
consumeState(
|
||||
Stream.value(
|
||||
Left(EditDefaultIdentityFailure(NullSessionOrAccountIdException())),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
|
||||
import 'package:jmap_dart_client/jmap/identities/identity.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/model/identity_signature.dart';
|
||||
|
||||
extension IdentityExtension on Identity {
|
||||
@@ -16,4 +18,32 @@ extension IdentityExtension on Identity {
|
||||
IdentitySignature? toIdentitySignature() => id != null
|
||||
? IdentitySignature(identityId: id!, signature: signatureAsString)
|
||||
: null;
|
||||
|
||||
Identity asDefault() => copyWith(sortOrder: UnsignedInt(0));
|
||||
|
||||
Identity copyWith({
|
||||
IdentityId? id,
|
||||
String? description,
|
||||
String? name,
|
||||
String? email,
|
||||
Set<EmailAddress>? bcc,
|
||||
Set<EmailAddress>? replyTo,
|
||||
Signature? textSignature,
|
||||
Signature? htmlSignature,
|
||||
bool? mayDelete,
|
||||
UnsignedInt? sortOrder,
|
||||
}) {
|
||||
return Identity(
|
||||
id: id ?? this.id,
|
||||
description: description ?? this.description,
|
||||
name: name ?? this.name,
|
||||
email: email ?? this.email,
|
||||
bcc: bcc ?? this.bcc,
|
||||
replyTo: replyTo ?? this.replyTo,
|
||||
textSignature: textSignature ?? this.textSignature,
|
||||
htmlSignature: htmlSignature ?? this.htmlSignature,
|
||||
mayDelete: mayDelete ?? this.mayDelete,
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ class IdentitiesController extends ReloadableController implements BeforeReconne
|
||||
if (newIdentityArguments is CreateNewIdentityRequest) {
|
||||
_createNewIdentityAction(session, accountId, newIdentityArguments);
|
||||
} else if (newIdentityArguments is EditIdentityRequest) {
|
||||
_editIdentityAction(session, accountId, newIdentityArguments);
|
||||
editIdentityAction(session, accountId, newIdentityArguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,12 +388,12 @@ class IdentitiesController extends ReloadableController implements BeforeReconne
|
||||
if (newIdentityArguments is CreateNewIdentityRequest) {
|
||||
_createNewIdentityAction(session, accountId, newIdentityArguments);
|
||||
} else if (newIdentityArguments is EditIdentityRequest) {
|
||||
_editIdentityAction(session, accountId, newIdentityArguments);
|
||||
editIdentityAction(session, accountId, newIdentityArguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _editIdentityAction(
|
||||
void editIdentityAction(
|
||||
Session session,
|
||||
AccountId accountId,
|
||||
EditIdentityRequest editIdentityRequest
|
||||
@@ -406,19 +406,18 @@ class IdentitiesController extends ReloadableController implements BeforeReconne
|
||||
}
|
||||
|
||||
void _editIdentitySuccess(EditIdentitySuccess success) {
|
||||
_removeIdentityCache();
|
||||
toastManager.showMessageSuccess(success);
|
||||
|
||||
if (currentOverlayContext != null && currentContext != null) {
|
||||
appToast.showToastSuccessMessage(
|
||||
currentOverlayContext!,
|
||||
AppLocalizations.of(currentContext!).you_are_changed_your_identity_successfully);
|
||||
if (!success.isSetAsDefault) {
|
||||
_removeIdentityCache();
|
||||
|
||||
_cleanUpPublicAssets(
|
||||
success.identityId,
|
||||
IdentityActionType.edit,
|
||||
success.publicAssetsInIdentityArguments,
|
||||
);
|
||||
}
|
||||
|
||||
_cleanUpPublicAssets(
|
||||
success.identityId,
|
||||
IdentityActionType.edit,
|
||||
success.publicAssetsInIdentityArguments);
|
||||
|
||||
_refreshAllIdentities();
|
||||
}
|
||||
|
||||
@@ -491,7 +490,7 @@ class IdentitiesController extends ReloadableController implements BeforeReconne
|
||||
if (newIdentityArguments is CreateNewIdentityRequest) {
|
||||
_createNewIdentityAction(session, accountId, newIdentityArguments);
|
||||
} else if (newIdentityArguments is EditIdentityRequest) {
|
||||
_editIdentityAction(session, accountId, newIdentityArguments);
|
||||
editIdentityAction(session, accountId, newIdentityArguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import 'package:core/presentation/extensions/either_view_state_extension.dart';
|
||||
import 'package:core/presentation/utils/theme_utils.dart';
|
||||
import 'package:core/presentation/views/list/no_stretch_scroll_behavior.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/state/edit_default_identity_state.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/base/setting_detail_view_builder.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/change_identity_as_default_extension.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/identities/identities_controller.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/identities/widgets/create_new_identity_button_widget.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/identities/widgets/identity_list_tile_builder.dart';
|
||||
@@ -88,41 +91,60 @@ class IdentitiesView extends GetWidget<IdentitiesController> {
|
||||
)),
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
final identities = controller.listAllIdentities;
|
||||
final isDefaultIdentitySupported = controller.isDefaultIdentitySupported;
|
||||
final identitySelected = controller.identitySelected.value;
|
||||
|
||||
final Widget listView = ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: controller.listAllIdentities.length + 1,
|
||||
itemCount: identities.length + 1,
|
||||
controller: controller.listIdentityScrollController,
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
start: 24,
|
||||
padding: EdgeInsetsDirectional.only(
|
||||
start: isDefaultIdentitySupported ? 12 : 24,
|
||||
end: 24,
|
||||
bottom: 24,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
if (index == controller.listAllIdentities.length) {
|
||||
if (index == identities.length) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final identity = controller.listAllIdentities[index];
|
||||
final isSelected = identity == controller.identitySelected.value;
|
||||
return Obx(() => IdentityListTileBuilder(
|
||||
imagePaths: controller.imagePaths,
|
||||
identity: identity,
|
||||
isSelected: isSelected,
|
||||
mapIdentitySignatures: controller.mapIdentitySignatures,
|
||||
signatureViewState: controller.signatureViewState.value,
|
||||
isDesktop: isDesktop,
|
||||
scrollController: controller.listIdentityScrollController,
|
||||
onEditIdentityAction: (identitySelected) =>
|
||||
controller.goToEditIdentity(context, identitySelected),
|
||||
onDeleteIdentityAction: (identitySelected) =>
|
||||
controller.openConfirmationDialogDeleteIdentityAction(
|
||||
context,
|
||||
identitySelected,
|
||||
),
|
||||
));
|
||||
final identity = identities[index];
|
||||
final isSelected = identity == identitySelected;
|
||||
|
||||
return Obx(() {
|
||||
final loadingState = controller.viewState.value
|
||||
.foldSuccessWithResult<EditDefaultIdentityLoading>();
|
||||
|
||||
bool isItemLoading =
|
||||
loadingState is EditDefaultIdentityLoading &&
|
||||
loadingState.isSetAsDefault;
|
||||
|
||||
return IdentityListTileBuilder(
|
||||
imagePaths: controller.imagePaths,
|
||||
identity: identity,
|
||||
isSelected: isSelected,
|
||||
isDefaultIdentitySupported: isDefaultIdentitySupported,
|
||||
mapIdentitySignatures: controller.mapIdentitySignatures,
|
||||
signatureViewState: controller.signatureViewState.value,
|
||||
isDesktop: isDesktop,
|
||||
isItemLoading: isItemLoading,
|
||||
scrollController: controller.listIdentityScrollController,
|
||||
onEditIdentityAction: (identitySelected) =>
|
||||
controller.goToEditIdentity(context, identitySelected),
|
||||
onDeleteIdentityAction: (identitySelected) =>
|
||||
controller.openConfirmationDialogDeleteIdentityAction(
|
||||
context,
|
||||
identitySelected,
|
||||
),
|
||||
onChangeIdentityAsDefaultAction: controller.changeIdentityAsDefault,
|
||||
);
|
||||
});
|
||||
},
|
||||
separatorBuilder: (_, index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||
padding: isDefaultIdentitySupported
|
||||
? const EdgeInsets.only(top: 24, bottom: 12)
|
||||
: const EdgeInsets.symmetric(vertical: 24),
|
||||
child: Divider(color: Colors.black.withValues(alpha: 0.08)),
|
||||
),
|
||||
);
|
||||
|
||||
+58
-22
@@ -3,9 +3,9 @@ import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/state/failure.dart';
|
||||
import 'package:core/presentation/state/success.dart';
|
||||
import 'package:core/presentation/utils/theme_utils.dart';
|
||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:jmap_dart_client/jmap/identities/identity.dart';
|
||||
import 'package:model/extensions/list_email_address_extension.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/identity_extension.dart';
|
||||
@@ -14,6 +14,8 @@ import 'package:tmail_ui_user/features/manage_account/presentation/identities/wi
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/identities/widgets/signature_loading_widget.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
typedef OnChangeIdentityAsDefaultAction = Function(Identity identity);
|
||||
|
||||
class IdentityListTileBuilder extends StatelessWidget {
|
||||
|
||||
const IdentityListTileBuilder({
|
||||
@@ -26,7 +28,10 @@ class IdentityListTileBuilder extends StatelessWidget {
|
||||
required this.onDeleteIdentityAction,
|
||||
this.isDesktop = false,
|
||||
this.isSelected = false,
|
||||
this.isDefaultIdentitySupported = false,
|
||||
this.isItemLoading = false,
|
||||
this.scrollController,
|
||||
this.onChangeIdentityAsDefaultAction,
|
||||
}) : super(key: key);
|
||||
|
||||
final Identity identity;
|
||||
@@ -35,17 +40,26 @@ class IdentityListTileBuilder extends StatelessWidget {
|
||||
final ImagePaths imagePaths;
|
||||
final bool isSelected;
|
||||
final bool isDesktop;
|
||||
final bool isDefaultIdentitySupported;
|
||||
final bool isItemLoading;
|
||||
final OnEditIdentityAction onEditIdentityAction;
|
||||
final OnDeleteIdentityAction onDeleteIdentityAction;
|
||||
final OnChangeIdentityAsDefaultAction? onChangeIdentityAsDefaultAction;
|
||||
final ScrollController? scrollController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final selectedIcon = SvgPicture.asset(
|
||||
isSelected ? imagePaths.icRadioSelected : imagePaths.icRadio,
|
||||
width: 18,
|
||||
height: 18,
|
||||
fit: BoxFit.fill,
|
||||
final selectedIcon = AbsorbPointer(
|
||||
absorbing: isItemLoading,
|
||||
child: TMailButtonWidget.fromIcon(
|
||||
icon: isSelected ? imagePaths.icRadioSelected : imagePaths.icRadio,
|
||||
iconSize: 18,
|
||||
padding: const EdgeInsets.all(12),
|
||||
backgroundColor: Colors.transparent,
|
||||
borderRadius: 100,
|
||||
onTapActionCallback: () =>
|
||||
onChangeIdentityAsDefaultAction?.call(identity),
|
||||
),
|
||||
);
|
||||
|
||||
final signatureContent = mapIdentitySignatures[identity.id!] ??
|
||||
@@ -113,18 +127,30 @@ class IdentityListTileBuilder extends StatelessWidget {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
selectedIcon,
|
||||
if (isDefaultIdentitySupported)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 6),
|
||||
child: selectedIcon,
|
||||
),
|
||||
Container(
|
||||
width: 280,
|
||||
padding: const EdgeInsetsDirectional.only(start: 18, end: 12),
|
||||
padding: EdgeInsetsDirectional.only(
|
||||
end: 12,
|
||||
top: isDefaultIdentitySupported ? 10 : 0,
|
||||
),
|
||||
child: identityContent,
|
||||
),
|
||||
ListIdentityItemActionsWidget(
|
||||
identity: identity,
|
||||
imagePaths: imagePaths,
|
||||
onEditIdentityAction: onEditIdentityAction,
|
||||
onDeleteIdentityAction: onDeleteIdentityAction,
|
||||
isDesktop: isDesktop,
|
||||
Padding(
|
||||
padding: isDefaultIdentitySupported
|
||||
? const EdgeInsetsDirectional.only(top: 10)
|
||||
: EdgeInsetsDirectional.zero,
|
||||
child: ListIdentityItemActionsWidget(
|
||||
identity: identity,
|
||||
imagePaths: imagePaths,
|
||||
onEditIdentityAction: onEditIdentityAction,
|
||||
onDeleteIdentityAction: onDeleteIdentityAction,
|
||||
isDesktop: isDesktop,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
@@ -134,14 +160,24 @@ class IdentityListTileBuilder extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
selectedIcon,
|
||||
const SizedBox(width: 18),
|
||||
Expanded(child: identityContent),
|
||||
],
|
||||
),
|
||||
if (isDefaultIdentitySupported)
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 6),
|
||||
child: selectedIcon,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 10),
|
||||
child: identityContent,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
identityContent,
|
||||
const SizedBox(height: 24),
|
||||
ListIdentityItemActionsWidget(
|
||||
identity: identity,
|
||||
|
||||
Reference in New Issue
Block a user