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

This commit is contained in:
dab246
2025-09-04 15:06:28 +07:00
committed by Dat H. Pham
parent c09a2c92b2
commit 36e58fc990
23 changed files with 689 additions and 498 deletions
@@ -52,24 +52,20 @@ class _TreeViewData extends StatelessWidget {
}
class TreeViewChild {
final BuildContext context;
final bool? isExpanded;
final Widget parent;
final List<Widget> children;
final VoidCallback? onTap;
final EdgeInsetsGeometry? paddingChild;
TreeViewChild(
this.context,
{
required this.parent,
required this.children,
this.isExpanded,
this.onTap,
this.paddingChild,
Key? key,
}
);
TreeViewChild({
required this.parent,
required this.children,
this.isExpanded,
this.onTap,
this.paddingChild,
Key? key,
});
Widget build() {
return Column(
+3 -39
View File
@@ -19,6 +19,7 @@ import 'package:tmail_ui_user/features/base/action/update_mailbox_properties_act
import 'package:tmail_ui_user/features/base/action/update_mailbox_properties_action/update_mailbox_total_emails_count_action.dart';
import 'package:tmail_ui_user/features/base/action/update_mailbox_properties_action/update_mailbox_unread_count_action.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/base/mixin/message_dialog_action_manager.dart';
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_action_state.dart';
@@ -55,7 +56,8 @@ typedef MovingMailboxActionCallback = void Function(PresentationMailbox mailboxS
typedef DeleteMailboxActionCallback = void Function(PresentationMailbox mailbox);
typedef AllowSubaddressingActionCallback = void Function(MailboxId, Map<String, List<String>?>?, MailboxActions);
abstract class BaseMailboxController extends BaseController {
abstract class BaseMailboxController extends BaseController
with ExpandFolderTriggerScrollableMixin {
final TreeBuilder _treeBuilder;
final VerifyNameInteractor verifyNameInteractor;
final GetAllMailboxInteractor? getAllMailboxInteractor;
@@ -159,44 +161,6 @@ abstract class BaseMailboxController extends BaseController {
}
}
void triggerScrollWhenExpandFolder(
ExpandMode expandMode,
GlobalKey itemKey,
ScrollController scrollController,
) {
if (expandMode == ExpandMode.COLLAPSE) return;
final context = itemKey.currentContext;
if (context == null) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToSelfIfNeeded(context, scrollController);
});
}
void _scrollToSelfIfNeeded(
BuildContext context,
ScrollController scrollController,
) {
final renderBox = context.findRenderObject() as RenderBox?;
if (renderBox == null) return;
final position = renderBox.localToGlobal(Offset.zero);
final screenHeight = MediaQuery.of(context).size.height;
const offsetY = 200;
final bottomY = position.dy + renderBox.size.height + offsetY;
log('BaseMailboxController::_scrollToSelfIfNeeded:position = $position |screenHeight = $screenHeight | bottomY = $bottomY');
if (bottomY > screenHeight) {
final scrollOffset = scrollController.offset + bottomY - screenHeight + 40;
log('BaseMailboxController::_scrollToSelfIfNeeded:scrollOffset = $scrollOffset:');
scrollController.animateTo(
scrollOffset,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
}
void selectMailboxNode(MailboxNode mailboxNodeSelected) {
final newSelectMode = mailboxNodeSelected.selectMode == SelectMode.INACTIVE
? SelectMode.ACTIVE
@@ -0,0 +1,44 @@
import 'package:core/utils/app_logger.dart';
import 'package:flutter/material.dart';
import 'package:model/mailbox/expand_mode.dart';
mixin ExpandFolderTriggerScrollableMixin {
void triggerScrollWhenExpandFolder(
ExpandMode expandMode,
GlobalKey itemKey,
ScrollController scrollController,
) {
if (expandMode == ExpandMode.COLLAPSE) return;
final context = itemKey.currentContext;
if (context == null) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToSelfIfNeeded(context, scrollController);
});
}
void _scrollToSelfIfNeeded(
BuildContext context,
ScrollController scrollController,
) {
final renderBox = context.findRenderObject() as RenderBox?;
if (renderBox == null) return;
final position = renderBox.localToGlobal(Offset.zero);
final screenHeight = MediaQuery.of(context).size.height;
const offsetY = 200;
final bottomY = position.dy + renderBox.size.height + offsetY;
log('$runtimeType::_scrollToSelfIfNeeded:position = $position |screenHeight = $screenHeight | bottomY = $bottomY');
if (bottomY > screenHeight) {
final scrollOffset =
scrollController.offset + bottomY - screenHeight + 40;
log('$runtimeType::_scrollToSelfIfNeeded:scrollOffset = $scrollOffset:');
scrollController.animateTo(
scrollOffset,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
}
}
@@ -7,12 +7,14 @@ class DefaultButtonArrowDownFieldWidget extends StatelessWidget {
final String text;
final String iconArrowDown;
final VoidCallback onTap;
final Widget? icon;
const DefaultButtonArrowDownFieldWidget({
super.key,
required this.text,
required this.iconArrowDown,
required this.onTap,
this.icon,
});
@override
@@ -35,6 +37,7 @@ class DefaultButtonArrowDownFieldWidget extends StatelessWidget {
padding: const EdgeInsetsDirectional.only(start: 12, end: 8),
child: Row(
children: [
if (icon != null) icon!,
Expanded(
child: Text(
text,
@@ -0,0 +1,58 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/views/dialog/confirm_dialog_button.dart';
import 'package:flutter/material.dart';
class ModalListActionButtonWidget extends StatelessWidget {
final String positiveLabel;
final String negativeLabel;
final VoidCallback onNegativeAction;
final VoidCallback onPositiveAction;
final EdgeInsetsGeometry? padding;
const ModalListActionButtonWidget({
super.key,
required this.positiveLabel,
required this.negativeLabel,
required this.onPositiveAction,
required this.onNegativeAction,
this.padding,
});
@override
Widget build(BuildContext context) {
Widget negativeButton = Container(
constraints: const BoxConstraints(minWidth: 67),
height: 48,
child: ConfirmDialogButton(
label: negativeLabel,
onTapAction: onNegativeAction,
),
);
Widget positiveButton = Container(
constraints: const BoxConstraints(minWidth: 153),
height: 48,
child: ConfirmDialogButton(
label: positiveLabel,
backgroundColor: AppColor.primaryMain,
textColor: Colors.white,
onTapAction: onPositiveAction,
),
);
Widget bodyWidget = Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Flexible(child: negativeButton),
const SizedBox(width: 8),
Flexible(child: positiveButton),
],
);
if (padding != null) {
return Padding(padding: padding!, child: bodyWidget);
} else {
return bodyWidget;
}
}
}
@@ -32,7 +32,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_icon_
import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_item_widget_styles.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_category_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/create_mailbox_name_input_decoration_builder.dart';
import 'package:tmail_ui_user/features/destination_picker/presentation/widgets/create_mailbox_name_input_decoration_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_bar_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
@@ -413,7 +413,6 @@ class DestinationPickerView extends GetWidget<DestinationPickerController>
?.map((mailboxNode) {
if (mailboxNode.hasChildren()) {
return TreeViewChild(
context,
key: const Key('children_tree_mailbox_child'),
isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND,
paddingChild: const EdgeInsetsDirectional.only(start: 14),
@@ -422,7 +421,9 @@ class DestinationPickerView extends GetWidget<DestinationPickerController>
mailboxActions: actions,
mailboxIdAlreadySelected: mailboxIdSelected,
mailboxDisplayed: MailboxDisplayed.destinationPicker,
onOpenMailboxFolderClick: (node) => _pickMailboxNode(context, node),
onOpenMailboxFolderClick: (node) => node != null
? _pickMailboxNode(context, node)
: null,
onExpandFolderActionClick: (mailboxNode, itemKey) =>
controller.toggleMailboxFolder(
mailboxNode,
@@ -443,7 +444,9 @@ class DestinationPickerView extends GetWidget<DestinationPickerController>
mailboxDisplayed: MailboxDisplayed.destinationPicker,
mailboxIdAlreadySelected: mailboxIdSelected,
mailboxActions: actions,
onOpenMailboxFolderClick: (node) => _pickMailboxNode(context, node),
onOpenMailboxFolderClick: (node) => node != null
? _pickMailboxNode(context, node)
: null,
);
}})
.toList() ?? <Widget>[];
@@ -199,7 +199,9 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
.selectedMailbox
.value,
onOpenMailboxFolderClick: (mailboxNode) =>
controller.openMailbox(context, mailboxNode.item),
mailboxNode != null
? controller.openMailbox(context, mailboxNode.item)
: null,
onExpandFolderActionClick: mailboxNode.hasChildren()
? (mailboxNode, itemKey) => controller.toggleMailboxFolder(
mailboxNode,
@@ -228,7 +230,6 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
if (mailboxNode.hasChildren()) {
return TreeViewChild(
context,
key: const Key('children_tree_mailbox_child'),
isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND,
paddingChild: const EdgeInsetsDirectional.only(start: 12),
@@ -843,15 +843,12 @@ class MailboxController extends BaseMailboxController
}
void goToCreateNewMailboxView(BuildContext context, {PresentationMailbox? parentMailbox}) async {
if (session !=null && accountId != null) {
if (session != null && accountId != null) {
final arguments = MailboxCreatorArguments(
accountId!,
defaultMailboxTree.value,
personalMailboxTree.value,
teamMailboxesTree.value,
mailboxDashBoardController.sessionCurrent!,
parentMailbox
);
defaultMailboxTree.value,
personalMailboxTree.value,
parentMailbox,
);
final result = PlatformInfo.isWeb
? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.mailboxCreator, arguments: arguments)
@@ -1,5 +1,6 @@
enum MailboxDisplayed {
mailbox,
destinationPicker
destinationPicker,
modalFolder;
}
@@ -11,7 +11,7 @@ typedef OnDragEmailToMailboxAccepted = void Function(List<PresentationEmail>, Pr
typedef OnLongPressMailboxAction = void Function(PresentationMailbox);
typedef OnClickExpandMailboxNodeAction = void Function(MailboxNode, GlobalKey itemKey);
typedef OnClickOpenMailboxNodeAction = void Function(MailboxNode);
typedef OnClickOpenMailboxNodeAction = void Function(MailboxNode?);
typedef OnSelectMailboxNodeAction = void Function(MailboxNode);
typedef OnClickOpenMenuMailboxNodeAction = Future<void> Function(RelativeRect, MailboxNode);
typedef OnLongPressMailboxNodeAction = void Function(MailboxNode);
@@ -0,0 +1,84 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_icon_widget_styles.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_item_widget_styles.dart';
class FolderItemWidget extends StatelessWidget {
final ImagePaths imagePaths;
final String folderName;
final bool isSelected;
final VoidCallback? onTapAction;
const FolderItemWidget({
super.key,
required this.imagePaths,
required this.folderName,
this.isSelected = false,
this.onTapAction,
});
@override
Widget build(BuildContext context) {
Widget itemWidget = Container(
padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.itemPadding,
),
height: MailboxItemWidgetStyles.height,
child: Row(
children: [
SvgPicture.asset(
imagePaths.icFolderMailbox,
width: MailboxIconWidgetStyles.iconSize,
height: MailboxIconWidgetStyles.iconSize,
colorFilter: AppColor.primaryLinShare.asFilter(),
fit: BoxFit.fill,
),
const SizedBox(width: MailboxItemWidgetStyles.labelIconSpace),
Expanded(
child: Text(
folderName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: isSelected
? ThemeUtils.textStyleInter700(
color: Colors.black,
fontSize: 14,
)
: ThemeUtils.textStyleBodyBody3(
color: Colors.black,
),
),
),
const SizedBox(width: MailboxItemWidgetStyles.labelIconSpace),
if (isSelected)
SvgPicture.asset(
imagePaths.icCheck,
width: MailboxIconWidgetStyles.iconSize,
height: MailboxIconWidgetStyles.iconSize,
colorFilter: AppColor.primaryLinShare.asFilter(),
fit: BoxFit.fill,
),
],
),
);
if (onTapAction != null) {
return Material(
type: MaterialType.transparency,
child: InkWell(
borderRadius: const BorderRadius.all(
Radius.circular(MailboxItemWidgetStyles.borderRadius),
),
hoverColor: AppColor.blue100,
onTap: onTapAction,
child: itemWidget,
),
);
} else {
return itemWidget;
}
}
}
@@ -24,6 +24,7 @@ class LabelMailboxItemWidget extends StatefulWidget {
final bool showTrailing;
final bool isItemHovered;
final bool isSelected;
final bool isSelectedFolderInModal;
final OnClickOpenMenuMailboxNodeAction? onMenuActionClick;
final OnEmptyMailboxActionCallback? onEmptyMailboxActionCallback;
final OnClickExpandMailboxNodeAction? onClickExpandMailboxNodeAction;
@@ -35,6 +36,7 @@ class LabelMailboxItemWidget extends StatefulWidget {
this.showTrailing = true,
this.isItemHovered = false,
this.isSelected = false,
this.isSelectedFolderInModal = false,
this.onMenuActionClick,
this.onEmptyMailboxActionCallback,
this.onClickExpandMailboxNodeAction,
@@ -219,6 +221,11 @@ class _LabelMailboxItemWidgetState extends State<LabelMailboxItemWidget> {
color: _responsiveUtils.isDesktop(context) ? null : AppColor.iconFolder,
fontSize: 14,
);
} else if (widget.isSelectedFolderInModal) {
return ThemeUtils.textStyleInter700(
color: Colors.black,
fontSize: 14,
);
} else {
return _responsiveUtils.isWebDesktop(context)
? ThemeUtils.textStyleBodyBody3(color: Colors.black)
@@ -25,6 +25,7 @@ class MailboxItemWidget extends StatefulWidget {
final PresentationMailbox? mailboxNodeSelected;
final MailboxActions? mailboxActions;
final MailboxId? mailboxIdAlreadySelected;
final Color? hoverColor;
final OnClickExpandMailboxNodeAction? onExpandFolderActionClick;
final OnClickOpenMailboxNodeAction? onOpenMailboxFolderClick;
@@ -41,6 +42,7 @@ class MailboxItemWidget extends StatefulWidget {
this.mailboxNodeSelected,
this.mailboxActions,
this.mailboxIdAlreadySelected,
this.hoverColor,
this.onExpandFolderActionClick,
this.onOpenMailboxFolderClick,
this.onSelectMailboxFolderClick,
@@ -229,11 +231,11 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => !_isSelectActionNoValid
? widget.onOpenMailboxFolderClick?.call(widget.mailboxNode)
onTap: !isSelectedFolderInModal
? () => widget.onOpenMailboxFolderClick?.call(widget.mailboxNode)
: null,
customBorder: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8))),
hoverColor: AppColor.colorMailboxHovered,
hoverColor: widget.hoverColor ?? AppColor.colorMailboxHovered,
child: Container(
padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.itemPadding,
@@ -255,14 +257,17 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
showTrailing: false,
isSelected: _isSelected,
isItemHovered: _isItemHovered,
isSelectedFolderInModal: isSelectedFolderInModal,
onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
)
),
if (_isSelectActionNoValid)
if (isSelectedFolderInModal)
SvgPicture.asset(
_imagePaths.icSelectedSB,
isFolderModalActive
? _imagePaths.icCheck
: _imagePaths.icSelectedSB,
width: MailboxItemWidgetStyles.selectionIconSize,
height: MailboxItemWidgetStyles.selectionIconSize,
fit: BoxFit.fill
@@ -282,24 +287,25 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
widget.mailboxNodeSelected?.id == widget.mailboxNode.item.id;
Color get backgroundColorItem {
if (widget.mailboxDisplayed == MailboxDisplayed.destinationPicker) {
return Colors.white;
} else {
if (_isSelected) {
return AppColor.blue100;
} else {
return Colors.transparent;
}
if (widget.mailboxDisplayed == MailboxDisplayed.mailbox) {
return _isSelected ? AppColor.blue100 : Colors.transparent;
}
return Colors.white;
}
bool get _isSelectActionNoValid => widget.mailboxNode.item.id == widget.mailboxIdAlreadySelected &&
widget.mailboxDisplayed == MailboxDisplayed.destinationPicker &&
(
widget.mailboxActions == MailboxActions.select ||
widget.mailboxActions == MailboxActions.create ||
widget.mailboxActions == MailboxActions.moveEmail
);
bool get isFolderModalActive =>
widget.mailboxDisplayed == MailboxDisplayed.modalFolder;
bool get isSelectedFolderInModal {
final isDestinationPickerActive =
widget.mailboxDisplayed == MailboxDisplayed.destinationPicker &&
(widget.mailboxActions == MailboxActions.select ||
widget.mailboxActions == MailboxActions.create ||
widget.mailboxActions == MailboxActions.moveEmail);
return widget.mailboxNode.item.id == widget.mailboxIdAlreadySelected &&
(isDestinationPickerActive || isFolderModalActive);
}
bool get _isIconDisplayed =>
widget.mailboxNode.item.isPersonal ||
@@ -1,14 +1,10 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.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/domain/model/verification/duplicate_name_validator.dart';
@@ -20,27 +16,24 @@ import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_na
import 'package:tmail_ui_user/features/mailbox_creator/presentation/extensions/validator_failure_extension.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/main/routes/app_routes.dart';
import 'package:tmail_ui_user/main/routes/dialog_router.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class MailboxCreatorController extends BaseController {
class MailboxCreatorController extends BaseController
with ExpandFolderTriggerScrollableMixin {
final VerifyNameInteractor _verifyNameInteractor;
final selectedMailbox = Rxn<PresentationMailbox>();
final newNameMailbox = Rxn<String>();
final isFolderModalEnabled = RxBool(false);
bool _createdMailbox = false;
final personalMailboxTree = MailboxTree(MailboxNode.root()).obs;
final defaultMailboxTree = MailboxTree(MailboxNode.root()).obs;
final FocusNode nameInputFocusNode = FocusNode();
final TextEditingController nameInputController = TextEditingController();
MailboxCreatorArguments? arguments;
AccountId? accountId;
Session? _session;
MailboxTree? defaultMailboxTree;
MailboxTree? personalMailboxTree;
MailboxTree? teamMailboxesTre;
final ScrollController listFolderScrollController = ScrollController();
List<String> listMailboxNameAsStringExist = <String>[];
@@ -51,47 +44,35 @@ class MailboxCreatorController extends BaseController {
@override
void onInit() {
super.onInit();
log('MailboxCreatorController::onInit():arguments: ${Get.arguments}');
arguments = Get.arguments;
}
@override
void onReady() {
super.onReady();
log('MailboxCreatorController::onReady():');
MailboxCreatorArguments? arguments = Get.arguments;
if (arguments != null) {
personalMailboxTree = arguments!.personalMailboxTree;
defaultMailboxTree = arguments!.defaultMailboxTree;
teamMailboxesTre = arguments!.teamMailboxesTree;
accountId = arguments!.accountId;
_session = arguments!.session;
if (arguments!.selectedMailbox != null) {
selectedMailbox.value = arguments!.selectedMailbox;
}
personalMailboxTree.value = arguments.personalMailboxTree;
defaultMailboxTree.value = arguments.defaultMailboxTree;
selectedMailbox.value = arguments.selectedMailbox;
_createListMailboxNameAsStringInMailboxLocation();
}
}
@override
void onClose() {
log('MailboxCreatorController::onClose():');
listMailboxNameAsStringExist = [];
_createdMailbox = false;
nameInputFocusNode.dispose();
nameInputController.dispose();
listFolderScrollController.dispose();
super.onClose();
}
MailboxNode? _findMailboxNodeById(MailboxId mailboxId) {
final mailboxNode = defaultMailboxTree?.findNode((node) => node.item.id == mailboxId)
?? personalMailboxTree?.findNode((node) => node.item.id == mailboxId)
?? teamMailboxesTre?.findNode((node) => node.item.id == mailboxId);
final mailboxNode = defaultMailboxTree.value.findNode((node) => node.item.id == mailboxId)
?? personalMailboxTree.value.findNode((node) => node.item.id == mailboxId);
return mailboxNode;
}
void _createListMailboxNameAsStringInMailboxLocation() {
if (selectedMailbox.value == null) {
final allChildrenAtMailboxLocation = (defaultMailboxTree?.root.childrenItems ?? <MailboxNode>[])
+ (personalMailboxTree?.root.childrenItems ?? <MailboxNode>[])
+ (teamMailboxesTre?.root.childrenItems ?? <MailboxNode>[]);
final allChildrenAtMailboxLocation = (defaultMailboxTree.value.root.childrenItems ?? <MailboxNode>[])
+ (personalMailboxTree.value.root.childrenItems ?? <MailboxNode>[]);
if (allChildrenAtMailboxLocation.isNotEmpty) {
listMailboxNameAsStringExist = allChildrenAtMailboxLocation
.where((mailboxNode) => mailboxNode.nameNotEmpty)
@@ -140,33 +121,22 @@ class MailboxCreatorController extends BaseController {
);
}
void selectMailboxLocation(BuildContext context) async {
KeyboardUtils.hideKeyboard(context);
void openFolderModal(BuildContext context) {
nameInputFocusNode.unfocus();
if (accountId != null) {
final arguments = DestinationPickerArguments(
accountId!,
MailboxActions.create,
_session,
mailboxIdSelected: selectedMailbox.value?.id);
final destinationMailbox = PlatformInfo.isWeb
? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.destinationPicker, arguments: arguments)
: await push(AppRoutes.destinationPicker, arguments: arguments);
if (destinationMailbox is PresentationMailbox) {
final mailboxDestination = destinationMailbox == PresentationMailbox.unifiedMailbox
? null
: destinationMailbox;
selectedMailbox.value = mailboxDestination;
_createListMailboxNameAsStringInMailboxLocation();
}
if (!responsiveUtils.isMobile(context)) {
isFolderModalEnabled.value = true;
}
}
void selectMailboxLocation(MailboxNode? mailboxDestination) {
isFolderModalEnabled.value = false;
selectedMailbox.value = mailboxDestination?.item;
_createListMailboxNameAsStringInMailboxLocation();
}
void createNewMailbox(BuildContext context) {
KeyboardUtils.hideKeyboard(context);
nameInputFocusNode.unfocus();
final nameMailbox = newNameMailbox.value;
final nameValidated = getErrorInputNameString(context);
@@ -180,11 +150,35 @@ class MailboxCreatorController extends BaseController {
MailboxName(nameMailbox),
mailboxLocation: selectedMailbox.value);
popBack(result: newMailboxArguments);
} else {
newNameMailbox.refresh();
}
}
void closeMailboxCreator(BuildContext context) {
KeyboardUtils.hideKeyboard(context);
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,
);
}
}
void closeView() {
nameInputFocusNode.unfocus();
popBack();
}
}
@@ -1,24 +1,20 @@
import 'dart:math';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/style_utils.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/presentation/views/text/text_field_builder.dart';
import 'package:core/utils/app_logger.dart';
import 'package:core/utils/direction_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:pointer_interceptor/pointer_interceptor.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_close_button_widget.dart';
import 'package:tmail_ui_user/features/base/widget/label_input_field_builder.dart';
import 'package:tmail_ui_user/features/base/widget/modal_list_action_button_widget.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_icon_widget.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_controller.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/widgets/app_bar_mailbox_creator_builder.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/widgets/create_mailbox_name_input_decoration_builder.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/widgets/modal_folder_tree_list_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class MailboxCreatorView extends GetWidget<MailboxCreatorController> {
final _maxHeight = 656.0;
@override
final controller = Get.find<MailboxCreatorController>();
@@ -26,234 +22,181 @@ class MailboxCreatorView extends GetWidget<MailboxCreatorController> {
@override
Widget build(BuildContext context) {
log('MailboxCreatorView::build():');
return PointerInterceptor(
child: GestureDetector(
onTap: () => controller.closeMailboxCreator(context),
child: Card(
margin: EdgeInsets.zero,
borderOnForeground: false,
color: Colors.transparent,
child: SafeArea(
top: PlatformInfo.isMobile && controller.responsiveUtils.isPortraitMobile(context),
bottom: false,
left: false,
right: false,
child: Center(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Container(
margin: _getMarginView(context),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: _getRadiusView(context),
boxShadow: const [
BoxShadow(
color: AppColor.colorShadowLayerBottom,
blurRadius: 96,
spreadRadius: 96,
offset: Offset.zero),
BoxShadow(
color: AppColor.colorShadowLayerTop,
blurRadius: 2,
spreadRadius: 2,
offset: Offset.zero),
]),
width: _getWidthView(context),
height: _getHeightView(context),
child: ClipRRect(
borderRadius: _getRadiusView(context),
child: SafeArea(
top: false,
bottom: false,
left: PlatformInfo.isMobile && controller.responsiveUtils.isLandscapeMobile(context),
right: PlatformInfo.isMobile && controller.responsiveUtils.isLandscapeMobile(context),
child: Column(children: [
_buildAppBar(context),
const Divider(color: AppColor.colorDividerDestinationPicker, height: 1),
_buildCreateMailboxNameInput(context),
_buildMailboxLocation(context),
]),
)
)
),
)
),
final appLocalizations = AppLocalizations.of(context);
final theme = Theme.of(context);
Widget bodyWidget = Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(16)),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.08),
blurRadius: 24,
offset: const Offset(0, 2),
),
BoxShadow(
color: Colors.black.withValues(alpha: 0.08),
blurRadius: 2,
),
],
),
width: min(
controller.responsiveUtils.getSizeScreenWidth(context) - 32,
554,
),
constraints: BoxConstraints(
maxHeight: min(
controller.responsiveUtils.getSizeScreenHeight(context) - 100,
671,
),
),
);
}
clipBehavior: Clip.antiAlias,
child: Stack(
children: [
Padding(
padding: EdgeInsetsDirectional.only(
start: 32,
end: 32,
bottom: controller.responsiveUtils.isMobile(context) ? 0 : 16,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 64,
alignment: Alignment.center,
child: Text(
appLocalizations.createANewFolder,
style: theme.textTheme.headlineSmall?.copyWith(
color: AppColor.m3SurfaceBackground,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Obx(() {
final folderName =
controller.selectedMailbox.value?.getDisplayName(context) ??
appLocalizations.personalFolders;
return Center(
child: Text(
appLocalizations
.subtitleDisplayTheFolderNameLocationInFolderCreationModal(
folderName,
),
style: ThemeUtils.textStyleInter400.copyWith(
color: AppColor.steelGrayA540,
fontSize: 13,
height: 20 / 13,
),
textAlign: TextAlign.center,
),
);
}),
const SizedBox(height: 32),
Obx(
() => LabelInputFieldBuilder(
label: AppLocalizations.of(context).folderName,
hintText: AppLocalizations.of(context).enterTheFolderName,
textEditingController: controller.nameInputController,
focusNode: controller.nameInputFocusNode,
errorText: controller.getErrorInputNameString(context),
arrangeHorizontally: false,
isLabelHasColon: false,
labelStyle: ThemeUtils.textStyleInter600().copyWith(
fontSize: 14,
height: 18 / 14,
color: Colors.black,
),
runSpacing: 16,
inputFieldMaxWidth: double.infinity,
onTextChange: controller.setNewNameMailbox,
),
),
Padding(
padding: const EdgeInsets.only(top: 26, bottom: 16),
child: Text(
appLocalizations.selectTheFolderLocation,
style: ThemeUtils.textStyleInter600().copyWith(
fontSize: 14,
height: 18 / 14,
color: Colors.black,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Obx(() {
final selectedMailbox = controller.selectedMailbox.value;
final isFolderModalEnabled =
controller.isFolderModalEnabled.isTrue;
Widget _buildAppBar(BuildContext context) {
return (AppBarMailboxCreatorBuilder(
context,
title: AppLocalizations.of(context).newFolder,
isValidated: true)
..addOnCancelActionClick(() => controller.closeMailboxCreator(context))
..addOnDoneActionClick(() => controller.createNewMailbox(context)))
.build();
}
Widget _buildCreateMailboxNameInput(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Obx(() => TextFieldBuilder(
onTextChange: controller.setNewNameMailbox,
keyboardType: TextInputType.visiblePassword,
cursorColor: AppColor.colorTextButton,
controller: controller.nameInputController,
textDirection: DirectionUtils.getDirectionByLanguage(context),
maxLines: 1,
textStyle: ThemeUtils.defaultTextStyleInterFont.copyWith(
color: AppColor.colorNameEmail,
fontSize: 16,
overflow: CommonTextStyle.defaultTextOverFlow),
focusNode: controller.nameInputFocusNode,
decoration: (CreateMailboxNameInputDecorationBuilder()
..setHintText(AppLocalizations.of(context).hintInputCreateNewFolder)
..setErrorText(controller.getErrorInputNameString(context)))
.build(),
))
);
}
Widget _buildMailboxLocation(BuildContext context) {
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
child: Text(
AppLocalizations.of(context).selectParentFolder,
textAlign: TextAlign.left,
style: ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 13,
color: AppColor.colorHintSearchBar,
fontWeight: FontWeight.normal)),
),
Container(
alignment: Alignment.center,
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
color: AppColor.colorBgMailbox
return Flexible(
child: AnimatedSize(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
alignment: Alignment.topCenter,
child: isFolderModalEnabled
? Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
border: Border.all(
color: AppColor.m3Neutral90,
width: 1,
),
),
padding: const EdgeInsetsDirectional.only(
start: 14,
top: 13,
bottom: 13,
end: 4,
),
child: Obx(() => ModalFolderTreeListWidget(
defaultTree: controller.defaultMailboxTree.value,
personalTree: controller.personalMailboxTree.value,
imagePaths: controller.imagePaths,
listScrollController:
controller.listFolderScrollController,
mailboxIdSelected: selectedMailbox?.id,
onSelectFolderAction: controller.selectMailboxLocation,
onToggleFolderAction: controller.toggleFolder,
)),
)
: DefaultButtonArrowDownFieldWidget(
text: selectedMailbox?.getDisplayName(context) ??
appLocalizations.personalFolders,
icon: MailboxIconWidget(
icon: selectedMailbox?.getMailboxIcon(controller.imagePaths)
?? controller.imagePaths.icFolderMailbox,
),
iconArrowDown: controller.imagePaths.icDropDown,
onTap: () => controller.openFolderModal(context),
),
),
);
}),
ModalListActionButtonWidget(
positiveLabel: appLocalizations.createFolder,
negativeLabel: appLocalizations.cancel,
padding: const EdgeInsets.symmetric(vertical: 25),
onPositiveAction: () => controller.createNewMailbox(context),
onNegativeAction: controller.closeView,
)
],
),
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => controller.selectMailboxLocation(context),
customBorder: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
child: Row(children: [
const SizedBox(width: 12),
Obx(() => SvgPicture.asset(
controller.selectedMailbox.value?.getMailboxIcon(controller.imagePaths) ?? controller.imagePaths.icFolderMailbox,
width: PlatformInfo.isWeb ? 20 : 24,
height: PlatformInfo.isWeb ? 20 : 24,
fit: BoxFit.fill)),
const SizedBox(width: 12),
Expanded(child: Obx(() => Text(
controller.selectedMailbox.value?.getDisplayName(context) ?? AppLocalizations.of(context).allFolders,
maxLines: 1,
softWrap: CommonTextStyle.defaultSoftWrap,
overflow: CommonTextStyle.defaultTextOverFlow,
style: ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 15,
color: controller.selectedMailbox.value == null
? AppColor.colorHintSearchBar
: AppColor.colorNameEmail),
))),
const SizedBox(width: 12),
IconButton(
color: AppColor.primaryColor,
icon: SvgPicture.asset(
DirectionUtils.isDirectionRTLByLanguage(context)
? controller.imagePaths.icBack
: controller.imagePaths.icCollapseFolder,
colorFilter: AppColor.colorCollapseMailbox.asFilter(),
fit: BoxFit.fill),
onPressed: () => controller.selectMailboxLocation(context))
])),
)
)
]);
}
DefaultCloseButtonWidget(
iconClose: controller.imagePaths.icCloseDialog,
onTapActionCallback: controller.closeView,
),
],
),
);
double _getWidthView(BuildContext context) {
if (PlatformInfo.isWeb) {
if (controller.responsiveUtils.isMobile(context)) {
return double.infinity;
} else {
return 556;
}
} else {
if (controller.responsiveUtils.isLandscapeMobile(context) ||
controller.responsiveUtils.isPortraitMobile(context)) {
return double.infinity;
} else {
return 556;
}
}
return Center(child: bodyWidget);
}
double _getHeightView(BuildContext context) {
if (PlatformInfo.isWeb) {
if (controller.responsiveUtils.isMobile(context)) {
return double.infinity;
} else {
if (controller.responsiveUtils.getSizeScreenHeight(context) > _maxHeight) {
return _maxHeight;
} else {
return double.infinity;
}
}
} else {
if (controller.responsiveUtils.isLandscapeMobile(context) ||
controller.responsiveUtils.isPortraitMobile(context)) {
return double.infinity;
} else {
if (controller.responsiveUtils.getSizeScreenHeight(context) > _maxHeight) {
return _maxHeight;
} else {
return double.infinity;
}
}
}
}
EdgeInsets _getMarginView(BuildContext context) {
if (PlatformInfo.isWeb) {
if (controller.responsiveUtils.isMobile(context)) {
return EdgeInsets.zero;
} else {
if (controller.responsiveUtils.getSizeScreenHeight(context) > _maxHeight) {
return const EdgeInsets.symmetric(vertical: 12);
} else {
return const EdgeInsets.symmetric(vertical: 50);
}
}
} else {
if (controller.responsiveUtils.isLandscapeMobile(context) ||
controller.responsiveUtils.isPortraitMobile(context)) {
return EdgeInsets.zero;
} else {
if (controller.responsiveUtils.getSizeScreenHeight(context) > _maxHeight) {
return const EdgeInsets.symmetric(vertical: 12);
} else {
return const EdgeInsets.symmetric(vertical: 50);
}
}
}
}
BorderRadius _getRadiusView(BuildContext context) {
if (PlatformInfo.isMobile && controller.responsiveUtils.isLandscapeMobile(context)) {
return BorderRadius.zero;
} else if (controller.responsiveUtils.isMobile(context)) {
return const BorderRadius.only(
topRight: Radius.circular(16),
topLeft: Radius.circular(16));
} else {
return const BorderRadius.all(Radius.circular(16));
}
}
}
}
@@ -1,34 +1,23 @@
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
class MailboxCreatorArguments with EquatableMixin{
final AccountId accountId;
final MailboxTree personalMailboxTree;
final MailboxTree defaultMailboxTree;
final MailboxTree teamMailboxesTree;
final Session session;
final PresentationMailbox? selectedMailbox;
MailboxCreatorArguments(
this.accountId,
this.defaultMailboxTree,
this.defaultMailboxTree,
this.personalMailboxTree,
this.teamMailboxesTree,
this.session,
this.selectedMailbox
this.selectedMailbox,
);
@override
List<Object?> get props => [
accountId,
defaultMailboxTree,
defaultMailboxTree,
personalMailboxTree,
teamMailboxesTree,
session,
selectedMailbox
selectedMailbox,
];
}
@@ -1,92 +0,0 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnCancelActionClick = void Function();
typedef OnDoneActionClick = void Function();
class AppBarMailboxCreatorBuilder {
OnCancelActionClick? _cancelActionClick;
OnDoneActionClick? _onDoneActionClick;
final BuildContext _context;
final bool isValidated;
final String? title;
AppBarMailboxCreatorBuilder(
this._context,
{
this.title,
this.isValidated = false
}
);
void addOnCancelActionClick(OnCancelActionClick onCancelActionClick) {
_cancelActionClick = onCancelActionClick;
}
void addOnDoneActionClick(OnDoneActionClick onDoneActionClick) {
_onDoneActionClick = onDoneActionClick;
}
Widget build() {
return Container(
color: Colors.white,
height: 52,
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(children: [
_buildCancelButton(),
Expanded(child: _buildTitle()),
_buildCreateButton()
])
);
}
Widget _buildCancelButton() {
return Material(
borderRadius: BorderRadius.circular(20),
color: Colors.transparent,
child: TextButton(
child: Text(
AppLocalizations.of(_context).cancel,
style: ThemeUtils.defaultTextStyleInterFont.copyWith(fontSize: 17, color: AppColor.colorTextButton),
),
onPressed: () => _cancelActionClick?.call()
)
);
}
Widget _buildCreateButton() {
return Material(
borderRadius: BorderRadius.circular(20),
color: Colors.transparent,
child: TextButton(
child: Text(
AppLocalizations.of(_context).done,
style: ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 17,
color: isValidated
? AppColor.colorTextButton
: AppColor.colorDisableMailboxCreateButton),
),
onPressed: () => isValidated ? _onDoneActionClick?.call() : null
)
);
}
Widget _buildTitle() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(
title ?? '',
textAlign: TextAlign.center,
maxLines: 1,
softWrap: CommonTextStyle.defaultSoftWrap,
overflow: CommonTextStyle.defaultTextOverFlow,
style: ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 20,
color: AppColor.colorNameEmail,
fontWeight: FontWeight.bold)));
}
}
@@ -0,0 +1,114 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/list/tree_view.dart';
import 'package:flutter/material.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/utils/mailbox_method_action_define.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/main/localizations/app_localizations.dart';
class ModalFolderTreeListWidget extends StatelessWidget {
final MailboxTree defaultTree;
final MailboxTree personalTree;
final ScrollController listScrollController;
final ImagePaths imagePaths;
final OnClickOpenMailboxNodeAction onSelectFolderAction;
final OnClickExpandMailboxNodeAction onToggleFolderAction;
final MailboxId? mailboxIdSelected;
const ModalFolderTreeListWidget({
super.key,
required this.defaultTree,
required this.personalTree,
required this.listScrollController,
required this.imagePaths,
required this.onSelectFolderAction,
required this.onToggleFolderAction,
this.mailboxIdSelected,
});
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: const ClampingScrollPhysics(),
controller: listScrollController,
padding: const EdgeInsetsDirectional.only(end: 14),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
FolderItemWidget(
folderName: AppLocalizations.of(context).personalFolders,
imagePaths: imagePaths,
isSelected: mailboxIdSelected == null,
onTapAction: () => onSelectFolderAction(null),
),
if (defaultTree.root.hasChildren())
_buildFolderTree(
mailboxTree: defaultTree,
mailboxIdSelected: mailboxIdSelected,
),
if (personalTree.root.hasChildren())
_buildFolderTree(
mailboxTree: personalTree,
mailboxIdSelected: mailboxIdSelected,
),
],
),
);
}
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,
onOpenMailboxFolderClick: onSelectFolderAction,
onExpandFolderActionClick: onToggleFolderAction,
),
children: _buildListChildTileWidget(
parentNode: mailboxNode,
mailboxIdSelected: mailboxIdSelected,
),
).build();
} else {
return MailboxItemWidget(
mailboxNode: mailboxNode,
mailboxDisplayed: MailboxDisplayed.modalFolder,
mailboxIdAlreadySelected: mailboxIdSelected,
hoverColor: AppColor.blue100,
onOpenMailboxFolderClick: onSelectFolderAction,
onExpandFolderActionClick: onToggleFolderAction,
);
}
},
).toList() ?? [];
}
}
@@ -272,7 +272,6 @@ class MailboxVisibilityView extends GetWidget<MailboxVisibilityController>
return parentNode.childrenItems
?.map((mailboxNode) => mailboxNode.hasChildren()
? TreeViewChild(
context,
key: const Key('children_tree_mailbox_child'),
isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND,
paddingChild: const EdgeInsetsDirectional.only(start: 10),
@@ -756,12 +756,9 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
void goToCreateNewMailboxView(BuildContext context, {PresentationMailbox? parentMailbox}) async {
if (session != null && accountId != null) {
final arguments = MailboxCreatorArguments(
accountId!,
defaultMailboxTree.value,
personalMailboxTree.value,
teamMailboxesTree.value,
session!,
parentMailbox
parentMailbox,
);
final result = PlatformInfo.isWeb
+40
View File
@@ -4789,5 +4789,45 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"createANewFolder": "Create a New Folder",
"@createANewFolder": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"subtitleDisplayTheFolderNameLocationInFolderCreationModal": "New folder will be created inside {folderName}",
"@subtitleDisplayTheFolderNameLocationInFolderCreationModal": {
"type": "text",
"placeholders_order": [
"folderName"
],
"placeholders": {
"folderName": {}
}
},
"folderName": "Folder Name",
"@folderName": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"enterTheFolderName": "Enter the folder name",
"@enterTheFolderName": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"selectTheFolderLocation": "Select the folder location",
"@selectTheFolderLocation": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"createFolder": "Create folder",
"@createFolder": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
@@ -5059,4 +5059,47 @@ class AppLocalizations {
name: 'actions',
);
}
String get createANewFolder {
return Intl.message(
'Create a New Folder',
name: 'createANewFolder',
);
}
String subtitleDisplayTheFolderNameLocationInFolderCreationModal(String folderName) {
return Intl.message(
'New folder will be created inside $folderName',
name: 'subtitleDisplayTheFolderNameLocationInFolderCreationModal',
args: [folderName]
);
}
String get folderName {
return Intl.message(
'Folder Name',
name: 'folderName',
);
}
String get enterTheFolderName {
return Intl.message(
'Enter the folder name',
name: 'enterTheFolderName',
);
}
String get selectTheFolderLocation {
return Intl.message(
'Select the folder location',
name: 'selectTheFolderLocation',
);
}
String get createFolder {
return Intl.message(
'Create folder',
name: 'createFolder',
);
}
}