TF-80 Move multiple email to mailbox from thread view

This commit is contained in:
dab246
2021-09-21 12:52:27 +07:00
committed by Dat H. Pham
parent 24e52dc6a4
commit a12efc8d2b
43 changed files with 1007 additions and 443 deletions
@@ -0,0 +1,18 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
extension ListMailboxNodeExtensions on List<MailboxNode> {
List<MailboxNode>? updateNode(MailboxId currentMailboxId, MailboxNode newNode) {
return map((MailboxNode child) {
if (child.item.id == currentMailboxId) {
return newNode;
} else {
if (child.hasChildren()) {
return child.copyWith(mailboxNodes: child.updateNode(currentMailboxId, newNode));
}
return child;
}
}).toList();
}
}
@@ -11,10 +11,11 @@ import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_i
import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/move_multiple_email_to_mailbox_state.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -26,8 +27,8 @@ class MailboxController extends BaseController {
final TreeBuilder _treeBuilder;
final ResponsiveUtils responsiveUtils;
final folderMailboxTree = MailboxTree(MailboxNode.root()).obs;
final defaultMailboxList = <PresentationMailbox>[].obs;
final folderMailboxNodeList = <MailboxNode>[].obs;
MailboxController(
this._getAllMailboxInteractor,
@@ -51,6 +52,10 @@ class MailboxController extends BaseController {
success is MarkAsMultipleEmailReadAllSuccess ||
success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
refreshGetAllMailboxAction();
} else if (success is MoveMultipleEmailToMailboxAllSuccess
|| success is MoveMultipleEmailToMailboxHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshGetAllMailboxAction();
}
});
});
@@ -97,7 +102,20 @@ class MailboxController extends BaseController {
void onError(error) {}
void _buildTree(List<PresentationMailbox> folderMailboxList) async {
folderMailboxTree.value = await _treeBuilder.generateMailboxTree(folderMailboxList);
final _folderMailboxTree = await _treeBuilder.generateMailboxTree(folderMailboxList);
folderMailboxNodeList.value = _folderMailboxTree.root.childrenItems ?? [];
}
void toggleMailboxFolder(MailboxNode mailboxNode) {
final newExpandMode = mailboxNode.expandMode == ExpandMode.COLLAPSE
? ExpandMode.EXPAND
: ExpandMode.COLLAPSE;
final newMailboxNodeList = folderMailboxNodeList.updateNode(
mailboxNode.item.id,
mailboxNode.copyWith(newExpandMode: newExpandMode)) ?? [];
folderMailboxNodeList.value = newMailboxNodeList;
}
void _setUpMapMailboxIdDefault(List<PresentationMailbox> defaultMailboxList) {
@@ -1,7 +1,4 @@
import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
@@ -174,7 +171,7 @@ class MailboxView extends GetWidget<MailboxController> {
}
Widget _buildFolderMailbox(BuildContext context) {
return Obx(() => controller.folderMailboxTree.value.root.hasChildren()
return Obx(() => controller.folderMailboxNodeList.isNotEmpty
? Transform(
transform: Matrix4.translationValues(responsiveUtils.isMobile(context) ? 0.0 : -15.0, 0.0, 0.0),
child: Padding(
@@ -182,7 +179,7 @@ class MailboxView extends GetWidget<MailboxController> {
child: TreeView(
startExpanded: false,
key: Key('folder_mailbox_list'),
children: _buildListChildTileWidget(context, controller.folderMailboxTree.value.root.childrenItems!)))
children: _buildListChildTileWidget(context, controller.folderMailboxNodeList)))
)
: SizedBox.shrink()
);
@@ -192,24 +189,27 @@ class MailboxView extends GetWidget<MailboxController> {
return listMailboxNode
.map((mailboxNode) => mailboxNode.hasChildren()
? Padding(
padding: EdgeInsets.only(left: 16),
padding: EdgeInsets.only(left: 20),
child: TreeViewChild(
key: Key('children_tree_mailbox_child'),
parent: Obx(() => MailBoxFolderTileBuilder(
context,
imagePaths,
responsiveUtils,
mailboxNode,
selectMode: controller.getSelectMode(
mailboxNode.item,
controller.mailboxDashBoardController.selectedMailbox.value))
.build()),
children: _buildListChildTileWidget(context, mailboxNode.childrenItems!)))
context,
key: Key('children_tree_mailbox_child'),
isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND,
parent: Obx(() => (MailBoxFolderTileBuilder(
context,
imagePaths,
responsiveUtils,
mailboxNode,
selectMode: controller.getSelectMode(
mailboxNode.item,
controller.mailboxDashBoardController.selectedMailbox.value))
..addOnSelectMailboxFolderClick((mailboxNode) => controller.selectMailbox(context, mailboxNode.item))
..addOnExpandFolderActionClick((mailboxNode) => controller.toggleMailboxFolder(mailboxNode)))
.build()),
children: _buildListChildTileWidget(context, mailboxNode.childrenItems!)
).build())
: Padding(
padding: EdgeInsets.only(left: 16),
child: Obx(() => GestureDetector(
onTap: () => controller.selectMailbox(context, mailboxNode.item),
child: MailBoxFolderTileBuilder(
padding: EdgeInsets.only(left: 20),
child: Obx(() => (MailBoxFolderTileBuilder(
context,
imagePaths,
responsiveUtils,
@@ -217,8 +217,9 @@ class MailboxView extends GetWidget<MailboxController> {
selectMode: controller.getSelectMode(
mailboxNode.item,
controller.mailboxDashBoardController.selectedMailbox.value))
.build(),
))))
..addOnSelectMailboxFolderClick((mailboxNode) => controller.selectMailbox(context, mailboxNode.item)))
.build(),
)))
.toList();
}
@@ -1,19 +1,24 @@
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/mailbox/expand_mode.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
class MailboxNode with EquatableMixin{
static PresentationMailbox _root = PresentationMailbox(MailboxId(Id('root')));
PresentationMailbox item;
List<MailboxNode>? childrenItems;
ExpandMode expandMode;
factory MailboxNode.root() => MailboxNode(_root);
static PresentationMailbox rootItem() => _root;
bool hasChildren() => childrenItems?.isNotEmpty ?? false;
MailboxNode(this.item, {this.childrenItems});
MailboxNode(this.item, {this.childrenItems, this.expandMode = ExpandMode.COLLAPSE});
void addChildNode(MailboxNode node) {
if (childrenItems == null) {
@@ -22,6 +27,60 @@ class MailboxNode with EquatableMixin{
childrenItems?.add(node);
}
String getPathMailboxNode(MailboxTree mailboxTree, List<PresentationMailbox> defaultMailboxList) {
String path = '${item.name?.name}';
var parentId = item.parentId;
while(parentId != null) {
var parent = mailboxTree.findNode(parentId);
if (parent == null) {
try {
final parentItem = defaultMailboxList.firstWhere((mailbox) => mailbox.id == parentId);
parent = MailboxNode(parentItem);
} catch(e) {}
}
if (parent != null) {
path = '${parent.item.name?.name}/$path';
parentId = parent.item.parentId;
} else {
break;
}
}
return path;
}
List<MailboxNode>? updateNode(MailboxId mailboxId, MailboxNode newNode, {MailboxNode? parent}) {
List<MailboxNode>? _children = parent == null ? this.childrenItems : parent.childrenItems;
return _children?.map((MailboxNode child) {
if (child.item.id == mailboxId) {
return newNode;
} else {
if (child.hasChildren()) {
return child.copyWith(
mailboxNodes: updateNode(
mailboxId,
newNode,
parent: child,
),
);
}
return child;
}
}).toList();
}
@override
List<Object?> get props => [item, childrenItems];
}
}
extension MailboxNodeExtension on MailboxNode {
MailboxNode copyWith({ExpandMode? newExpandMode, List<MailboxNode>? mailboxNodes}) {
return MailboxNode(
item,
childrenItems: mailboxNodes ?? childrenItems,
expandMode: newExpandMode ?? expandMode);
}
}
@@ -1,5 +1,8 @@
import 'dart:collection';
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'mailbox_node.dart';
@@ -7,6 +10,23 @@ class MailboxTree with EquatableMixin {
MailboxNode root;
MailboxTree(this.root);
MailboxNode? findNode(MailboxId? mailboxId) {
var result;
final queue = ListQueue<MailboxNode>();
queue.addLast(root);
while (queue.isNotEmpty && mailboxId != null) {
final currentNode = queue.removeFirst();
if (mailboxId == currentNode.item.id) {
result = currentNode;
break;
}
currentNode.childrenItems?.forEach((child) {
queue.addLast(child);
});
}
return result;
}
@override
List<Object?> get props => [root];
}
@@ -3,9 +3,13 @@ import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_displayed.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
typedef OnExpandFolderActionClick = void Function(MailboxNode mailboxNode);
typedef OnSelectMailboxFolderClick = void Function(MailboxNode mailboxNode);
class MailBoxFolderTileBuilder {
final MailboxNode _mailboxNode;
@@ -15,6 +19,9 @@ class MailBoxFolderTileBuilder {
final SelectMode selectMode;
final MailboxDisplayed mailboxDisplayed;
OnExpandFolderActionClick? _onExpandFolderActionClick;
OnSelectMailboxFolderClick? _onSelectMailboxFolderClick;
MailBoxFolderTileBuilder(
this._context,
this._imagePaths,
@@ -26,6 +33,14 @@ class MailBoxFolderTileBuilder {
}
);
void addOnExpandFolderActionClick(OnExpandFolderActionClick onExpandFolderActionClick) {
this._onExpandFolderActionClick = onExpandFolderActionClick;
}
void addOnSelectMailboxFolderClick(OnSelectMailboxFolderClick onSelectMailboxFolderClick) {
this._onSelectMailboxFolderClick = onSelectMailboxFolderClick;
}
Widget build() {
return Container(
key: Key('mailbox_folder_tile'),
@@ -39,6 +54,11 @@ class MailBoxFolderTileBuilder {
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: ListTile(
onTap: () {
if (_onSelectMailboxFolderClick != null) {
_onSelectMailboxFolderClick!(_mailboxNode);
}
},
contentPadding: EdgeInsets.zero,
leading: Padding(
padding: EdgeInsets.only(left: mailboxDisplayed == MailboxDisplayed.mailbox
@@ -72,14 +92,21 @@ class MailBoxFolderTileBuilder {
: 36,
left: mailboxDisplayed == MailboxDisplayed.mailbox ? 16 : 16),
child: _mailboxNode.hasChildren()
? SvgPicture.asset(
_imagePaths.icFolderArrow,
width: 12,
height: 12,
color: selectMode == SelectMode.ACTIVE
? AppColor.mailboxSelectedIconColor
: AppColor.mailboxIconColor,
fit: BoxFit.fill)
? GestureDetector(
onTap: () {
if (_onExpandFolderActionClick != null) {
_onExpandFolderActionClick!(_mailboxNode);
}
},
child: SvgPicture.asset(
_mailboxNode.expandMode == ExpandMode.EXPAND ? _imagePaths.icExpandFolder : _imagePaths.icFolderArrow,
width: _mailboxNode.expandMode == ExpandMode.EXPAND ? 8 : 12,
height: _mailboxNode.expandMode == ExpandMode.EXPAND ? 8 : 12,
color: selectMode == SelectMode.ACTIVE
? AppColor.mailboxSelectedIconColor
: AppColor.mailboxIconColor,
fit: BoxFit.fill),
)
: SizedBox.shrink())
)
)