TF-248 Update UI and Action for selection multiple email

This commit is contained in:
dab246
2022-02-09 13:00:49 +07:00
committed by Dat H. Pham
parent 879692aa54
commit a48f508171
22 changed files with 443 additions and 155 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.5 2C9.31434 2.0001 9.13237 2.05188 8.97447 2.14955C8.81658 2.24722 8.68899 2.38692 8.606 2.553L7.882 4H4.5C4.23478 4 3.98043 4.10536 3.79289 4.29289C3.60536 4.48043 3.5 4.73478 3.5 5C3.5 5.26522 3.60536 5.51957 3.79289 5.70711C3.98043 5.89464 4.23478 6 4.5 6V16C4.5 16.5304 4.71071 17.0391 5.08579 17.4142C5.46086 17.7893 5.96957 18 6.5 18H14.5C15.0304 18 15.5391 17.7893 15.9142 17.4142C16.2893 17.0391 16.5 16.5304 16.5 16V6C16.7652 6 17.0196 5.89464 17.2071 5.70711C17.3946 5.51957 17.5 5.26522 17.5 5C17.5 4.73478 17.3946 4.48043 17.2071 4.29289C17.0196 4.10536 16.7652 4 16.5 4H13.118L12.394 2.553C12.311 2.38692 12.1834 2.24722 12.0255 2.14955C11.8676 2.05188 11.6857 2.0001 11.5 2H9.5ZM7.5 8C7.5 7.73478 7.60536 7.48043 7.79289 7.29289C7.98043 7.10536 8.23478 7 8.5 7C8.76522 7 9.01957 7.10536 9.20711 7.29289C9.39464 7.48043 9.5 7.73478 9.5 8V14C9.5 14.2652 9.39464 14.5196 9.20711 14.7071C9.01957 14.8946 8.76522 15 8.5 15C8.23478 15 7.98043 14.8946 7.79289 14.7071C7.60536 14.5196 7.5 14.2652 7.5 14V8ZM12.5 7C12.2348 7 11.9804 7.10536 11.7929 7.29289C11.6054 7.48043 11.5 7.73478 11.5 8V14C11.5 14.2652 11.6054 14.5196 11.7929 14.7071C11.9804 14.8946 12.2348 15 12.5 15C12.7652 15 13.0196 14.8946 13.2071 14.7071C13.3946 14.5196 13.5 14.2652 13.5 14V8C13.5 7.73478 13.3946 7.48043 13.2071 7.29289C13.0196 7.10536 12.7652 7 12.5 7Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 6C3.5 5.20435 3.81607 4.44129 4.37868 3.87868C4.94129 3.31607 5.70435 3 6.5 3H16.5C16.6857 3 16.8678 3.05171 17.0257 3.14935C17.1837 3.24698 17.3114 3.38668 17.3944 3.55279C17.4775 3.71889 17.5126 3.90484 17.496 4.08981C17.4793 4.27477 17.4114 4.45143 17.3 4.6L14.75 8L17.3 11.4C17.4114 11.5486 17.4793 11.7252 17.496 11.9102C17.5126 12.0952 17.4775 12.2811 17.3944 12.4472C17.3114 12.6133 17.1837 12.753 17.0257 12.8506C16.8678 12.9483 16.6857 13 16.5 13H6.5C6.23478 13 5.98043 13.1054 5.79289 13.2929C5.60536 13.4804 5.5 13.7348 5.5 14V17C5.5 17.2652 5.39464 17.5196 5.20711 17.7071C5.01957 17.8946 4.76522 18 4.5 18C4.23478 18 3.98043 17.8946 3.79289 17.7071C3.60536 17.5196 3.5 17.2652 3.5 17V6Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 875 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.87874 3.27022C1.87874 2.66812 2.11792 2.09068 2.54367 1.66493C2.96942 1.23918 3.54686 1 4.14896 1H9.82451L12.0947 3.27022H17.7703C18.3724 3.27022 18.9498 3.5094 19.3756 3.93515C19.8013 4.3609 20.0405 4.93834 20.0405 5.54044V12.3511C20.0405 12.9532 19.8013 13.5306 19.3756 13.9564C18.9498 14.3821 18.3724 14.6213 17.7703 14.6213H11.6452C10.922 12.3187 8.77076 10.6485 6.22946 10.6485H2.44576C2.25439 10.6485 2.06524 10.6579 1.87874 10.6764V3.27022ZM2.13415 15.7163H7.26174L5.49063 17.4874C5.24298 17.7351 5.24298 18.1366 5.49063 18.3843C5.73828 18.6319 6.1398 18.6319 6.38745 18.3843L9.24112 15.5306C9.48877 15.2829 9.48877 14.8814 9.24112 14.6338L6.38745 11.7801C6.1398 11.5325 5.73828 11.5325 5.49063 11.7801C5.24298 12.0278 5.24298 12.4293 5.49063 12.6769L7.26174 14.448L2.13415 14.448C1.78392 14.448 1.5 14.732 1.5 15.0822C1.5 15.4324 1.78392 15.7163 2.13415 15.7163Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.9596 17.92C17.531 17.92 18.3924 17.0654 18.3924 15.501V8.85732C18.3924 7.3618 18.1237 7.07235 17.1243 6.36249L12.2036 2.74431C11.5213 2.255 11.0872 2 10.4462 2C9.81217 2 9.37799 2.255 8.69571 2.74431L3.77498 6.36249C2.78256 7.06545 2.5 7.3618 2.5 8.85732V15.501C2.5 17.0654 3.36147 17.92 4.9328 17.92H15.9596ZM12.3001 11.0627L11.9969 10.7594C11.48 10.2495 10.9631 10.0151 10.4049 10.0151C9.84663 10.0151 9.32975 10.2495 8.80597 10.7594L8.50274 11.0558L4.91901 7.49274L9.63988 3.97794C9.94312 3.75051 10.143 3.63335 10.4462 3.63335C10.7495 3.63335 10.9493 3.75051 11.2526 3.97794L15.9252 7.45829L12.3001 11.0627ZM16.7522 15.439L13.3339 12.0758L16.7522 8.67813V15.439ZM4.14024 15.3494V8.76083L7.47586 12.0689L4.14024 15.3494ZM15.5186 16.2453H5.29117L9.69501 11.8966C9.97068 11.6278 10.1774 11.5175 10.4049 11.5175C10.6323 11.5175 10.839 11.6209 11.1147 11.8966L15.5186 16.2453Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1010 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12C0 5.37258 5.37258 0 12 0ZM15.6954 8.49541L10.35 13.8408L8.30459 11.7954C7.77739 11.2682 6.92261 11.2682 6.39541 11.7954C5.8682 12.3226 5.8682 13.1774 6.39541 13.7046L9.39541 16.7046C9.92261 17.2318 10.7774 17.2318 11.3046 16.7046L17.6046 10.4046C18.1318 9.87739 18.1318 9.02261 17.6046 8.49541C17.0774 7.9682 16.2226 7.9682 15.6954 8.49541Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 558 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.5 9.5C18.5 9.89783 18.342 10.2794 18.0607 10.5607C17.7794 10.842 17.3978 11 17 11C16.6022 11 16.2206 10.842 15.9393 10.5607C15.658 10.2794 15.5 9.89783 15.5 9.5V3.5C15.5 3.10218 15.658 2.72064 15.9393 2.43934C16.2206 2.15804 16.6022 2 17 2C17.3978 2 17.7794 2.15804 18.0607 2.43934C18.342 2.72064 18.5 3.10218 18.5 3.5V9.5ZM14.5 9.667V4.237C14.5003 3.86544 14.397 3.50116 14.2018 3.18499C14.0067 2.86882 13.7273 2.61327 13.395 2.447L13.345 2.422C12.7892 2.14422 12.1763 1.99973 11.555 2H6.14C5.67747 1.99982 5.22918 2.15995 4.87145 2.45314C4.51371 2.74633 4.26866 3.15444 4.178 3.608L2.978 9.608C2.91999 9.89821 2.92712 10.1977 2.99886 10.4848C3.0706 10.7719 3.20516 11.0396 3.39285 11.2684C3.58054 11.4972 3.81667 11.6815 4.08422 11.808C4.35176 11.9346 4.64405 12.0001 4.94 12H8.5V16C8.5 16.5304 8.71072 17.0391 9.08579 17.4142C9.46086 17.7893 9.96957 18 10.5 18C10.7652 18 11.0196 17.8946 11.2071 17.7071C11.3946 17.5196 11.5 17.2652 11.5 17V16.333C11.5 15.4675 11.7807 14.6254 12.3 13.933L13.7 12.067C14.2193 11.3746 14.5 10.5325 14.5 9.667Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.5139 7.99074C17.7854 7.99074 18.8393 6.93686 18.8393 5.6586C18.8393 4.38714 17.7854 3.33325 16.5139 3.33325C15.2357 3.33325 14.1818 4.38714 14.1818 5.6586C14.1818 6.93686 15.2357 7.99074 16.5139 7.99074ZM15.5552 16.6666C16.9967 16.6666 17.8398 15.8167 17.8398 14.28V8.71826C17.3435 8.96303 16.7859 9.05142 16.2216 8.97663V13.7769L12.8559 10.4385L14.7937 8.53468C14.379 8.28991 14.0254 7.94994 13.767 7.55559L10.7074 10.5813C10.4354 10.8464 10.2314 10.9552 10.0071 10.9552C9.78268 10.9552 9.57871 10.8464 9.30674 10.5813L4.69684 6.01896H13.2095C13.1143 5.47502 13.1959 4.86988 13.4271 4.36674H4.45207C3.01063 4.36674 2.16072 5.20985 2.16072 6.75328V14.28C2.16072 15.8235 3.01063 16.6666 4.56086 16.6666H15.5552ZM3.77894 13.7905V7.12044L7.15137 10.4385L3.77894 13.7905ZM15.3717 15.0144H4.62885C4.60845 15.0144 4.59485 15.0076 4.58125 15.0076L8.17126 11.438L8.42963 11.6963C8.94637 12.1995 9.45632 12.4307 10.0071 12.4307C10.5578 12.4307 11.0677 12.1995 11.5777 11.6963L11.8429 11.438L15.4329 15.0076C15.4125 15.0076 15.3921 15.0144 15.3717 15.0144Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="11.5" stroke="#99A2AD"/>
</svg>

