TF-4002 Apply new design for folder creation modal on web
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
}
|
||||
-92
@@ -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() ?? [];
|
||||
}
|
||||
}
|
||||
-1
@@ -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
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user