@@ -0,0 +1,28 @@
|
|||||||
|
# 58. Hide session expires dialog to avoid confusing users
|
||||||
|
|
||||||
|
Date: 2025-04-14
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Why did we use Session Expires dialog before, to solve data loss problems when connection is lost:
|
||||||
|
|
||||||
|
- Data loss when connection is lost [#2928](https://github.com/linagora/tmail-flutter/issues/2928)
|
||||||
|
- Poor network in the train take me to login page [#2965](https://github.com/linagora/tmail-flutter/issues/2965)
|
||||||
|
- Finner handling of reconnection [#3290](https://github.com/linagora/tmail-flutter/issues/3290)
|
||||||
|
|
||||||
|
But displaying a dialog with such text is confusing to many users,
|
||||||
|
who worry about whether the data has actually been saved.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
Hide Session Expires dialog:
|
||||||
|
- If composer is open, it will automatically save data and reconnect immediately
|
||||||
|
- If composer is closed, it will automatically reconnect immediately.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
Every time the session expires, the system automatically reconnects and restores the old data.
|
||||||
@@ -6,7 +6,6 @@ import 'package:dartz/dartz.dart';
|
|||||||
import 'package:fcm/model/firebase_capability.dart';
|
import 'package:fcm/model/firebase_capability.dart';
|
||||||
import 'package:fcm/model/firebase_registration_id.dart';
|
import 'package:fcm/model/firebase_registration_id.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:forward/forward/capability_forward.dart';
|
import 'package:forward/forward/capability_forward.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
@@ -221,44 +220,11 @@ abstract class BaseController extends GetxController
|
|||||||
|
|
||||||
void _handleBadCredentialsException() {
|
void _handleBadCredentialsException() {
|
||||||
log('$runtimeType::_handleBadCredentialsException:');
|
log('$runtimeType::_handleBadCredentialsException:');
|
||||||
if (!twakeAppManager.hasComposer) {
|
if (twakeAppManager.hasComposer) {
|
||||||
_performReconnection();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentContext == null) {
|
|
||||||
_performSaveAndReconnection();
|
_performSaveAndReconnection();
|
||||||
return;
|
} else {
|
||||||
|
_performReconnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (twakeAppManager.isSessionExpiresDialogOpened) return;
|
|
||||||
|
|
||||||
final appLocalizations = AppLocalizations.of(currentContext!);
|
|
||||||
showConfirmDialogAction(
|
|
||||||
currentContext!,
|
|
||||||
appLocalizations.messageWarningDialogWhenExpiredOIDCTokenAndReconnection,
|
|
||||||
appLocalizations.saveAndRefresh,
|
|
||||||
title: appLocalizations.sessionExpired,
|
|
||||||
cancelTitle: appLocalizations.no,
|
|
||||||
alignCenter: true,
|
|
||||||
outsideDismissible: false,
|
|
||||||
titleActionButtonMaxLines: 1,
|
|
||||||
icon: SvgPicture.asset(imagePaths.icTMailLogo, width: 64, height: 64),
|
|
||||||
onConfirmAction: () {
|
|
||||||
twakeAppManager.setSessionExpiresDialogDisplayState(false);
|
|
||||||
_performSaveAndReconnection();
|
|
||||||
},
|
|
||||||
onCancelAction: () {
|
|
||||||
twakeAppManager.setSessionExpiresDialogDisplayState(false);
|
|
||||||
_performReconnection();
|
|
||||||
},
|
|
||||||
onCloseButtonAction: () {
|
|
||||||
twakeAppManager.setSessionExpiresDialogDisplayState(false);
|
|
||||||
_performCloseReconnectionConfirmDialog();
|
|
||||||
}
|
|
||||||
).whenComplete(() => twakeAppManager.setSessionExpiresDialogDisplayState(false));
|
|
||||||
|
|
||||||
twakeAppManager.setSessionExpiresDialogDisplayState(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _performSaveAndReconnection() {
|
void _performSaveAndReconnection() {
|
||||||
@@ -273,10 +239,6 @@ abstract class BaseController extends GetxController
|
|||||||
clearDataAndGoToLoginPage();
|
clearDataAndGoToLoginPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _performCloseReconnectionConfirmDialog() {
|
|
||||||
popBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onDataFailureViewState(Failure failure) {
|
void onDataFailureViewState(Failure failure) {
|
||||||
log('$runtimeType::onDataFailureViewState:failure = ${failure.runtimeType}');
|
log('$runtimeType::onDataFailureViewState:failure = ${failure.runtimeType}');
|
||||||
if (failure is FeatureFailure) {
|
if (failure is FeatureFailure) {
|
||||||
|
|||||||
@@ -4064,12 +4064,6 @@
|
|||||||
"placeholders_order": [],
|
"placeholders_order": [],
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
"sessionExpired": "Session expired",
|
|
||||||
"@sessionExpired": {
|
|
||||||
"type": "text",
|
|
||||||
"placeholders_order": [],
|
|
||||||
"placeholders": {}
|
|
||||||
},
|
|
||||||
"sMimeGoodSignatureMessage": "The authenticity of this message had been verified with SMime signature.",
|
"sMimeGoodSignatureMessage": "The authenticity of this message had been verified with SMime signature.",
|
||||||
"@sMimeGoodSignatureMessage": {
|
"@sMimeGoodSignatureMessage": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -4238,12 +4232,6 @@
|
|||||||
"placeholders_order": [],
|
"placeholders_order": [],
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
"messageWarningDialogWhenExpiredOIDCTokenAndReconnection": "Your session expired. We need to take you back to the login page in order to refresh it. You might want to save the email you are currently editing before we do so.",
|
|
||||||
"@messageWarningDialogWhenExpiredOIDCTokenAndReconnection": {
|
|
||||||
"type": "text",
|
|
||||||
"placeholders_order": [],
|
|
||||||
"placeholders": {}
|
|
||||||
},
|
|
||||||
"replyToList": "Reply to list",
|
"replyToList": "Reply to list",
|
||||||
"@replyToList": {
|
"@replyToList": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -4280,12 +4268,6 @@
|
|||||||
"placeholders_order": [],
|
"placeholders_order": [],
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
"saveAndRefresh": "Save & refresh",
|
|
||||||
"@saveAndRefresh": {
|
|
||||||
"type": "text",
|
|
||||||
"placeholders_order": [],
|
|
||||||
"placeholders": {}
|
|
||||||
},
|
|
||||||
"thisHtmlAttachmentCannotBePreviewed": "This html attachment cannot be previewed",
|
"thisHtmlAttachmentCannotBePreviewed": "This html attachment cannot be previewed",
|
||||||
"@thisHtmlAttachmentCannotBePreviewed": {
|
"@thisHtmlAttachmentCannotBePreviewed": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
@@ -4242,13 +4242,6 @@ class AppLocalizations {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String get sessionExpired {
|
|
||||||
return Intl.message(
|
|
||||||
'Session expired',
|
|
||||||
name: 'sessionExpired',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String get sMimeGoodSignatureMessage {
|
String get sMimeGoodSignatureMessage {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
'The authenticity of this message had been verified with SMime signature.',
|
'The authenticity of this message had been verified with SMime signature.',
|
||||||
@@ -4436,14 +4429,6 @@ class AppLocalizations {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String get messageWarningDialogWhenExpiredOIDCTokenAndReconnection {
|
|
||||||
return Intl.message(
|
|
||||||
'Your session expired. We need to take you back to the login page in order to refresh it. You might want to save the email you are currently editing before we do so.',
|
|
||||||
name: 'messageWarningDialogWhenExpiredOIDCTokenAndReconnection',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
String get replyToList {
|
String get replyToList {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
'Reply to list',
|
'Reply to list',
|
||||||
@@ -4486,13 +4471,6 @@ class AppLocalizations {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String get saveAndRefresh {
|
|
||||||
return Intl.message(
|
|
||||||
'Save & refresh',
|
|
||||||
name: 'saveAndRefresh',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String get thisHtmlAttachmentCannotBePreviewed {
|
String get thisHtmlAttachmentCannotBePreviewed {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
'This html attachment cannot be previewed',
|
'This html attachment cannot be previewed',
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
|
|
||||||
class TwakeAppManager {
|
class TwakeAppManager {
|
||||||
bool _hasComposer = false;
|
bool _hasComposer = false;
|
||||||
bool _isSessionExpiresDialogOpened = false;
|
|
||||||
|
|
||||||
void setHasComposer(bool value) => _hasComposer = value;
|
void setHasComposer(bool value) => _hasComposer = value;
|
||||||
|
|
||||||
bool get hasComposer => _hasComposer;
|
bool get hasComposer => _hasComposer;
|
||||||
|
|
||||||
void setSessionExpiresDialogDisplayState(bool value) => _isSessionExpiresDialogOpened = value;
|
|
||||||
|
|
||||||
bool get isSessionExpiresDialogOpened => _isSessionExpiresDialogOpened;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user