After

Width:  |  Height:  |  Size: 155 B

@@ -51,6 +51,14 @@ class ImagePaths {
String get icFilter => _getImagePath('ic_filter.svg');
String get icSearchBar => _getImagePath('ic_search_bar.svg');
String get icCompose => _getImagePath('ic_compose.svg');
String get icReadV2 => _getImagePath('ic_read_v2.svg');
String get icUnreadV2 => _getImagePath('ic_unread_v2.svg');
String get icSelectedV2 => _getImagePath('ic_selected_v2.svg');
String get icUnSelectedV2 => _getImagePath('ic_unselected_v2.svg');
String get icDeleteV2 => _getImagePath('ic_delete_v2.svg');
String get icSpamV2 => _getImagePath('ic_spam_v2.svg');
String get icMoveV2 => _getImagePath('ic_move_v2.svg');
String get icFlagV2 => _getImagePath('ic_flag_v2.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
@@ -13,10 +13,11 @@ class ButtonBuilder {
String? _icon;
String? _text;
double? _size;
double? _padding;
EdgeInsets? _paddingIcon;
bool? _isVertical;
Key? _key;
Color? _color;
Color? _iconColor;
TextStyle? _textStyle;
void key(Key key) {
_key = key;
@@ -26,12 +27,16 @@ class ButtonBuilder {
_size = size;
}
void color(Color color) {
_color = color;
void iconColor(Color color) {
_iconColor = color;
}
void padding(double padding) {
_padding = padding;
void textStyle(TextStyle style) {
_textStyle = style;
}
void paddingIcon(EdgeInsets paddingIcon) {
_paddingIcon = paddingIcon;
}
void text(String text, {required bool isVertical}) {
@@ -87,15 +92,15 @@ class ButtonBuilder {
}
Widget _buildIcon() => Padding(
padding: EdgeInsets.all(_padding ?? 10),
child: SvgPicture.asset(_icon ?? '', width: _size ?? 24, height: _size ?? 24, fit: BoxFit.fill, color: _color));
padding: _paddingIcon ?? EdgeInsets.all(10),
child: SvgPicture.asset(_icon ?? '', width: _size ?? 24, height: _size ?? 24, fit: BoxFit.fill, color: _iconColor));
Widget _buildText() {
return Text(
'${_text ?? ''}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12, color: AppColor.textButtonColor, fontWeight: FontWeight.w500),
style: _textStyle ?? TextStyle(fontSize: 12, color: AppColor.textButtonColor, fontWeight: FontWeight.w500),
);
}
}
@@ -103,16 +103,20 @@ class _ScrollingFloatingButtonAnimatedState
_scrollController.position.userScrollDirection ==
ScrollDirection.reverse) {
if (widget.animateIcon!) _animationController.forward();
setState(() {
_onTop = false;
});
if (mounted) {
setState(() {
_onTop = false;
});
}
} else if (_scrollController.position.pixels <= widget.limitIndicator! &&
_scrollController.position.userScrollDirection ==
ScrollDirection.forward) {
if (widget.animateIcon!) _animationController.reverse();
setState(() {
_onTop = true;
});
if (mounted) {
setState(() {
_onTop = true;
});
}
}
});
}
@@ -128,9 +132,11 @@ class _ScrollingFloatingButtonAnimatedState
height: widget.height,
width: _onTop ? widget.width : widget.height,
onEnd: () {
setState(() {
_visibleText = !_visibleText;
});
if (mounted) {
setState(() {
_visibleText = !_visibleText;
});
}
},
decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(widget.height! / 2))),
child: InkWell(
@@ -7,6 +7,7 @@ class IconBuilder {
Key? _key;
double? _size;
String? _icon;
EdgeInsets? _padding;
OnPressIconActionClick? _onPressIconActionClick;
IconBuilder(this._icon);
@@ -19,6 +20,10 @@ class IconBuilder {
_size = size;
}
void padding(EdgeInsets padding) {
_padding = padding;
}
void addOnTapActionClick(OnPressIconActionClick onPressIconActionClick) {
_onPressIconActionClick = onPressIconActionClick;
}
@@ -29,16 +34,21 @@ class IconBuilder {
width: _size ?? 40,
height: _size ?? 40,
alignment: Alignment.center,
padding: EdgeInsets.all(3),
child: IconButton(
padding: EdgeInsets.zero,
iconSize: _size ?? 40,
icon: SvgPicture.asset(_icon!, width: _size ?? 40, height: _size ?? 40, fit: BoxFit.fill),
onPressed: () => {
if (_onPressIconActionClick != null) {
_onPressIconActionClick!()
}
})
padding: _padding ?? EdgeInsets.all(3),
child: Material(
borderRadius: BorderRadius.circular((_size ?? 40) / 2),
color: Colors.transparent,
child: IconButton(
padding: EdgeInsets.zero,
iconSize: _size ?? 40,
icon: SvgPicture.asset(_icon!, width: _size ?? 40, height: _size ?? 40, fit: BoxFit.fill),
onPressed: () => {
if (_onPressIconActionClick != null) {
_onPressIconActionClick!()
}
}
)
)
);
}
}
@@ -41,7 +41,7 @@ class AppBarDestinationPickerBuilder {
Widget _buildBackButton() {
return (ButtonBuilder(_imagePaths.icComposerClose)
..padding(5)
..paddingIcon(EdgeInsets.all(5))
..size(30)
..onPressActionClick(() {
if (_onCloseActionClick != null) {
@@ -320,6 +320,10 @@ class ThreadController extends BaseController {
}
}
void enableSelectionEmail() {
currentSelectMode.value = SelectMode.ACTIVE;
}
List<PresentationEmail> getListEmailSelected() {
if (isSearchActive()) {
return emailListSearch.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
@@ -604,6 +608,27 @@ class ThreadController extends BaseController {
&& mailboxDashBoardController.userProfile.value != null
&& mailboxDashBoardController.mapDefaultMailboxId.containsKey(PresentationMailbox.roleOutbox);
bool isSelectionEnabled() => currentSelectMode.value == SelectMode.ACTIVE;
void pressEmailSelectionAction(BuildContext context, EmailActionType actionType, List<PresentationEmail> selectionEmail) {
switch(actionType) {
case EmailActionType.markAsRead:
case EmailActionType.markAsUnread:
markAsSelectedEmailRead(selectionEmail);
break;
case EmailActionType.move:
moveSelectedMultipleEmailToMailboxAction(selectionEmail);
break;
case EmailActionType.markAsFlag:
case EmailActionType.markAsSpam:
case EmailActionType.delete:
_appToast.showToast(AppLocalizations.of(context).the_feature_is_under_development);
break;
default:
break;
}
}
void openMailboxLeftMenu() {
mailboxDashBoardController.openDrawer();
}
+119 -95
View File
@@ -6,9 +6,8 @@ import 'package:model/model.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/app_bar_thread_select_mode_active_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_context_menu_action_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/bottom_bar_thread_selection_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_bar_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/search_bar_thread_view_widget.dart';
@@ -63,26 +62,36 @@ class ThreadView extends GetWidget<ThreadController> {
_buildSuggestionBox(context)
],
)),
Obx(() => controller.isSelectionEnabled()
? Column(children: [
Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2),
_buildOptionSelectionBottomBar(context)
])
: SizedBox.shrink()),
]
)
)
),
floatingActionButton: Obx(() => !controller.isSearchActive()
? ScrollingFloatingButtonAnimated(
icon: SvgPicture.asset(imagePaths.icCompose, width: 20, height: 20, fit: BoxFit.fill),
text: Padding(
padding: EdgeInsets.only(right: 10),
child: Text(
AppLocalizations.of(context).compose,
style: TextStyle(color: AppColor.colorTextButton, fontSize: 15.0, fontWeight: FontWeight.w500))
),
onPress: () => controller.composeEmailAction(),
scrollController: controller.listEmailController,
color: Colors.white,
elevation: 4.0,
width: 140,
animateIcon: false)
: SizedBox.shrink())
floatingActionButton: Obx(() => !controller.isSearchActive() && !controller.isSelectionEnabled()
? Container(
padding: EdgeInsets.only(bottom: controller.isSelectionEnabled() ? 80 : 0),
child: Align(
alignment: Alignment.bottomRight,
child: ScrollingFloatingButtonAnimated(
icon: SvgPicture.asset(imagePaths.icCompose, width: 20, height: 20, fit: BoxFit.fill),
text: Padding(
padding: EdgeInsets.only(right: 10),
child: Text(
AppLocalizations.of(context).compose,
style: TextStyle(color: AppColor.colorTextButton, fontSize: 15.0, fontWeight: FontWeight.w500))
),
onPress: () => controller.composeEmailAction(),
scrollController: controller.listEmailController,
color: Colors.white,
elevation: 4.0,
width: 140,
animateIcon: false)))
: SizedBox.shrink()),
),
);
}
@@ -93,12 +102,24 @@ class ThreadView extends GetWidget<ThreadController> {
children: [
if (!controller.isSearchActive()) _buildAppBarNormal(context),
if (controller.isSearchActive()) _buildSearchForm(context),
if (controller.currentSelectMode.value == SelectMode.ACTIVE) _buildAppBarSelectModeActive(context),
],
);
});
}
Widget _buildOptionSelectionBottomBar(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10),
child: (BottomBarThreadSelectionWidget(
context,
imagePaths,
responsiveUtils,
controller.getListEmailSelected())
..addOnPressEmailSelectionActionClick((actionType, selectionEmail) =>
controller.pressEmailSelectionAction(context, actionType, selectionEmail)))
.build());
}
Widget _buildSearchForm(BuildContext context) {
return (SearchAppBarWidget(
context,
@@ -120,49 +141,53 @@ class ThreadView extends GetWidget<ThreadController> {
context,
imagePaths,
responsiveUtils,
controller.mailboxDashBoardController.selectedMailbox.value)
..addOpenListMailboxActionClick(() => controller.openMailboxLeftMenu()))
.build();
}
Widget _buildAppBarSelectModeActive(BuildContext context) {
return (AppBarThreadSelectModeActiveBuilder(
context,
imagePaths,
controller.mailboxDashBoardController.selectedMailbox.value,
controller.getListEmailSelected(),
responsiveUtils)
..addCloseActionClick(() => controller.cancelSelectEmail())
// ..addRemoveEmailActionClick((listEmail) => {})
..addOnMarkAsEmailReadActionClick((listEmail) => controller.markAsSelectedEmailRead(listEmail))
..addOpenContextMenuActionClick((listEmail) =>
controller.openContextMenuSelectedEmail(context, _contextMenuEmailActionTile(context, listEmail)))
..addOnOpenPopupMenuActionClick((listEmail, position) =>
controller.openPopupMenuSelectedEmail(context, position, _popupMenuEmailActionTile(context, listEmail))))
controller.currentSelectMode.value)
..addOpenListMailboxActionClick(() => controller.openMailboxLeftMenu())
..addOnEditThreadAction(() => controller.enableSelectionEmail())
..addOnCancelEditThread(() => controller.cancelSelectEmail()))
.build();
}
List<Widget> _contextMenuEmailActionTile(BuildContext context, List<PresentationEmail> listEmail) {
return [
// _moveToTrashAction(context, listEmail),
_moveToMailboxAction(context, listEmail),
_markAsReadAction(context, listEmail),
_markAsStarAction(context, listEmail),
// _moveToSpamAction(context, listEmail),
SizedBox(height: 20),
];
}
// Widget _buildAppBarSelectModeActive(BuildContext context) {
// return (AppBarThreadSelectModeActiveBuilder(
// context,
// imagePaths,
// controller.getListEmailSelected(),
// responsiveUtils)
// ..addCloseActionClick(() => controller.cancelSelectEmail())
// // ..addRemoveEmailActionClick((listEmail) => {})
// ..addOnMarkAsEmailReadActionClick((listEmail) => controller.markAsSelectedEmailRead(listEmail))
// ..addOpenContextMenuActionClick((listEmail) =>
// controller.openContextMenuSelectedEmail(context, _contextMenuEmailActionTile(context, listEmail)))
// ..addOnOpenPopupMenuActionClick((listEmail, position) =>
// controller.openPopupMenuSelectedEmail(context, position, _popupMenuEmailActionTile(context, listEmail))))
// .build();
// }
Widget _markAsReadAction(BuildContext context, List<PresentationEmail> listEmail) {
return (EmailContextMenuActionBuilder(
Key('mark_as_read_context_menu_action'),
SvgPicture.asset(imagePaths.icEyeDisable, width: 24, height: 24, fit: BoxFit.fill),
controller.isAllEmailRead(listEmail)
? AppLocalizations.of(context).mark_as_unread
: AppLocalizations.of(context).mark_as_read,
listEmail)
..onActionClick((data) => controller.markAsSelectedEmailRead(data, fromContextMenuAction: true)))
.build();
}
// List<Widget> _contextMenuEmailActionTile(BuildContext context, List<PresentationEmail> listEmail) {
// return [
// // _moveToTrashAction(context, listEmail),
// _moveToMailboxAction(context, listEmail),
// _markAsReadAction(context, listEmail),
// _markAsStarAction(context, listEmail),
// // _moveToSpamAction(context, listEmail),
// SizedBox(height: 20),
// ];
// }
// Widget _markAsReadAction(BuildContext context, List<PresentationEmail> listEmail) {
// return (EmailContextMenuActionBuilder(
// Key('mark_as_read_context_menu_action'),
// SvgPicture.asset(imagePaths.icEyeDisable, width: 24, height: 24, fit: BoxFit.fill),
// controller.isAllEmailRead(listEmail)
// ? AppLocalizations.of(context).mark_as_unread
// : AppLocalizations.of(context).mark_as_read,
// listEmail)
// ..onActionClick((data) => controller.markAsSelectedEmailRead(data, fromContextMenuAction: true)))
// .build();
// }
// Widget _moveToTrashAction(BuildContext context, List<PresentationEmail> listEmail) {
// return (EmailContextMenuActionBuilder(
@@ -174,33 +199,33 @@ class ThreadView extends GetWidget<ThreadController> {
// .build();
// }
Widget _moveToMailboxAction(BuildContext context, List<PresentationEmail> listEmail) {
return (EmailContextMenuActionBuilder(
Key('move_to_mailbox_context_menu_action'),
SvgPicture.asset(imagePaths.icFolder, width: 24, height: 24, fit: BoxFit.fill),
AppLocalizations.of(context).move_to_mailbox,
listEmail)
..onActionClick((data) => controller.moveSelectedMultipleEmailToMailboxAction(data)))
.build();
}
Widget _markAsStarAction(BuildContext context, List<PresentationEmail> listEmail) {
final markStarAction = controller.isAllEmailMarkAsStar(listEmail) ? MarkStarAction.unMarkStar : MarkStarAction.markStar;
return (EmailContextMenuActionBuilder(
Key('mark_as_star_context_menu_action'),
SvgPicture.asset(
markStarAction == MarkStarAction.markStar ? imagePaths.icFlag : imagePaths.icFlagged,
width: 24,
height: 24,
fit: BoxFit.fill),
markStarAction == MarkStarAction.markStar
? AppLocalizations.of(context).mark_as_star
: AppLocalizations.of(context).mark_as_unstar,
listEmail)
..onActionClick((data) => controller.markAsStarSelectedMultipleEmail(data, markStarAction)))
.build();
}
// Widget _moveToMailboxAction(BuildContext context, List<PresentationEmail> listEmail) {
// return (EmailContextMenuActionBuilder(
// Key('move_to_mailbox_context_menu_action'),
// SvgPicture.asset(imagePaths.icFolder, width: 24, height: 24, fit: BoxFit.fill),
// AppLocalizations.of(context).move_to_mailbox,
// listEmail)
// ..onActionClick((data) => controller.moveSelectedMultipleEmailToMailboxAction(data)))
// .build();
// }
//
// Widget _markAsStarAction(BuildContext context, List<PresentationEmail> listEmail) {
// final markStarAction = controller.isAllEmailMarkAsStar(listEmail) ? MarkStarAction.unMarkStar : MarkStarAction.markStar;
//
// return (EmailContextMenuActionBuilder(
// Key('mark_as_star_context_menu_action'),
// SvgPicture.asset(
// markStarAction == MarkStarAction.markStar ? imagePaths.icFlag : imagePaths.icFlagged,
// width: 24,
// height: 24,
// fit: BoxFit.fill),
// markStarAction == MarkStarAction.markStar
// ? AppLocalizations.of(context).mark_as_star
// : AppLocalizations.of(context).mark_as_unstar,
// listEmail)
// ..onActionClick((data) => controller.markAsStarSelectedMultipleEmail(data, markStarAction)))
// .build();
// }
// Widget _moveToSpamAction(BuildContext context, List<PresentationEmail> listEmail) {
// return (EmailContextMenuActionBuilder(
@@ -212,15 +237,15 @@ class ThreadView extends GetWidget<ThreadController> {
// .build();
// }
List<PopupMenuItem> _popupMenuEmailActionTile(BuildContext context, List<PresentationEmail> listEmail) {
return [
// PopupMenuItem(child: _moveToTrashAction(context, listEmail)),
PopupMenuItem(child: _moveToMailboxAction(context, listEmail)),
PopupMenuItem(child: _markAsReadAction(context, listEmail)),
PopupMenuItem(child: _markAsStarAction(context, listEmail)),
// PopupMenuItem(child: _moveToSpamAction(context, listEmail)),
];
}
// List<PopupMenuItem> _popupMenuEmailActionTile(BuildContext context, List<PresentationEmail> listEmail) {
// return [
// // PopupMenuItem(child: _moveToTrashAction(context, listEmail)),
// PopupMenuItem(child: _moveToMailboxAction(context, listEmail)),
// PopupMenuItem(child: _markAsReadAction(context, listEmail)),
// PopupMenuItem(child: _markAsStarAction(context, listEmail)),
// // PopupMenuItem(child: _moveToSpamAction(context, listEmail)),
// ];
// }
Widget _buildLoadingView() {
return Obx(() => controller.viewState.value.fold(
@@ -348,8 +373,7 @@ class ThreadView extends GetWidget<ThreadController> {
controller.mailboxDashBoardController.searchState.value.searchStatus,
controller.searchQuery)
..onOpenEmailAction((selectedEmail) => controller.previewEmail(context, selectedEmail))
..onSelectEmailAction((selectedEmail) => controller.selectEmail(context, selectedEmail))
..addOnMarkAsStarEmailActionClick((selectedEmail) => controller.markAsStarEmail(selectedEmail)))
..onSelectEmailAction((selectedEmail) => controller.selectEmail(context, selectedEmail)))
.build()),
));
}
@@ -7,22 +7,30 @@ import 'package:model/model.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnFilterEmailAction = void Function();
typedef OnEditThreadAction = void Function();
typedef OnOpenListMailboxActionClick = void Function();
typedef OnCancelEditThread = void Function();
class AppBarThreadWidgetBuilder {
OnFilterEmailAction? _onFilterEmailAction;
OnOpenListMailboxActionClick? _onOpenListMailboxActionClick;
OnEditThreadAction? _onEditThreadAction;
OnCancelEditThread? _onCancelEditThread;
final BuildContext _context;
final ImagePaths _imagePaths;
final ResponsiveUtils _responsiveUtils;
final PresentationMailbox? _presentationMailbox;
final List<PresentationEmail> _listSelectionEmail;
final SelectMode _selectMode;
AppBarThreadWidgetBuilder(
this._context,
this._imagePaths,
this._responsiveUtils,
this._presentationMailbox,
this._listSelectionEmail,
this._selectMode,
);
void addOnFilterEmailAction(OnFilterEmailAction onFilterEmailAction) {
@@ -33,6 +41,14 @@ class AppBarThreadWidgetBuilder {
_onOpenListMailboxActionClick = onOpenListMailboxActionClick;
}
void addOnEditThreadAction(OnEditThreadAction onEditThreadAction) {
_onEditThreadAction = onEditThreadAction;
}
void addOnCancelEditThread(OnCancelEditThread onCancelEditThread) {
_onCancelEditThread = onCancelEditThread;
}
Widget build() {
return Container(
key: Key('app_bar_thread_widget'),
@@ -44,7 +60,9 @@ class AppBarThreadWidgetBuilder {
data: MediaQueryData(padding: EdgeInsets.zero),
child: Row(
children: [
_buildEditButton(),
if (_selectMode != SelectMode.ACTIVE) _buildEditButton(),
if (_selectMode == SelectMode.ACTIVE) _buildBackButton(),
if (_selectMode == SelectMode.ACTIVE) _buildCountItemSelected(),
Expanded(child: _buildContentCenterAppBar()),
_buildFilterButton(),
]
@@ -60,7 +78,7 @@ class AppBarThreadWidgetBuilder {
child: Padding(
padding: EdgeInsets.only(right: 16),
child: TextButton(
onPressed: () {},
onPressed: () => _onEditThreadAction?.call(),
child: Text(
AppLocalizations.of(_context).edit,
style: TextStyle(fontSize: 17, color: AppColor.colorTextButton),
@@ -78,13 +96,40 @@ class AppBarThreadWidgetBuilder {
padding: EdgeInsets.only(left: 16),
child: IconButton(
color: AppColor.baseTextColor,
icon: SvgPicture.asset(_imagePaths.icFilter, color: AppColor.baseTextColor, fit: BoxFit.fill),
icon: SvgPicture.asset(_imagePaths.icFilter, fit: BoxFit.fill),
onPressed: () => _onFilterEmailAction?.call()
)
)
);
}
Widget _buildBackButton() {
return Material(
borderRadius: BorderRadius.circular(12),
color: Colors.transparent,
child: IconButton(
color: AppColor.baseTextColor,
icon: SvgPicture.asset(
_imagePaths.icBack,
width: 20,
height: 20,
color: AppColor.colorTextButton,
fit: BoxFit.fill),
onPressed: () => _onCancelEditThread?.call()
)
);
}
Widget _buildCountItemSelected() {
return Padding(
padding: EdgeInsets.zero,
child: Text(
'${_listSelectionEmail.length}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 17, color: AppColor.colorTextButton)));
}
Widget _buildContentCenterAppBar() {
return Row(
mainAxisSize: MainAxisSize.min,
@@ -0,0 +1,102 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnPressEmailSelectionActionClick = void Function(EmailActionType, List<PresentationEmail>);
class BottomBarThreadSelectionWidget {
final BuildContext _context;
final ImagePaths _imagePaths;
final ResponsiveUtils _responsiveUtils;
final List<PresentationEmail> _listSelectionEmail;
OnPressEmailSelectionActionClick? _onPressEmailSelectionActionClick;
BottomBarThreadSelectionWidget(
this._context,
this._imagePaths,
this._responsiveUtils,
this._listSelectionEmail,
);
void addOnPressEmailSelectionActionClick(OnPressEmailSelectionActionClick onPressEmailSelectionActionClick) {
_onPressEmailSelectionActionClick = onPressEmailSelectionActionClick;
}
Widget build() {
return Container(
key: Key('bottom_bar_thread_selection_widget'),
alignment: Alignment.center,
color: Colors.white,
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: _buildListOptionButton()
)
);
}
Widget _buildListOptionButton() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
(ButtonBuilder(_listSelectionEmail.isAllEmailRead ? _imagePaths.icUnreadV2 : _imagePaths.icReadV2)
..key(Key('button_mark_read_email'))
..paddingIcon(EdgeInsets.all(8))
..textStyle(TextStyle(fontSize: 12, color: AppColor.colorTextButton))
..onPressActionClick(() {
if (_onPressEmailSelectionActionClick != null) {
_onPressEmailSelectionActionClick!(
_listSelectionEmail.isAllEmailRead ? EmailActionType.markAsUnread : EmailActionType.markAsRead,
_listSelectionEmail);
}})
..text(
_listSelectionEmail.isAllEmailRead ? AppLocalizations.of(_context).unread : AppLocalizations.of(_context).read,
isVertical: _responsiveUtils.isMobile(_context)))
.build(),
(ButtonBuilder(_imagePaths.icFlagV2)
..key(Key('button_flag_email'))
..paddingIcon(EdgeInsets.all(8))
..textStyle(TextStyle(fontSize: 12, color: AppColor.colorTextButton))
..onPressActionClick(() {
if (_onPressEmailSelectionActionClick != null) {
_onPressEmailSelectionActionClick!(EmailActionType.markAsFlag, _listSelectionEmail);
}})
..text(AppLocalizations.of(_context).flag, isVertical: _responsiveUtils.isMobile(_context)))
.build(),
(ButtonBuilder(_imagePaths.icMoveV2)
..key(Key('button_move_email'))
..paddingIcon(EdgeInsets.all(8))
..textStyle(TextStyle(fontSize: 12, color: AppColor.colorTextButton))
..onPressActionClick(() {
if (_onPressEmailSelectionActionClick != null) {
_onPressEmailSelectionActionClick!(EmailActionType.move, _listSelectionEmail);
}})
..text(AppLocalizations.of(_context).move, isVertical: _responsiveUtils.isMobile(_context)))
.build(),
(ButtonBuilder(_imagePaths.icSpamV2)
..key(Key('button_spam_email'))
..paddingIcon(EdgeInsets.all(8))
..textStyle(TextStyle(fontSize: 12, color: AppColor.colorTextButton))
..onPressActionClick(() {
if (_onPressEmailSelectionActionClick != null) {
_onPressEmailSelectionActionClick!(EmailActionType.markAsSpam, _listSelectionEmail);
}})
..text(AppLocalizations.of(_context).spam, isVertical: _responsiveUtils.isMobile(_context)))
.build(),
(ButtonBuilder(_imagePaths.icDeleteV2)
..key(Key('button_delete_email'))
..paddingIcon(EdgeInsets.all(8))
..textStyle(TextStyle(fontSize: 12, color: AppColor.colorTextButton))
..onPressActionClick(() {
if (_onPressEmailSelectionActionClick != null) {
_onPressEmailSelectionActionClick!(EmailActionType.delete, _listSelectionEmail);
}})
..text(AppLocalizations.of(_context).delete, isVertical: _responsiveUtils.isMobile(_context)))
.build()
]
);
}
}
@@ -10,7 +10,6 @@ import 'package:tmail_ui_user/features/thread/presentation/model/search_status.d
typedef OnOpenEmailActionClick = void Function(PresentationEmail selectedEmail);
typedef OnSelectEmailActionClick = void Function(PresentationEmail selectedEmail);
typedef OnMarkAsStarEmailActionClick = void Function(PresentationEmail selectedEmail);
class EmailTileBuilder {
@@ -24,7 +23,6 @@ class EmailTileBuilder {
OnOpenEmailActionClick? _onOpenEmailActionClick;
OnSelectEmailActionClick? _onSelectEmailActionClick;
OnMarkAsStarEmailActionClick? _onMarkAsStarEmailActionClick;
EmailTileBuilder(
this._context,
@@ -44,10 +42,6 @@ class EmailTileBuilder {
_onSelectEmailActionClick = onSelectEmailActionClick;
}
void addOnMarkAsStarEmailActionClick(OnMarkAsStarEmailActionClick onMarkAsStarEmailActionClick) {
_onMarkAsStarEmailActionClick = onMarkAsStarEmailActionClick;
}
Widget build() {
return Theme(
data: ThemeData(
@@ -104,7 +98,7 @@ class EmailTileBuilder {
Padding(
padding: EdgeInsets.only(left: 8),
child: (ButtonBuilder(_imagePaths.icAttachment)
..padding(0)
..paddingIcon(EdgeInsets.zero)
..size(16))
.build()),
Padding(
@@ -115,7 +109,7 @@ class EmailTileBuilder {
overflow:TextOverflow.ellipsis,
style: TextStyle(fontSize: 13, color: AppColor.colorContentEmail))),
(ButtonBuilder(_imagePaths.icChevron)
..padding(0)
..paddingIcon(EdgeInsets.zero)
..size(16))
.build(),
],
@@ -162,7 +156,7 @@ class EmailTileBuilder {
),
if (_presentationEmail.isFlaggedEmail() )
(ButtonBuilder(_imagePaths.icStar)
..padding(0)
..paddingIcon(EdgeInsets.zero)
..size(15))
.build(),
],
@@ -201,24 +195,15 @@ class EmailTileBuilder {
return AnimatedSwitcher(
duration: Duration(milliseconds: 600),
transitionBuilder: _transitionBuilder,
child: _presentationEmail.selectMode == SelectMode.ACTIVE
? (IconBuilder(_imagePaths.icSelected)
..addOnTapActionClick(() {
if (_selectModeAll == SelectMode.ACTIVE && _onSelectEmailActionClick != null) {
_onSelectEmailActionClick!(_presentationEmail);
}}))
.build()
: (AvatarBuilder()
..text('${_presentationEmail.getAvatarText()}')
..size(56)
..textColor(Colors.white)
..avatarColor(_presentationEmail.avatarColors)
// .iconStatus(_imagePaths.icOffline)
..addOnTapActionClick(() {
if (_selectModeAll == SelectMode.ACTIVE && _onSelectEmailActionClick != null) {
_onSelectEmailActionClick!(_presentationEmail);
}}))
.build()
child: (IconBuilder(_presentationEmail.selectMode == SelectMode.ACTIVE ? _imagePaths.icSelectedV2 : _imagePaths.icUnSelectedV2)
..padding(EdgeInsets.all(14))
..size(55)
..addOnTapActionClick(() {
if (_selectModeAll == SelectMode.ACTIVE && _onSelectEmailActionClick != null) {
_onSelectEmailActionClick!(_presentationEmail);
}}))
.build()
);
} else {
return (AvatarBuilder()
+42 -1
View File
@@ -476,5 +476,46 @@ class AppLocalizations {
'Compose',
name: 'compose');
}
}
String get delete {
return Intl.message(
'Delete',
name: 'delete');
}
String get move {
return Intl.message(
'Move',
name: 'move');
}
String get spam {
return Intl.message(
'Spam',
name: 'spam');
}
String get flag {
return Intl.message(
'Flag',
name: 'flag');
}
String get read {
return Intl.message(
'Read',
name: 'read');
}
String get unread {
return Intl.message(
'Unread',
name: 'unread');
}
String get the_feature_is_under_development {
return Intl.message(
'This feature is under development.',
name: 'the_feature_is_under_development');
}
}
+6
View File
@@ -4,4 +4,10 @@ enum EmailActionType {
forward,
replyAll,
compose,
markAsRead,
markAsUnread,
markAsFlag,
move,
markAsSpam,
delete,
}
@@ -0,0 +1,6 @@
import 'package:model/email/presentation_email.dart';
extension ListPresentationEmailExtension on List<PresentationEmail> {
bool get isAllEmailRead => every((email) => email.isReadEmail());
}
+1
View File
@@ -53,6 +53,7 @@ export 'extensions/list_extension.dart';
export 'extensions/list_email_extension.dart';
export 'extensions/media_type_extension.dart';
export 'extensions/list_attachment_extension.dart';
export 'extensions/list_presentation_email_extension.dart';
// Download
export 'download/download_task_id.dart';