TF-2119 Disable drag and drop recipients on mobile

(cherry picked from commit d1760dbdbac30a3af13fd6a7dca97236484dbd9a)
This commit is contained in:
dab246
2023-09-15 00:46:35 +07:00
committed by Dat H. Pham
parent e1dd99c613
commit c3a6d0f4d8
3 changed files with 218 additions and 124 deletions
@@ -118,7 +118,6 @@ class ComposerView extends GetWidget<ComposerController> {
onUpdateListEmailAddressAction: controller.updateListEmailAddress, onUpdateListEmailAddressAction: controller.updateListEmailAddress,
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
onFocusNextAddressAction: controller.handleFocusNextAddressAction, onFocusNextAddressAction: controller.handleFocusNextAddressAction,
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
), ),
if (controller.ccRecipientState.value == PrefixRecipientState.enabled) if (controller.ccRecipientState.value == PrefixRecipientState.enabled)
RecipientComposerWidget( RecipientComposerWidget(
@@ -139,7 +138,6 @@ class ComposerView extends GetWidget<ComposerController> {
onUpdateListEmailAddressAction: controller.updateListEmailAddress, onUpdateListEmailAddressAction: controller.updateListEmailAddress,
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
onFocusNextAddressAction: controller.handleFocusNextAddressAction, onFocusNextAddressAction: controller.handleFocusNextAddressAction,
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
), ),
if (controller.bccRecipientState.value == PrefixRecipientState.enabled) if (controller.bccRecipientState.value == PrefixRecipientState.enabled)
RecipientComposerWidget( RecipientComposerWidget(
@@ -160,7 +158,6 @@ class ComposerView extends GetWidget<ComposerController> {
onUpdateListEmailAddressAction: controller.updateListEmailAddress, onUpdateListEmailAddressAction: controller.updateListEmailAddress,
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
onFocusNextAddressAction: controller.handleFocusNextAddressAction, onFocusNextAddressAction: controller.handleFocusNextAddressAction,
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
), ),
], ],
)), )),
@@ -262,7 +259,6 @@ class ComposerView extends GetWidget<ComposerController> {
onUpdateListEmailAddressAction: controller.updateListEmailAddress, onUpdateListEmailAddressAction: controller.updateListEmailAddress,
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
onFocusNextAddressAction: controller.handleFocusNextAddressAction, onFocusNextAddressAction: controller.handleFocusNextAddressAction,
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
), ),
if (controller.ccRecipientState.value == PrefixRecipientState.enabled) if (controller.ccRecipientState.value == PrefixRecipientState.enabled)
RecipientComposerWidget( RecipientComposerWidget(
@@ -283,7 +279,6 @@ class ComposerView extends GetWidget<ComposerController> {
onUpdateListEmailAddressAction: controller.updateListEmailAddress, onUpdateListEmailAddressAction: controller.updateListEmailAddress,
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
onFocusNextAddressAction: controller.handleFocusNextAddressAction, onFocusNextAddressAction: controller.handleFocusNextAddressAction,
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
), ),
if (controller.bccRecipientState.value == PrefixRecipientState.enabled) if (controller.bccRecipientState.value == PrefixRecipientState.enabled)
RecipientComposerWidget( RecipientComposerWidget(
@@ -304,7 +299,6 @@ class ComposerView extends GetWidget<ComposerController> {
onUpdateListEmailAddressAction: controller.updateListEmailAddress, onUpdateListEmailAddressAction: controller.updateListEmailAddress,
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
onFocusNextAddressAction: controller.handleFocusNextAddressAction, onFocusNextAddressAction: controller.handleFocusNextAddressAction,
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
), ),
], ],
)), )),
@@ -5,6 +5,7 @@ import 'package:collection/collection.dart';
import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -146,82 +147,143 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
}, },
child: StatefulBuilder( child: StatefulBuilder(
builder: (context, stateSetter) { builder: (context, stateSetter) {
return DragTarget<DraggableEmailAddress>( if (PlatformInfo.isWeb) {
builder: (context, candidateData, rejectedData) { return DragTarget<DraggableEmailAddress>(
return TagEditor<SuggestionEmailAddress>( builder: (context, candidateData, rejectedData) {
key: widget.keyTagEditor, return TagEditor<SuggestionEmailAddress>(
length: _collapsedListEmailAddress.length, key: widget.keyTagEditor,
controller: widget.controller, length: _collapsedListEmailAddress.length,
focusNode: widget.focusNode, controller: widget.controller,
enableBorder: _isDragging, focusNode: widget.focusNode,
borderRadius: RecipientComposerWidgetStyle.enableBorderRadius, enableBorder: _isDragging,
enableBorderColor: RecipientComposerWidgetStyle.enableBorderColor, borderRadius: RecipientComposerWidgetStyle.enableBorderRadius,
autoDisposeFocusNode: widget.autoDisposeFocusNode, enableBorderColor: RecipientComposerWidgetStyle.enableBorderColor,
keyboardType: TextInputType.emailAddress, autoDisposeFocusNode: widget.autoDisposeFocusNode,
textInputAction: TextInputAction.done, keyboardType: TextInputType.emailAddress,
debounceDuration: const Duration(milliseconds: 150), textInputAction: TextInputAction.done,
hasAddButton: false, debounceDuration: const Duration(milliseconds: 150),
tagSpacing: 8, hasAddButton: false,
autofocus: widget.prefix != PrefixEmailAddress.to && _currentListEmailAddress.isEmpty, tagSpacing: 8,
minTextFieldWidth: 20, autofocus: widget.prefix != PrefixEmailAddress.to && _currentListEmailAddress.isEmpty,
resetTextOnSubmitted: true, minTextFieldWidth: 20,
suggestionsBoxElevation: 20.0, resetTextOnSubmitted: true,
suggestionsBoxBackgroundColor: Colors.white, suggestionsBoxElevation: 20.0,
suggestionsBoxRadius: 20, suggestionsBoxBackgroundColor: Colors.white,
suggestionsBoxMaxHeight: 350, suggestionsBoxRadius: 20,
textStyle: RecipientComposerWidgetStyle.inputTextStyle, suggestionsBoxMaxHeight: 350,
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter), textStyle: RecipientComposerWidgetStyle.inputTextStyle,
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter), onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter), onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter), onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
inputDecoration: const InputDecoration(border: InputBorder.none), onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
tagBuilder: (context, index) { inputDecoration: const InputDecoration(border: InputBorder.none),
final currentEmailAddress = _currentListEmailAddress[index]; tagBuilder: (context, index) {
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last; final currentEmailAddress = _currentListEmailAddress[index];
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
return RecipientTagItemWidget( return RecipientTagItemWidget(
prefix: widget.prefix, prefix: widget.prefix,
currentEmailAddress: currentEmailAddress, currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress, currentListEmailAddress: _currentListEmailAddress,
collapsedListEmailAddress: _collapsedListEmailAddress, collapsedListEmailAddress: _collapsedListEmailAddress,
isLatestEmail: isLatestEmail, isLatestEmail: isLatestEmail,
isCollapsed: _isCollapse, isCollapsed: _isCollapse,
isLatestTagFocused: _lastTagFocused, isLatestTagFocused: _lastTagFocused,
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter), onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
onShowFullAction: widget.onShowFullListEmailAddressAction, onShowFullAction: widget.onShowFullListEmailAddressAction,
); );
}, },
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter), onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
findSuggestions: _findSuggestions, findSuggestions: _findSuggestions,
useDefaultHighlight: false, useDefaultHighlight: false,
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) { suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
return RecipientSuggestionItemWidget( return RecipientSuggestionItemWidget(
suggestionState: suggestionEmailAddress.state, suggestionState: suggestionEmailAddress.state,
emailAddress: suggestionEmailAddress.emailAddress, emailAddress: suggestionEmailAddress.emailAddress,
suggestionValid: suggestionValid, suggestionValid: suggestionValid,
highlight: highlight, highlight: highlight,
onSelectedAction: (emailAddress) { onSelectedAction: (emailAddress) {
stateSetter(() => _currentListEmailAddress.add(emailAddress)); stateSetter(() => _currentListEmailAddress.add(emailAddress));
_updateListEmailAddressAction(); _updateListEmailAddressAction();
tagEditorState.resetTextField(); tagEditorState.resetTextField();
tagEditorState.closeSuggestionBox(); tagEditorState.closeSuggestionBox();
}, },
); );
}, },
); );
}, },
onAccept: (draggableEmailAddress) => _handleAcceptDraggableEmailAddressAction(draggableEmailAddress, stateSetter), onAccept: (draggableEmailAddress) => _handleAcceptDraggableEmailAddressAction(draggableEmailAddress, stateSetter),
onLeave: (draggableEmailAddress) { onLeave: (draggableEmailAddress) {
if (_isDragging) { if (_isDragging) {
stateSetter(() => _isDragging = false); stateSetter(() => _isDragging = false);
} }
}, },
onMove: (details) { onMove: (details) {
if (!_isDragging) { if (!_isDragging) {
stateSetter(() => _isDragging = true); stateSetter(() => _isDragging = true);
} }
}, },
); );
} else {
return TagEditor<SuggestionEmailAddress>(
key: widget.keyTagEditor,
length: _collapsedListEmailAddress.length,
controller: widget.controller,
focusNode: widget.focusNode,
autoDisposeFocusNode: widget.autoDisposeFocusNode,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.done,
debounceDuration: const Duration(milliseconds: 150),
hasAddButton: false,
tagSpacing: 8,
autofocus: widget.prefix != PrefixEmailAddress.to && _currentListEmailAddress.isEmpty,
minTextFieldWidth: 20,
resetTextOnSubmitted: true,
suggestionsBoxElevation: 20.0,
suggestionsBoxBackgroundColor: Colors.white,
suggestionsBoxRadius: 20,
suggestionsBoxMaxHeight: 350,
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
inputDecoration: const InputDecoration(border: InputBorder.none),
tagBuilder: (context, index) {
final currentEmailAddress = _currentListEmailAddress[index];
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
return RecipientTagItemWidget(
prefix: widget.prefix,
currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress,
collapsedListEmailAddress: _collapsedListEmailAddress,
isLatestEmail: isLatestEmail,
isCollapsed: _isCollapse,
isLatestTagFocused: _lastTagFocused,
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
onShowFullAction: widget.onShowFullListEmailAddressAction,
);
},
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
findSuggestions: _findSuggestions,
useDefaultHighlight: false,
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
return RecipientSuggestionItemWidget(
suggestionState: suggestionEmailAddress.state,
emailAddress: suggestionEmailAddress.emailAddress,
suggestionValid: suggestionValid,
highlight: highlight,
onSelectedAction: (emailAddress) {
stateSetter(() => _currentListEmailAddress.add(emailAddress));
_updateListEmailAddressAction();
tagEditorState.resetTextField();
tagEditorState.closeSuggestionBox();
},
);
},
);
}
}, },
) )
) )
@@ -49,52 +49,90 @@ class RecipientTagItemWidget extends StatelessWidget {
return Stack( return Stack(
alignment: AlignmentDirectional.centerEnd, alignment: AlignmentDirectional.centerEnd,
children: [ children: [
Padding( if (PlatformInfo.isWeb)
padding: EdgeInsetsDirectional.only( Padding(
top: PlatformInfo.isWeb ? 8 : 0, padding: EdgeInsetsDirectional.only(
end: isCollapsed ? 40 : 0), top: 8,
child: InkWell( end: isCollapsed ? 40 : 0),
onTap: () => isCollapsed child: InkWell(
? onShowFullAction?.call(prefix) onTap: () => isCollapsed
: null, ? onShowFullAction?.call(prefix)
child: Draggable<DraggableEmailAddress>( : null,
data: DraggableEmailAddress(emailAddress: currentEmailAddress, prefix: prefix), child: Draggable<DraggableEmailAddress>(
feedback: DraggableRecipientTagWidget(emailAddress: currentEmailAddress), data: DraggableEmailAddress(emailAddress: currentEmailAddress, prefix: prefix),
childWhenDragging: DraggableRecipientTagWidget(emailAddress: currentEmailAddress), feedback: DraggableRecipientTagWidget(emailAddress: currentEmailAddress),
child: MouseRegion( childWhenDragging: DraggableRecipientTagWidget(emailAddress: currentEmailAddress),
cursor: SystemMouseCursors.grab, child: MouseRegion(
child: Chip( cursor: SystemMouseCursors.grab,
labelPadding: EdgeInsetsDirectional.symmetric( child: Chip(
horizontal: 4, labelPadding: EdgeInsetsDirectional.symmetric(
vertical: DirectionUtils.isDirectionRTLByHasAnyRtl(currentEmailAddress.asString()) ? 0 : 2 horizontal: 4,
vertical: DirectionUtils.isDirectionRTLByHasAnyRtl(currentEmailAddress.asString()) ? 0 : 2
),
label: Text(
currentEmailAddress.asString(),
maxLines: 1,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
),
deleteIcon: SvgPicture.asset(_imagePaths.icClose, fit: BoxFit.fill),
labelStyle: RecipientTagItemWidgetStyle.labelTextStyle,
backgroundColor: _getTagBackgroundColor(),
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(RecipientTagItemWidgetStyle.radius)),
side: _getTagBorderSide(),
),
avatar: currentEmailAddress.displayName.isNotEmpty
? GradientCircleAvatarIcon(
colors: currentEmailAddress.avatarColors,
label: currentEmailAddress.displayName.firstLetterToUpperCase,
labelFontSize: RecipientTagItemWidgetStyle.avatarLabelFontSize,
iconSize: RecipientTagItemWidgetStyle.avatarIconSize,
)
: null,
onDeleted: () => onDeleteTagAction?.call(currentEmailAddress),
), ),
label: Text(
currentEmailAddress.asString(),
maxLines: 1,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
),
deleteIcon: SvgPicture.asset(_imagePaths.icClose, fit: BoxFit.fill),
labelStyle: RecipientTagItemWidgetStyle.labelTextStyle,
backgroundColor: _getTagBackgroundColor(),
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(RecipientTagItemWidgetStyle.radius)),
side: _getTagBorderSide(),
),
avatar: currentEmailAddress.displayName.isNotEmpty
? GradientCircleAvatarIcon(
colors: currentEmailAddress.avatarColors,
label: currentEmailAddress.displayName.firstLetterToUpperCase,
labelFontSize: RecipientTagItemWidgetStyle.avatarLabelFontSize,
iconSize: RecipientTagItemWidgetStyle.avatarIconSize,
)
: null,
onDeleted: () => onDeleteTagAction?.call(currentEmailAddress),
), ),
), )
) ),
)
else
Padding(
padding: EdgeInsetsDirectional.only(end: isCollapsed ? 40 : 0),
child: InkWell(
onTap: () => isCollapsed
? onShowFullAction?.call(prefix)
: null,
child: Chip(
labelPadding: EdgeInsetsDirectional.symmetric(
horizontal: 4,
vertical: DirectionUtils.isDirectionRTLByHasAnyRtl(currentEmailAddress.asString()) ? 0 : 2
),
label: Text(
currentEmailAddress.asString(),
maxLines: 1,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
),
deleteIcon: SvgPicture.asset(_imagePaths.icClose, fit: BoxFit.fill),
labelStyle: RecipientTagItemWidgetStyle.labelTextStyle,
backgroundColor: _getTagBackgroundColor(),
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(RecipientTagItemWidgetStyle.radius)),
side: _getTagBorderSide(),
),
avatar: currentEmailAddress.displayName.isNotEmpty
? GradientCircleAvatarIcon(
colors: currentEmailAddress.avatarColors,
label: currentEmailAddress.displayName.firstLetterToUpperCase,
labelFontSize: RecipientTagItemWidgetStyle.avatarLabelFontSize,
iconSize: RecipientTagItemWidgetStyle.avatarIconSize,
)
: null,
onDeleted: () => onDeleteTagAction?.call(currentEmailAddress),
)
),
), ),
),
if (isCollapsed) if (isCollapsed)
TMailButtonWidget.fromText( TMailButtonWidget.fromText(
margin: RecipientTagItemWidgetStyle.counterMargin, margin: RecipientTagItemWidgetStyle.counterMargin,