TF-4011 Support arrow keys on keyboard to get again focus after deleting a recipient
This commit is contained in:
+11
-10
@@ -83,7 +83,7 @@ class _DefaultAutocompleteInputFieldWidgetState
|
||||
extends State<DefaultAutocompleteInputFieldWidget> {
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
bool _lastTagFocused = false;
|
||||
int _tagIndexFocused = -1;
|
||||
bool _isDragging = false;
|
||||
late List<EmailAddress> _currentListEmailAddress;
|
||||
Timer? _gapBetweenTagChangedAndFindSuggestion;
|
||||
@@ -157,17 +157,14 @@ class _DefaultAutocompleteInputFieldWidgetState
|
||||
onSubmitted: _handleSubmitTagAction,
|
||||
tagBuilder: (context, index) {
|
||||
final currentEmailAddress = _currentListEmailAddress.elementAt(index);
|
||||
final isLatestEmail =
|
||||
currentEmailAddress == _currentListEmailAddress.last;
|
||||
return DefaultAutocompleteTagItemWidget(
|
||||
field: widget.field,
|
||||
currentEmailAddress: currentEmailAddress,
|
||||
currentListEmailAddress: _currentListEmailAddress,
|
||||
collapsedListEmailAddress: _collapsedListEmailAddress,
|
||||
iconClose: _imagePaths.icClose,
|
||||
isLatestEmail: isLatestEmail,
|
||||
isCollapsed: _isCollapse,
|
||||
isLatestTagFocused: _lastTagFocused,
|
||||
isTagFocused: _tagIndexFocused == index,
|
||||
onDeleteTagAction: _handleDeleteTagAction,
|
||||
onShowFullAction: widget.onShowFullListEmailAddressAction,
|
||||
);
|
||||
@@ -335,13 +332,17 @@ class _DefaultAutocompleteInputFieldWidgetState
|
||||
);
|
||||
}
|
||||
|
||||
void _handleFocusTagAction(bool focused) {
|
||||
_setStateSafety(() => _lastTagFocused = focused);
|
||||
void _handleFocusTagAction(int index) {
|
||||
_setStateSafety(() => _tagIndexFocused = index);
|
||||
}
|
||||
|
||||
void _handleDeleteLatestTagAction() {
|
||||
if (_currentListEmailAddress.isNotEmpty) {
|
||||
_setStateSafety(_currentListEmailAddress.removeLast);
|
||||
void _handleDeleteLatestTagAction(int index) {
|
||||
if (_currentListEmailAddress.isNotEmpty &&
|
||||
index >= 0 &&
|
||||
index < _currentListEmailAddress.length) {
|
||||
_setStateSafety(() {
|
||||
_currentListEmailAddress.removeAt(index);
|
||||
});
|
||||
_updateListEmailAddressAction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/ad
|
||||
class DefaultAutocompleteTagItemWidget extends StatelessWidget {
|
||||
|
||||
final bool isCollapsed;
|
||||
final bool isLatestTagFocused;
|
||||
final bool isLatestEmail;
|
||||
final bool isTagFocused;
|
||||
final FilterField field;
|
||||
final EmailAddress currentEmailAddress;
|
||||
final String iconClose;
|
||||
@@ -34,8 +33,7 @@ class DefaultAutocompleteTagItemWidget extends StatelessWidget {
|
||||
required this.collapsedListEmailAddress,
|
||||
required this.iconClose,
|
||||
this.isCollapsed = false,
|
||||
this.isLatestTagFocused = false,
|
||||
this.isLatestEmail = false,
|
||||
this.isTagFocused = false,
|
||||
this.onDeleteTagAction,
|
||||
this.onShowFullAction,
|
||||
}) : super(key: key);
|
||||
@@ -141,7 +139,7 @@ class DefaultAutocompleteTagItemWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
Color _getTagBackgroundColor() {
|
||||
if (isLatestTagFocused && isLatestEmail) {
|
||||
if (isTagFocused) {
|
||||
return AppColor.colorItemRecipientSelected;
|
||||
} else {
|
||||
return AppColor.colorEmailAddressTag;
|
||||
@@ -149,7 +147,7 @@ class DefaultAutocompleteTagItemWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
BorderSide _getTagBorderSide() {
|
||||
if (isLatestTagFocused && isLatestEmail) {
|
||||
if (isTagFocused) {
|
||||
return const BorderSide(width: 1, color: AppColor.primaryColor);
|
||||
} else {
|
||||
return const BorderSide(width: 0, color: AppColor.colorEmailAddressTag);
|
||||
|
||||
@@ -126,7 +126,7 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
Timer? _gapBetweenTagChangedAndFindSuggestion;
|
||||
bool _lastTagFocused = false;
|
||||
int _tagIndexFocused = -1;
|
||||
bool _isDragging = false;
|
||||
late List<EmailAddress> _currentListEmailAddress;
|
||||
|
||||
@@ -204,8 +204,8 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
suggestionItemHeight: RecipientComposerWidgetStyle.suggestionBoxItemHeight,
|
||||
suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth),
|
||||
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
|
||||
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
|
||||
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
|
||||
onFocusTagAction: (index) => _handleFocusTagAction.call(index, stateSetter),
|
||||
onDeleteTagAction: (index) => _handleDeleteLatestTagAction.call(index, stateSetter),
|
||||
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
|
||||
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
|
||||
onTapOutside: (_) {},
|
||||
@@ -217,7 +217,6 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
inputDecoration: const InputDecoration(border: InputBorder.none),
|
||||
tagBuilder: (context, index) {
|
||||
final currentEmailAddress = _currentListEmailAddress[index];
|
||||
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
|
||||
|
||||
return RecipientTagItemWidget(
|
||||
index: index,
|
||||
@@ -227,9 +226,8 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
currentEmailAddress: currentEmailAddress,
|
||||
currentListEmailAddress: _currentListEmailAddress,
|
||||
collapsedListEmailAddress: _collapsedListEmailAddress,
|
||||
isLatestEmail: isLatestEmail,
|
||||
isCollapsed: _isCollapse,
|
||||
isLatestTagFocused: _lastTagFocused,
|
||||
isTagFocused: _tagIndexFocused == index,
|
||||
maxWidth: widget.maxWidth,
|
||||
isMobile: _responsiveUtils.isMobile(context),
|
||||
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
|
||||
@@ -299,8 +297,8 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
suggestionItemHeight: RecipientComposerWidgetStyle.suggestionBoxItemHeight,
|
||||
suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth),
|
||||
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
|
||||
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
|
||||
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
|
||||
onFocusTagAction: (index) => _handleFocusTagAction.call(index, stateSetter),
|
||||
onDeleteTagAction: (index) => _handleDeleteLatestTagAction.call(index, stateSetter),
|
||||
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
|
||||
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
|
||||
onTapOutside: (_) {},
|
||||
@@ -312,7 +310,6 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
inputDecoration: const InputDecoration(border: InputBorder.none),
|
||||
tagBuilder: (context, index) {
|
||||
final currentEmailAddress = _currentListEmailAddress[index];
|
||||
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
|
||||
|
||||
return RecipientTagItemWidget(
|
||||
index: index,
|
||||
@@ -322,9 +319,8 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
currentEmailAddress: currentEmailAddress,
|
||||
currentListEmailAddress: _currentListEmailAddress,
|
||||
collapsedListEmailAddress: _collapsedListEmailAddress,
|
||||
isLatestEmail: isLatestEmail,
|
||||
isCollapsed: _isCollapse,
|
||||
isLatestTagFocused: _lastTagFocused,
|
||||
isTagFocused: _tagIndexFocused == index,
|
||||
maxWidth: widget.maxWidth,
|
||||
isMobile: _responsiveUtils.isMobile(context),
|
||||
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
|
||||
@@ -525,13 +521,17 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleFocusTagAction(bool focused, StateSetter stateSetter) {
|
||||
stateSetter(() => _lastTagFocused = focused);
|
||||
void _handleFocusTagAction(int index, StateSetter stateSetter) {
|
||||
stateSetter(() => _tagIndexFocused = index);
|
||||
}
|
||||
|
||||
void _handleDeleteLatestTagAction(StateSetter stateSetter) {
|
||||
if (_currentListEmailAddress.isNotEmpty) {
|
||||
stateSetter(_currentListEmailAddress.removeLast);
|
||||
void _handleDeleteLatestTagAction(int index, StateSetter stateSetter) {
|
||||
if (_currentListEmailAddress.isNotEmpty &&
|
||||
index >= 0 &&
|
||||
index < _currentListEmailAddress.length) {
|
||||
stateSetter(() {
|
||||
_currentListEmailAddress.removeAt(index);
|
||||
});
|
||||
_updateListEmailAddressAction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart
|
||||
class RecipientTagItemWidget extends StatelessWidget {
|
||||
|
||||
final bool isCollapsed;
|
||||
final bool isLatestTagFocused;
|
||||
final bool isLatestEmail;
|
||||
final bool isTagFocused;
|
||||
final ImagePaths imagePaths;
|
||||
final double? maxWidth;
|
||||
final int index;
|
||||
@@ -50,8 +49,7 @@ class RecipientTagItemWidget extends StatelessWidget {
|
||||
required this.imagePaths,
|
||||
@visibleForTesting this.isTestingForWeb = false,
|
||||
this.isCollapsed = false,
|
||||
this.isLatestTagFocused = false,
|
||||
this.isLatestEmail = false,
|
||||
this.isTagFocused = false,
|
||||
this.isMobile = false,
|
||||
this.onShowFullAction,
|
||||
this.onDeleteTagAction,
|
||||
@@ -195,7 +193,7 @@ class RecipientTagItemWidget extends StatelessWidget {
|
||||
int get countRecipients => currentListEmailAddress.length - collapsedListEmailAddress.length;
|
||||
|
||||
Color _getTagBackgroundColor() {
|
||||
if (isLatestTagFocused && isLatestEmail) {
|
||||
if (isTagFocused) {
|
||||
return AppColor.colorItemRecipientSelected;
|
||||
} else if (EmailUtils.isEmailAddressValid(currentEmailAddress.emailAddress)) {
|
||||
return AppColor.grayBackgroundColor;
|
||||
@@ -205,7 +203,7 @@ class RecipientTagItemWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
BorderSide _getTagBorderSide() {
|
||||
if (isLatestTagFocused && isLatestEmail) {
|
||||
if (isTagFocused) {
|
||||
return const BorderSide(width: 1, color: AppColor.primaryColor);
|
||||
} else if (EmailUtils.isEmailAddressValid(currentEmailAddress.emailAddress)) {
|
||||
return const BorderSide(width: 1, color: AppColor.colorEmailAddressTag);
|
||||
|
||||
@@ -18,16 +18,14 @@ typedef DeleteContactCallbackAction = Function(EmailAddress contactDeleted);
|
||||
class ContactInputTagItem extends StatelessWidget {
|
||||
|
||||
final EmailAddress contact;
|
||||
final bool isLastContact;
|
||||
final bool lastTagFocused;
|
||||
final bool isTagFocused;
|
||||
final DeleteContactCallbackAction? deleteContactCallbackAction;
|
||||
|
||||
const ContactInputTagItem(
|
||||
this.contact,
|
||||
{
|
||||
Key? key,
|
||||
this.isLastContact = false,
|
||||
this.lastTagFocused = false,
|
||||
this.isTagFocused = false,
|
||||
this.deleteContactCallbackAction
|
||||
}
|
||||
) : super(key: key);
|
||||
@@ -97,7 +95,7 @@ class ContactInputTagItem extends StatelessWidget {
|
||||
bool _isValidEmailAddress(String value) => value.isEmail || AppUtils.isEmailLocalhost(value);
|
||||
|
||||
Color _getTagBackgroundColor() {
|
||||
if (lastTagFocused && isLastContact) {
|
||||
if (isTagFocused) {
|
||||
return AppColor.colorItemRecipientSelected;
|
||||
} else {
|
||||
return _isValidEmailAddress(contact.emailAddress)
|
||||
@@ -107,7 +105,7 @@ class ContactInputTagItem extends StatelessWidget {
|
||||
}
|
||||
|
||||
BorderSide _getTagBorderSide() {
|
||||
if (lastTagFocused && isLastContact) {
|
||||
if (isTagFocused) {
|
||||
return const BorderSide(
|
||||
width: 1,
|
||||
color: AppColor.primaryColor);
|
||||
|
||||
+9
-8
@@ -67,7 +67,7 @@ class _AutocompleteContactTextFieldWithTagsState extends State<AutocompleteConta
|
||||
|
||||
late List<EmailAddress> listEmailAddress;
|
||||
|
||||
bool lastTagFocused = false;
|
||||
int _tagIndexFocused = -1;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -107,15 +107,17 @@ class _AutocompleteContactTextFieldWithTagsState extends State<AutocompleteConta
|
||||
suggestionsBoxBackgroundColor: Colors.white,
|
||||
suggestionsBoxRadius: 16,
|
||||
suggestionsBoxMaxHeight: 350,
|
||||
onFocusTagAction: (focused) {
|
||||
onFocusTagAction: (index) {
|
||||
setState(() {
|
||||
lastTagFocused = focused;
|
||||
_tagIndexFocused = index;
|
||||
});
|
||||
},
|
||||
onDeleteTagAction: () {
|
||||
if (listEmailAddress.isNotEmpty) {
|
||||
onDeleteTagAction: (index) {
|
||||
if (listEmailAddress.isNotEmpty &&
|
||||
index >= 0 &&
|
||||
index < listEmailAddress.length) {
|
||||
setState(() {
|
||||
listEmailAddress.removeLast();
|
||||
listEmailAddress.removeAt(index);
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -136,8 +138,7 @@ class _AutocompleteContactTextFieldWithTagsState extends State<AutocompleteConta
|
||||
),
|
||||
tagBuilder: (context, index) => ContactInputTagItem(
|
||||
listEmailAddress[index],
|
||||
isLastContact: index == listEmailAddress.length - 1,
|
||||
lastTagFocused: lastTagFocused,
|
||||
isTagFocused: _tagIndexFocused == index,
|
||||
deleteContactCallbackAction: (contact) {
|
||||
setState(() => listEmailAddress.remove(contact));
|
||||
}
|
||||
|
||||
+2
-2
@@ -2083,10 +2083,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: super_tag_editor
|
||||
sha256: "291b4b5ef5c44d1d06dc0337f66b71f7afd77b8c98d0ad0f4f8baca6a6f3cbc4"
|
||||
sha256: fbf81653bc01a89e6fe63b9ae01cc12d557020cf74c870ed49e8e406ad710aac
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
version: "0.3.3"
|
||||
syncfusion_flutter_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ dependencies:
|
||||
ref: master
|
||||
|
||||
### Dependencies from pub.dev ###
|
||||
super_tag_editor: 0.3.2
|
||||
super_tag_editor: 0.3.3
|
||||
|
||||
cupertino_icons: 1.0.6
|
||||
|
||||
|
||||
Reference in New Issue
Block a user