TF-3847 Fix blank user avatar on Stalwart server

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-07-08 16:43:48 +07:00
committed by Dat H. Pham
parent 18a490286e
commit da71890120
17 changed files with 137 additions and 54 deletions
@@ -85,7 +85,7 @@ extension ComposerPrintDraftExtension on ComposerController {
child: PrintDraftDialogView(
emailPrint: DraftEmailPrint(
appName: appLocalizations.app_name,
userName: mailboxDashBoardController.getOwnEmailAddress(),
userName: mailboxDashBoardController.ownEmailAddress.value,
attachments: uploadController.allAttachmentsUploaded,
emailContent: emailContent,
fromPrefix: appLocalizations.from_email_address_prefix,
@@ -220,7 +220,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
Session? get session => mailboxDashBoardController.sessionCurrent;
String get ownEmailAddress => mailboxDashBoardController.getOwnEmailAddress();
String get ownEmailAddress => mailboxDashBoardController.ownEmailAddress.value;
SingleEmailController(
this._getEmailContentInteractor,
@@ -2052,7 +2052,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_printEmailInteractor.execute(
EmailPrint(
appName: appLocalizations.app_name,
userName: mailboxDashBoardController.getOwnEmailAddress(),
userName: mailboxDashBoardController.ownEmailAddress.value,
attachments: currentEmailLoaded.value!.attachments,
emailContent: currentEmailLoaded.value!.htmlContent,
fromPrefix: appLocalizations.from_email_address_prefix,
@@ -2555,7 +2555,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
listEmailAddressAttendees.addAll(listEmailAddress);
final currentUserEmail = mailboxDashBoardController.getOwnEmailAddress();
final currentUserEmail = mailboxDashBoardController.ownEmailAddress.value;
final listEmailAddressMailTo = listEmailAddressAttendees.removeInvalidEmails(currentUserEmail);
log('SingleEmailController::handleMailToAttendees: listEmailAddressMailTo = $listEmailAddressMailTo');
mailboxDashBoardController.openComposer(
@@ -375,7 +375,8 @@ class EmailView extends GetWidget<SingleEmailController> {
attendanceStatus: controller.attendanceStatus.value,
ownEmailAddress: controller
.mailboxDashBoardController
.getOwnEmailAddress(),
.ownEmailAddress
.value,
onMailtoAttendeesAction: controller.handleMailToAttendees,
openEmailAddressDetailAction: controller.openEmailAddressDialog,
isFree: controller.isCalendarEventFree,
@@ -34,9 +34,7 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
final dashboardController = controller.mailboxDashBoardController;
final accountId = dashboardController.accountId.value;
final session = dashboardController.sessionCurrent;
final username = accountId != null
? dashboardController.getOwnEmailAddress()
: '';
final username = dashboardController.ownEmailAddress.value;
final linagoraApps = dashboardController
.appGridDashboardController
@@ -1229,7 +1229,7 @@ class MailboxController extends BaseMailboxController
case MailboxActions.copySubaddress:
try{
final subaddress = getSubAddress(
mailboxDashBoardController.getOwnEmailAddress(),
mailboxDashBoardController.ownEmailAddress.value,
findNodePathWithSeparator(mailbox.id, '.')!,
);
copySubAddressAction(context, subaddress);
@@ -1247,7 +1247,7 @@ class MailboxController extends BaseMailboxController
case MailboxActions.allowSubaddressing:
try{
final subAddress = getSubAddress(
mailboxDashBoardController.getOwnEmailAddress(),
mailboxDashBoardController.ownEmailAddress.value,
findNodePathWithSeparator(mailbox.id, '.')!,
);
openConfirmationDialogSubAddressingAction(
@@ -11,7 +11,7 @@ typedef OnSubtitleClick = void Function();
class UserInformationWidget extends StatelessWidget {
final String userName;
final String ownEmailAddress;
final String? subtitle;
final EdgeInsetsGeometry? titlePadding;
final OnSubtitleClick? onSubtitleClick;
@@ -20,7 +20,7 @@ class UserInformationWidget extends StatelessWidget {
const UserInformationWidget({
Key? key,
required this.userName,
required this.ownEmailAddress,
this.subtitle,
this.titlePadding,
this.onSubtitleClick,
@@ -35,7 +35,7 @@ class UserInformationWidget extends StatelessWidget {
decoration: BoxDecoration(border: border),
child: Row(children: [
UserAvatarBuilder(
username: userName.firstLetterToUpperCase,
username: ownEmailAddress.firstLetterToUpperCase,
size: 51,
textStyle: ThemeUtils.textStyleInter500().copyWith(
fontSize: 25.5,
@@ -49,7 +49,7 @@ class UserInformationWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SelectableText(
userName,
ownEmailAddress,
maxLines: 1,
style: ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 17,
@@ -113,6 +113,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_own_email_address_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart';
@@ -259,6 +260,7 @@ class MailboxDashBoardController extends ReloadableController
final isDrawerOpened = RxBool(false);
final isContextMenuOpened = RxBool(false);
final isPopupMenuOpened = RxBool(false);
final ownEmailAddress = RxString('');
Session? sessionCurrent;
Map<Role, MailboxId> mapDefaultMailboxIdByRole = {};
@@ -757,6 +759,7 @@ class MailboxDashBoardController extends ReloadableController
_isFirstSessionLoad = true;
sessionCurrent = session;
accountId.value = currentAccountId;
synchronizeOwnEmailAddress(session.getOwnEmailAddressOrEmpty());
injectAutoCompleteBindings(session, currentAccountId);
injectRuleFilterBindings(session, currentAccountId);
@@ -3099,12 +3102,17 @@ class MailboxDashBoardController extends ReloadableController
void _handleGetAllIdentitiesSuccess(GetAllIdentitiesSuccess success) {
log('MailboxDashBoardController::_handleGetAllIdentitiesSuccess: IDENTITIES_SIZE = ${_identities?.length}');
final listIdentitiesMayDeleted = success.identities?.toListMayDeleted() ?? [];
final listIdentities = success.identities ?? [];
final listIdentitiesMayDeleted = listIdentities.toListMayDeleted();
_identities = listIdentitiesMayDeleted;
updateOwnEmailAddressFromIdentities(listIdentities);
}
void _handleGetAllIdentitiesFailure() {
_identities = null;
synchronizeOwnEmailAddress(sessionCurrent?.getUserDisplayName() ?? '');
}
List<Identity> get listIdentities => _identities ?? [];
@@ -3160,8 +3168,6 @@ class MailboxDashBoardController extends ReloadableController
}
}
String getOwnEmailAddress() => sessionCurrent?.getOwnEmailAddressOrEmpty() ?? '';
@override
void onClose() {
if (PlatformInfo.isWeb) {
@@ -0,0 +1,24 @@
import 'package:core/utils/app_logger.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:model/extensions/session_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
extension UpdateOwnEmailAddressExtension on MailboxDashBoardController {
void synchronizeOwnEmailAddress(String emailAddress) {
log('UpdateOwnEmailAddressExtension::synchronizeOwnEmailAddress:OwnEmailAddress = ${ownEmailAddress.value}, NewEmailAddress = $emailAddress');
if (ownEmailAddress.value.isNotEmpty || emailAddress.isEmpty) return;
ownEmailAddress.value = emailAddress;
}
void updateOwnEmailAddressFromIdentities(List<Identity> listIdentities) {
final identityEmailAddress = listIdentities.firstOrNull?.email ?? '';
if (identityEmailAddress.isNotEmpty) {
synchronizeOwnEmailAddress(identityEmailAddress);
} else {
synchronizeOwnEmailAddress(sessionCurrent?.getUserDisplayName() ?? '');
}
}
}
@@ -78,30 +78,34 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
return Obx(() {
final accountId = controller.accountId.value;
return NavigationBarWidget(
imagePaths: controller.imagePaths,
accountId: accountId,
ownEmailAddress: controller.getOwnEmailAddress(),
contactSupportCapability: accountId != null
final ownEmailAddress = controller.ownEmailAddress.value;
final contactSupportCapability = accountId != null
? controller.sessionCurrent?.getContactSupportCapability(accountId)
: null,
searchForm: SearchInputFormWidget(),
appGridController: controller.appGridDashboardController,
settingActionTypes: ProfileSettingActionType.values,
onTapApplicationLogoAction: controller.redirectToInboxAction,
onTapContactSupportAction: (contactSupport) =>
controller.onGetHelpOrReportBug(contactSupport),
onProfileSettingActionTypeClick: (actionType) =>
controller.handleProfileSettingActionTypeClick(
: null;
return NavigationBarWidget(
imagePaths: controller.imagePaths,
accountId: accountId,
ownEmailAddress: ownEmailAddress,
contactSupportCapability: contactSupportCapability,
searchForm: SearchInputFormWidget(),
appGridController:
controller.appGridDashboardController,
settingActionTypes: ProfileSettingActionType.values,
onTapApplicationLogoAction:
controller.redirectToInboxAction,
onTapContactSupportAction: (contactSupport) =>
controller.onGetHelpOrReportBug(contactSupport),
onProfileSettingActionTypeClick: (actionType) =>
controller.handleProfileSettingActionTypeClick(
context: context,
actionType: actionType,
),
);
});
}
},
),
Expanded(child: Row(children: [
Expanded(child: Row(children: [
Column(children: [
ComposeButtonWidget(
imagePaths: controller.imagePaths,
@@ -144,13 +148,8 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
),
const Spacer(),
Obx(() {
final accountId = controller.accountId.value;
final ownEmailAddress = accountId == null
? ''
: controller.getOwnEmailAddress();
return ProfileSettingIcon(
ownEmailAddress: ownEmailAddress,
ownEmailAddress: controller.ownEmailAddress.value,
settingActionTypes: ProfileSettingActionType.values,
onProfileSettingActionTypeClick: (actionType) =>
controller.handleProfileSettingActionTypeClick(
@@ -0,0 +1,24 @@
import 'package:core/utils/app_logger.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:model/extensions/session_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
extension UpdateOwnEmailAddressExtension on ManageAccountDashBoardController {
void synchronizeOwnEmailAddress(String emailAddress) {
log('UpdateOwnEmailAddressExtension::synchronizeOwnEmailAddress:OwnEmailAddress = ${ownEmailAddress.value}, NewEmailAddress = $emailAddress');
if (ownEmailAddress.value.isNotEmpty || emailAddress.isEmpty) return;
ownEmailAddress.value = emailAddress;
}
void updateOwnEmailAddressFromIdentities(List<Identity> listIdentities) {
final identityEmailAddress = listIdentities.firstOrNull?.email ?? '';
if (identityEmailAddress.isNotEmpty) {
synchronizeOwnEmailAddress(identityEmailAddress);
} else {
synchronizeOwnEmailAddress(sessionCurrent?.getUserDisplayName() ?? '');
}
}
}
@@ -24,6 +24,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/update_vac
import 'package:tmail_ui_user/features/manage_account/presentation/action/dashboard_setting_action.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/bindings/email_rules_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/export_trace_log_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/update_own_email_address_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forward_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_bindings.dart';
@@ -53,6 +54,7 @@ class ManageAccountDashBoardController extends ReloadableController {
final settingsPageLevel = SettingsPageLevel.universal.obs;
final vacationResponse = Rxn<VacationResponse>();
final dashboardSettingAction = Rxn<UIAction>();
final ownEmailAddress = Rx<String>('');
Session? sessionCurrent;
bool? isVacationDateDialogDisplayed;
@@ -103,6 +105,7 @@ class ManageAccountDashBoardController extends ReloadableController {
log('ManageAccountDashBoardController::handleReloaded:');
sessionCurrent = session;
accountId.value = session.accountId;
synchronizeOwnEmailAddress(session.getOwnEmailAddressOrEmpty());
_bindingInteractorForMenuItemView(sessionCurrent, accountId.value);
_getVacationResponse();
_getParametersRouter();
@@ -112,7 +115,8 @@ class ManageAccountDashBoardController extends ReloadableController {
final arguments = Get.arguments;
if (arguments is ManageAccountArguments) {
sessionCurrent = arguments.session;
accountId.value = arguments.session?.personalAccount.accountId;
accountId.value = arguments.session?.accountId;
synchronizeOwnEmailAddress(arguments.session?.getOwnEmailAddressOrEmpty() ?? '');
previousUri = arguments.previousUri;
_bindingInteractorForMenuItemView(sessionCurrent, accountId.value);
_getVacationResponse();
@@ -399,9 +403,6 @@ class ManageAccountDashBoardController extends ReloadableController {
accountId: accountId.value!);
}
String getOwnEmailAddress() =>
sessionCurrent?.getOwnEmailAddressOrEmpty() ?? '';
@override
void onClose() {
BackButtonInterceptor.removeByName(AppRoutes.settings);
@@ -47,7 +47,7 @@ class ManageAccountDashBoardView extends GetWidget<ManageAccountDashBoardControl
return Obx(() => NavigationBarWidget(
imagePaths: controller.imagePaths,
accountId: controller.accountId.value,
ownEmailAddress: controller.getOwnEmailAddress(),
ownEmailAddress: controller.ownEmailAddress.value,
onTapApplicationLogoAction: () =>
controller.backToMailboxDashBoard(context: context),
settingActionTypes: const [ProfileSettingActionType.signOut],
@@ -20,11 +20,16 @@ class SettingsFirstLevelView extends GetWidget<SettingsController> {
key: const Key('setting_menu'),
child: Column(children: [
Obx(() => UserInformationWidget(
userName: controller.manageAccountDashboardController.accountId.value != null
? controller.manageAccountDashboardController.getOwnEmailAddress()
: '',
padding: SettingsUtils.getPaddingInFirstLevel(context, controller.responsiveUtils),
titlePadding: const EdgeInsetsDirectional.only(start: 16))),
ownEmailAddress: controller
.manageAccountDashboardController
.ownEmailAddress
.value,
padding: SettingsUtils.getPaddingInFirstLevel(
context,
controller.responsiveUtils,
),
titlePadding: const EdgeInsetsDirectional.only(start: 16),
)),
Divider(
color: AppColor.colorDividerHorizontal,
height: 1,
@@ -13,6 +13,7 @@ import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:model/extensions/identity_request_dto_extension.dart';
import 'package:model/extensions/session_extension.dart';
import 'package:tmail_ui_user/features/base/before_reconnect_handler.dart';
import 'package:tmail_ui_user/features/base/before_reconnect_manager.dart';
import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart';
@@ -39,6 +40,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_ident
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/transform_html_signature_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/identity_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/update_own_email_address_extension.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/features/manage_account/presentation/profiles/identities/widgets/delete_identity_dialog_builder.dart';
@@ -128,6 +130,10 @@ class IdentitiesController extends ReloadableController implements BeforeReconne
_deleteIdentityAction(failure.identityId);
} else if (failure is GetIdentityCacheOnWebFailure) {
_removeIdentityCache();
} else if (failure is GetAllIdentitiesFailure) {
accountDashBoardController.synchronizeOwnEmailAddress(
accountDashBoardController.sessionCurrent?.getUserDisplayName() ?? '',
);
}
}
@@ -158,13 +164,17 @@ class IdentitiesController extends ReloadableController implements BeforeReconne
}
void _handleGetAllIdentitiesSuccess(GetAllIdentitiesSuccess success) {
if (success.identities?.isNotEmpty == true) {
final newListIdentities = success.identities!
final listIdentities = success.identities ?? [];
if (listIdentities.isNotEmpty) {
final newListIdentities = listIdentities
.where((identity) => identity.mayDelete == true && identity.name?.trim().isNotEmpty == true)
.toList();
listAllIdentities.addAll(newListIdentities);
}
accountDashBoardController.updateOwnEmailAddressFromIdentities(listIdentities);
if (listAllIdentities.isNotEmpty) {
selectIdentity(listAllIdentities.first);
}
@@ -357,7 +357,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
case MailboxActions.copySubaddress:
try {
final subAddress = getSubAddress(
dashboardController.getOwnEmailAddress(),
dashboardController.ownEmailAddress.value,
findNodePathWithSeparator(mailbox.id, '.')!,
);
copySubAddressAction(context, subAddress);
@@ -371,7 +371,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
case MailboxActions.allowSubaddressing:
try{
final subAddress = getSubAddress(
dashboardController.getOwnEmailAddress(),
dashboardController.ownEmailAddress.value,
findNodePathWithSeparator(mailbox.id, '.')!,
);
openConfirmationDialogSubAddressingAction(
@@ -72,6 +72,20 @@ extension SessionExtension on Session {
}
}
String getUserDisplayName() {
try {
final accountDisplayName = personalAccount.name.value;
if (accountDisplayName.isNotEmpty) {
return accountDisplayName;
} else {
return username.value;
}
} catch (e) {
logError('SessionExtension::getUserDisplayName:Exception: $e');
return '';
}
}
String getOwnEmailAddressOrEmpty() {
try {
return getOwnEmailAddress();
@@ -243,6 +243,7 @@ void main() {
.thenAnswer((_) => Stream.value(Right(GetAllIdentitiesSuccess(
[identity1, identity2, identity3, identity4],
null))));
when(mockManageAccountDashBoardController.ownEmailAddress).thenReturn(Rx(''));
when(mockManageAccountDashBoardController.accountId).thenReturn(Rxn());
when(mockManageAccountDashBoardController.sessionCurrent).thenReturn(SessionFixtures.aliceSession);