TF-4002 Apply new design for folder creation modal on mobile

This commit is contained in:
dab246
2025-09-04 17:00:33 +07:00
committed by Dat H. Pham
parent 36e58fc990
commit 9bb5508111
10 changed files with 378 additions and 38 deletions
@@ -10,6 +10,9 @@ class FolderItemWidget extends StatelessWidget {
final ImagePaths imagePaths; final ImagePaths imagePaths;
final String folderName; final String folderName;
final bool isSelected; final bool isSelected;
final Color? iconColor;
final String? iconSelected;
final TextStyle? textStyle;
final VoidCallback? onTapAction; final VoidCallback? onTapAction;
const FolderItemWidget({ const FolderItemWidget({
@@ -17,6 +20,9 @@ class FolderItemWidget extends StatelessWidget {
required this.imagePaths, required this.imagePaths,
required this.folderName, required this.folderName,
this.isSelected = false, this.isSelected = false,
this.iconColor,
this.iconSelected,
this.textStyle,
this.onTapAction, this.onTapAction,
}); });
@@ -33,7 +39,8 @@ class FolderItemWidget extends StatelessWidget {
imagePaths.icFolderMailbox, imagePaths.icFolderMailbox,
width: MailboxIconWidgetStyles.iconSize, width: MailboxIconWidgetStyles.iconSize,
height: MailboxIconWidgetStyles.iconSize, height: MailboxIconWidgetStyles.iconSize,
colorFilter: AppColor.primaryLinShare.asFilter(), colorFilter:
iconColor?.asFilter() ?? AppColor.primaryLinShare.asFilter(),
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
const SizedBox(width: MailboxItemWidgetStyles.labelIconSpace), const SizedBox(width: MailboxItemWidgetStyles.labelIconSpace),
@@ -42,23 +49,23 @@ class FolderItemWidget extends StatelessWidget {
folderName, folderName,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: isSelected style: textStyle ??
? ThemeUtils.textStyleInter700( (isSelected
color: Colors.black, ? ThemeUtils.textStyleInter700(
fontSize: 14, color: Colors.black,
) fontSize: 14,
: ThemeUtils.textStyleBodyBody3( )
color: Colors.black, : ThemeUtils.textStyleBodyBody3(
), color: Colors.black,
)),
), ),
), ),
const SizedBox(width: MailboxItemWidgetStyles.labelIconSpace), const SizedBox(width: MailboxItemWidgetStyles.labelIconSpace),
if (isSelected) if (isSelected)
SvgPicture.asset( SvgPicture.asset(
imagePaths.icCheck, iconSelected ?? imagePaths.icCheck,
width: MailboxIconWidgetStyles.iconSize, width: MailboxIconWidgetStyles.iconSize,
height: MailboxIconWidgetStyles.iconSize, height: MailboxIconWidgetStyles.iconSize,
colorFilter: AppColor.primaryLinShare.asFilter(),
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
], ],
@@ -25,6 +25,7 @@ class LabelMailboxItemWidget extends StatefulWidget {
final bool isItemHovered; final bool isItemHovered;
final bool isSelected; final bool isSelected;
final bool isSelectedFolderInModal; final bool isSelectedFolderInModal;
final TextStyle? textStyle;
final OnClickOpenMenuMailboxNodeAction? onMenuActionClick; final OnClickOpenMenuMailboxNodeAction? onMenuActionClick;
final OnEmptyMailboxActionCallback? onEmptyMailboxActionCallback; final OnEmptyMailboxActionCallback? onEmptyMailboxActionCallback;
final OnClickExpandMailboxNodeAction? onClickExpandMailboxNodeAction; final OnClickExpandMailboxNodeAction? onClickExpandMailboxNodeAction;
@@ -37,6 +38,7 @@ class LabelMailboxItemWidget extends StatefulWidget {
this.isItemHovered = false, this.isItemHovered = false,
this.isSelected = false, this.isSelected = false,
this.isSelectedFolderInModal = false, this.isSelectedFolderInModal = false,
this.textStyle,
this.onMenuActionClick, this.onMenuActionClick,
this.onEmptyMailboxActionCallback, this.onEmptyMailboxActionCallback,
this.onClickExpandMailboxNodeAction, this.onClickExpandMailboxNodeAction,
@@ -58,7 +60,7 @@ class _LabelMailboxItemWidgetState extends State<LabelMailboxItemWidget> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final displayNameWidget = TextOverflowBuilder( final displayNameWidget = TextOverflowBuilder(
widget.mailboxNode.item.getDisplayName(context), widget.mailboxNode.item.getDisplayName(context),
style: _displayNameTextStyle, style: widget.textStyle ?? _displayNameTextStyle,
); );
final nameWithExpandIcon = Row( final nameWithExpandIcon = Row(
@@ -26,6 +26,10 @@ class MailboxItemWidget extends StatefulWidget {
final MailboxActions? mailboxActions; final MailboxActions? mailboxActions;
final MailboxId? mailboxIdAlreadySelected; final MailboxId? mailboxIdAlreadySelected;
final Color? hoverColor; final Color? hoverColor;
final TextStyle? textStyle;
final Color? iconColor;
final double? itemHeight;
final String? iconSelected;
final OnClickExpandMailboxNodeAction? onExpandFolderActionClick; final OnClickExpandMailboxNodeAction? onExpandFolderActionClick;
final OnClickOpenMailboxNodeAction? onOpenMailboxFolderClick; final OnClickOpenMailboxNodeAction? onOpenMailboxFolderClick;
@@ -43,6 +47,10 @@ class MailboxItemWidget extends StatefulWidget {
this.mailboxActions, this.mailboxActions,
this.mailboxIdAlreadySelected, this.mailboxIdAlreadySelected,
this.hoverColor, this.hoverColor,
this.iconColor,
this.textStyle,
this.itemHeight,
this.iconSelected,
this.onExpandFolderActionClick, this.onExpandFolderActionClick,
this.onOpenMailboxFolderClick, this.onOpenMailboxFolderClick,
this.onSelectMailboxFolderClick, this.onSelectMailboxFolderClick,
@@ -88,9 +96,9 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
padding: const EdgeInsetsDirectional.symmetric( padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.itemPadding, horizontal: MailboxItemWidgetStyles.itemPadding,
), ),
height: widget.mailboxNode.item.isTeamMailboxes height: widget.itemHeight ?? (widget.mailboxNode.item.isTeamMailboxes
? MailboxItemWidgetStyles.teamMailboxHeight ? MailboxItemWidgetStyles.teamMailboxHeight
: MailboxItemWidgetStyles.height, : MailboxItemWidgetStyles.height),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: widget.mailboxNode.item.isTeamMailboxes crossAxisAlignment: widget.mailboxNode.item.isTeamMailboxes
@@ -98,13 +106,17 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
: CrossAxisAlignment.center, : CrossAxisAlignment.center,
children: [ children: [
if (_isIconDisplayed) if (_isIconDisplayed)
MailboxIconWidget(icon: _iconMailbox), MailboxIconWidget(
icon: _iconMailbox,
color: widget.iconColor,
),
Expanded( Expanded(
child: LabelMailboxItemWidget( child: LabelMailboxItemWidget(
itemKey: _key, itemKey: _key,
mailboxNode: widget.mailboxNode, mailboxNode: widget.mailboxNode,
isItemHovered: _isItemHovered, isItemHovered: _isItemHovered,
isSelected: _isSelected, isSelected: _isSelected,
textStyle: widget.textStyle,
onMenuActionClick: widget.onMenuActionClick, onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback, onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick, onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
@@ -143,9 +155,9 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
padding: const EdgeInsetsDirectional.symmetric( padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.itemPadding, horizontal: MailboxItemWidgetStyles.itemPadding,
), ),
height: widget.mailboxNode.item.isTeamMailboxes height: widget.itemHeight ?? (widget.mailboxNode.item.isTeamMailboxes
? MailboxItemWidgetStyles.teamMailboxHeight ? MailboxItemWidgetStyles.teamMailboxHeight
: MailboxItemWidgetStyles.mobileHeight, : MailboxItemWidgetStyles.mobileHeight),
child: Row( child: Row(
children: [ children: [
if (_isIconDisplayed) if (_isIconDisplayed)
@@ -154,7 +166,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
padding: const EdgeInsetsDirectional.only( padding: const EdgeInsetsDirectional.only(
end: MailboxItemWidgetStyles.mobileLabelIconSpace, end: MailboxItemWidgetStyles.mobileLabelIconSpace,
), ),
color: AppColor.iconFolder, color: widget.iconColor ?? AppColor.iconFolder,
), ),
Expanded( Expanded(
child: LabelMailboxItemWidget( child: LabelMailboxItemWidget(
@@ -162,6 +174,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
mailboxNode: widget.mailboxNode, mailboxNode: widget.mailboxNode,
isItemHovered: _isItemHovered, isItemHovered: _isItemHovered,
isSelected: _isSelected, isSelected: _isSelected,
textStyle: widget.textStyle,
onMenuActionClick: widget.onMenuActionClick, onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback, onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick, onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
@@ -192,9 +205,9 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
padding: const EdgeInsetsDirectional.symmetric( padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.mobileItemPadding, horizontal: MailboxItemWidgetStyles.mobileItemPadding,
), ),
height: widget.mailboxNode.item.isTeamMailboxes height: widget.itemHeight ?? (widget.mailboxNode.item.isTeamMailboxes
? MailboxItemWidgetStyles.teamMailboxHeight ? MailboxItemWidgetStyles.teamMailboxHeight
: MailboxItemWidgetStyles.mobileHeight, : MailboxItemWidgetStyles.mobileHeight),
child: Row( child: Row(
children: [ children: [
if (_isIconDisplayed) if (_isIconDisplayed)
@@ -203,7 +216,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
padding: const EdgeInsetsDirectional.only( padding: const EdgeInsetsDirectional.only(
end: MailboxItemWidgetStyles.mobileLabelIconSpace, end: MailboxItemWidgetStyles.mobileLabelIconSpace,
), ),
color: AppColor.iconFolder, color: widget.iconColor ?? AppColor.iconFolder,
), ),
Expanded( Expanded(
child: LabelMailboxItemWidget( child: LabelMailboxItemWidget(
@@ -211,6 +224,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
mailboxNode: widget.mailboxNode, mailboxNode: widget.mailboxNode,
isItemHovered: _isItemHovered, isItemHovered: _isItemHovered,
isSelected: _isSelected, isSelected: _isSelected,
textStyle: widget.textStyle,
onMenuActionClick: widget.onMenuActionClick, onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback, onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick, onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
@@ -240,16 +254,19 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
padding: const EdgeInsetsDirectional.symmetric( padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.itemPadding, horizontal: MailboxItemWidgetStyles.itemPadding,
), ),
height: widget.mailboxNode.item.isTeamMailboxes height: widget.itemHeight ?? (widget.mailboxNode.item.isTeamMailboxes
? MailboxItemWidgetStyles.teamMailboxHeight ? MailboxItemWidgetStyles.teamMailboxHeight
: MailboxItemWidgetStyles.height, : MailboxItemWidgetStyles.height),
color: widget.mailboxNode.isSelected color: widget.mailboxNode.isSelected
? AppColor.colorItemSelected ? AppColor.colorItemSelected
: Colors.transparent, : Colors.transparent,
child: Row( child: Row(
children: [ children: [
if (_isIconDisplayed) if (_isIconDisplayed)
MailboxIconWidget(icon: _iconMailbox), MailboxIconWidget(
icon: _iconMailbox,
color: widget.iconColor,
),
Expanded( Expanded(
child: LabelMailboxItemWidget( child: LabelMailboxItemWidget(
itemKey: _key, itemKey: _key,
@@ -257,6 +274,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
showTrailing: false, showTrailing: false,
isSelected: _isSelected, isSelected: _isSelected,
isItemHovered: _isItemHovered, isItemHovered: _isItemHovered,
textStyle: widget.textStyle,
isSelectedFolderInModal: isSelectedFolderInModal, isSelectedFolderInModal: isSelectedFolderInModal,
onMenuActionClick: widget.onMenuActionClick, onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback, onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
@@ -265,9 +283,9 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
), ),
if (isSelectedFolderInModal) if (isSelectedFolderInModal)
SvgPicture.asset( SvgPicture.asset(
isFolderModalActive widget.iconSelected ?? (isFolderModalActive
? _imagePaths.icCheck ? _imagePaths.icCheck
: _imagePaths.icSelectedSB, : _imagePaths.icSelectedSB),
width: MailboxItemWidgetStyles.selectionIconSize, width: MailboxItemWidgetStyles.selectionIconSize,
height: MailboxItemWidgetStyles.selectionIconSize, height: MailboxItemWidgetStyles.selectionIconSize,
fit: BoxFit.fill fit: BoxFit.fill
@@ -1,4 +1,4 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
@@ -14,8 +14,11 @@ import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification
import 'package:tmail_ui_user/features/mailbox_creator/domain/state/verify_name_view_state.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/state/verify_name_view_state.dart';
import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/extensions/validator_failure_extension.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/extensions/validator_failure_extension.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/bottom_modal_folder_tree_arguments.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_mailbox_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_mailbox_arguments.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/widgets/bottom_modal/bottom_modal_folder_tree_list_bindings.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/widgets/bottom_modal/bottom_modal_folder_tree_list_widget.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class MailboxCreatorController extends BaseController class MailboxCreatorController extends BaseController
@@ -124,13 +127,20 @@ class MailboxCreatorController extends BaseController
void openFolderModal(BuildContext context) { void openFolderModal(BuildContext context) {
nameInputFocusNode.unfocus(); nameInputFocusNode.unfocus();
if (!responsiveUtils.isMobile(context)) { if (responsiveUtils.isMobile(context)) {
_showFolderListBottomModal(context);
} else {
isFolderModalEnabled.value = true; isFolderModalEnabled.value = true;
} }
} }
void selectMailboxLocation(MailboxNode? mailboxDestination) { void selectMailboxLocation(
isFolderModalEnabled.value = false; BuildContext context,
MailboxNode? mailboxDestination,
) {
if (!responsiveUtils.isMobile(context)) {
isFolderModalEnabled.value = false;
}
selectedMailbox.value = mailboxDestination?.item; selectedMailbox.value = mailboxDestination?.item;
_createListMailboxNameAsStringInMailboxLocation(); _createListMailboxNameAsStringInMailboxLocation();
} }
@@ -177,6 +187,41 @@ class MailboxCreatorController extends BaseController
} }
} }
Future<void> _showFolderListBottomModal(BuildContext context) async {
BottomModalFolderTreeListBindings().dependencies();
final result = await showModalBottomSheet(
context: context,
showDragHandle: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
),
),
backgroundColor: Colors.white,
routeSettings: RouteSettings(
arguments: BottomModalFolderTreeArguments(
defaultMailboxTree.value,
personalMailboxTree.value,
selectedMailbox.value,
),
),
builder: (_) => const BottomModalFolderTreeListWidget(),
).whenComplete(BottomModalFolderTreeListBindings().dispose);
if (result is PresentationMailbox) {
if (result.id == MailboxNode.root().item.id) {
selectedMailbox.value = null;
} else {
selectedMailbox.value = result;
}
_createListMailboxNameAsStringInMailboxLocation();
}
}
void closeView() { void closeView() {
nameInputFocusNode.unfocus(); nameInputFocusNode.unfocus();
popBack(); popBack();
@@ -2,6 +2,7 @@ import 'dart:math';
import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/theme_utils.dart'; import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/widget/default_field/default_button_arrow_down_field_widget.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_button_arrow_down_field_widget.dart';
@@ -159,10 +160,9 @@ class MailboxCreatorView extends GetWidget<MailboxCreatorController> {
defaultTree: controller.defaultMailboxTree.value, defaultTree: controller.defaultMailboxTree.value,
personalTree: controller.personalMailboxTree.value, personalTree: controller.personalMailboxTree.value,
imagePaths: controller.imagePaths, imagePaths: controller.imagePaths,
listScrollController: listScrollController: controller.listFolderScrollController,
controller.listFolderScrollController,
mailboxIdSelected: selectedMailbox?.id, mailboxIdSelected: selectedMailbox?.id,
onSelectFolderAction: controller.selectMailboxLocation, onSelectFolderAction: (node) => controller.selectMailboxLocation(context, node),
onToggleFolderAction: controller.toggleFolder, onToggleFolderAction: controller.toggleFolder,
)), )),
) )
@@ -197,6 +197,21 @@ class MailboxCreatorView extends GetWidget<MailboxCreatorController> {
), ),
); );
return Center(child: bodyWidget); bodyWidget = Center(child: bodyWidget);
if (PlatformInfo.isMobile) {
bodyWidget = GestureDetector(
onTap: controller.closeView,
child: Scaffold(
backgroundColor: AppColor.blackAlpha20,
body: GestureDetector(
onTap: controller.nameInputFocusNode.unfocus,
child: bodyWidget,
),
),
);
}
return bodyWidget;
} }
} }
@@ -0,0 +1,23 @@
import 'package:equatable/equatable.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
class BottomModalFolderTreeArguments with EquatableMixin {
final MailboxTree personalMailboxTree;
final MailboxTree defaultMailboxTree;
final PresentationMailbox? selectedMailbox;
BottomModalFolderTreeArguments(
this.defaultMailboxTree,
this.personalMailboxTree,
this.selectedMailbox,
);
@override
List<Object?> get props => [
defaultMailboxTree,
personalMailboxTree,
selectedMailbox,
];
}
@@ -0,0 +1,13 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/widgets/bottom_modal/bottom_modal_folder_tree_list_controller.dart';
class BottomModalFolderTreeListBindings extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => BottomModalFolderTreeListController());
}
void dispose() {
Get.delete<BottomModalFolderTreeListController>();
}
}
@@ -0,0 +1,64 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/base/mixin/expand_folder_trigger_scrollable_mixin.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/expand_mode_extension.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_creator/presentation/model/bottom_modal_folder_tree_arguments.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class BottomModalFolderTreeListController extends BaseController
with ExpandFolderTriggerScrollableMixin {
final personalMailboxTree = MailboxTree(MailboxNode.root()).obs;
final defaultMailboxTree = MailboxTree(MailboxNode.root()).obs;
final mailboxIdSelected = Rxn<MailboxId>();
final ScrollController listFolderScrollController = ScrollController();
@override
void onInit() {
super.onInit();
BottomModalFolderTreeArguments? arguments = Get.arguments;
if (arguments != null) {
personalMailboxTree.value = arguments.personalMailboxTree;
defaultMailboxTree.value = arguments.defaultMailboxTree;
mailboxIdSelected.value = arguments.selectedMailbox?.id;
}
}
void selectFolderAction(MailboxNode? mailboxNode) {
final selectedMailbox = mailboxNode?.item;
popBack(result: selectedMailbox);
}
void toggleFolder(MailboxNode selectedMailboxNode, GlobalKey itemKey) {
final newExpandMode = selectedMailboxNode.expandMode.toggle();
if (defaultMailboxTree.value.updateExpandedNode(selectedMailboxNode, newExpandMode) != null) {
defaultMailboxTree.refresh();
triggerScrollWhenExpandFolder(
selectedMailboxNode.expandMode,
itemKey,
listFolderScrollController,
);
}
if (personalMailboxTree.value.updateExpandedNode(selectedMailboxNode, newExpandMode) != null) {
personalMailboxTree.refresh();
triggerScrollWhenExpandFolder(
selectedMailboxNode.expandMode,
itemKey,
listFolderScrollController,
);
}
}
@override
void onClose() {
listFolderScrollController.dispose();
super.onClose();
}
}
@@ -0,0 +1,154 @@
import 'dart:math';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/presentation/views/list/tree_view.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/mailbox/expand_mode.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';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/folder_item_widget.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_item_widget.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/widgets/bottom_modal/bottom_modal_folder_tree_list_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class BottomModalFolderTreeListWidget extends GetWidget<BottomModalFolderTreeListController> {
const BottomModalFolderTreeListWidget({super.key});
@override
Widget build(BuildContext context) {
Widget bodyWidget = Container(
constraints: BoxConstraints(
maxHeight: min(
controller.responsiveUtils.getSizeScreenHeight(context) - 32,
469,
),
),
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
controller: controller.listFolderScrollController,
padding: const EdgeInsetsDirectional.all(14),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Obx(() => FolderItemWidget(
folderName: AppLocalizations.of(context).personalFolders,
imagePaths: controller.imagePaths,
isSelected: controller.mailboxIdSelected.value == null,
iconColor: AppColor.gray424244.withValues(alpha: 0.72),
iconSelected: controller.imagePaths.icChecked,
textStyle: ThemeUtils.textStyleInter400.copyWith(
color: AppColor.gray424244.withValues(alpha: 0.9),
fontSize: 16,
height: 21.01 / 16,
letterSpacing: -0.15,
),
onTapAction: () =>
controller.selectFolderAction(MailboxNode.root()),
)),
Obx(() {
final defaultTree = controller.defaultMailboxTree.value;
if (defaultTree.root.hasChildren()) {
return _buildFolderTree(
mailboxTree: defaultTree,
mailboxIdSelected: controller.mailboxIdSelected.value,
);
} else {
return const SizedBox.shrink();
}
}),
Obx(() {
final personalTree = controller.personalMailboxTree.value;
if (personalTree.root.hasChildren()) {
return _buildFolderTree(
mailboxTree: personalTree,
mailboxIdSelected: controller.mailboxIdSelected.value,
);
} else {
return const SizedBox.shrink();
}
}),
],
),
),
);
if (PlatformInfo.isMobile) {
return SafeArea(child: bodyWidget);
} else {
return bodyWidget;
}
}
Widget _buildFolderTree({
required MailboxTree mailboxTree,
MailboxId? mailboxIdSelected,
}) {
return TreeView(
children: _buildListChildTileWidget(
parentNode: mailboxTree.root,
mailboxIdSelected: mailboxIdSelected,
),
);
}
List<Widget> _buildListChildTileWidget({
required MailboxNode parentNode,
MailboxId? mailboxIdSelected,
}) {
return parentNode.childrenItems?.map(
(mailboxNode) {
if (mailboxNode.hasChildren()) {
return TreeViewChild(
isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND,
paddingChild: const EdgeInsetsDirectional.only(start: 14),
parent: MailboxItemWidget(
mailboxNode: mailboxNode,
mailboxIdAlreadySelected: mailboxIdSelected,
mailboxDisplayed: MailboxDisplayed.modalFolder,
hoverColor: AppColor.blue100,
iconColor: AppColor.gray424244.withValues(alpha: 0.72),
textStyle: ThemeUtils.textStyleInter400.copyWith(
color: AppColor.gray424244.withValues(alpha: 0.9),
fontSize: 16,
height: 21.01 / 16,
letterSpacing: -0.15,
),
itemHeight: 48,
iconSelected: controller.imagePaths.icChecked,
onOpenMailboxFolderClick: controller.selectFolderAction,
onExpandFolderActionClick: controller.toggleFolder,
),
children: _buildListChildTileWidget(
parentNode: mailboxNode,
mailboxIdSelected: mailboxIdSelected,
),
).build();
} else {
return MailboxItemWidget(
mailboxNode: mailboxNode,
mailboxDisplayed: MailboxDisplayed.modalFolder,
mailboxIdAlreadySelected: mailboxIdSelected,
hoverColor: AppColor.blue100,
iconColor: AppColor.gray424244.withValues(alpha: 0.72),
textStyle: ThemeUtils.textStyleInter400.copyWith(
color: AppColor.gray424244.withValues(alpha: 0.9),
fontSize: 16,
height: 21.01 / 16,
letterSpacing: -0.15,
),
itemHeight: 48,
iconSelected: controller.imagePaths.icChecked,
onOpenMailboxFolderClick: controller.selectFolderAction,
onExpandFolderActionClick: controller.toggleFolder,
);
}
},
).toList() ?? [];
}
}
+2 -3
View File
@@ -29,7 +29,7 @@ class DialogRouter {
barrierDismissible: true, barrierDismissible: true,
barrierLabel: routeName, barrierLabel: routeName,
routeSettings: RouteSettings(arguments: arguments), routeSettings: RouteSettings(arguments: arguments),
pageBuilder: (_, __, ___) => _generateView(routeName: routeName, arguments: arguments) pageBuilder: (_, __, ___) => _generateView(routeName: routeName)
); );
_isDialogOpened.value = false; _isDialogOpened.value = false;
@@ -69,8 +69,7 @@ class DialogRouter {
} }
} }
static Widget _generateView({required String routeName, required Object? arguments}) { static Widget _generateView({required String routeName}) {
log('DialogRouter::_generateView():routeName: $routeName | arguments: $arguments');
switch(routeName) { switch(routeName) {
case AppRoutes.mailboxCreator: case AppRoutes.mailboxCreator:
return MailboxCreatorView(); return MailboxCreatorView();