TF-3479 Handle Show all & Hide all popup menu composer

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-02-14 10:10:30 +07:00
committed by Dat H. Pham
parent 1bad81dbf2
commit 16cb8c8a37
12 changed files with 341 additions and 125 deletions
@@ -1,58 +0,0 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/features/composer/presentation/utils/composer_utils.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ExpandComposerButton extends StatelessWidget {
final ImagePaths imagePaths;
final int countComposerHidden;
final VoidCallback onToggleDisplayComposerAction;
const ExpandComposerButton({
super.key,
required this.imagePaths,
required this.countComposerHidden,
required this.onToggleDisplayComposerAction,
});
@override
Widget build(BuildContext context) {
return Card(
elevation: 16,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))
),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () => {},
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Container(
color: Colors.white,
width: ComposerUtils.composerExpandMoreButtonMaxWidth,
height: ComposerUtils.minimizeHeight,
padding: const EdgeInsetsDirectional.symmetric(horizontal: 8),
child: Row(
children: [
SvgPicture.asset(imagePaths.icDoubleArrowUp),
const SizedBox(width: 8),
Expanded(
child: Text(
'+$countComposerHidden ${AppLocalizations.of(context).more.toLowerCase()}',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
]
)
),
),
);
}
}
@@ -0,0 +1,122 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.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/composer/presentation/manager/composer_manager.dart';
import 'package:tmail_ui_user/features/composer/presentation/utils/composer_utils.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/hidden_composer_list_view_overlay.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ExpandComposerButton extends StatefulWidget {
final int countComposerHidden;
final OnRemoveHiddenComposerItem onRemoveHiddenComposerItem;
final OnShowComposerAction onShowComposerAction;
const ExpandComposerButton({
super.key,
required this.countComposerHidden,
required this.onRemoveHiddenComposerItem,
required this.onShowComposerAction,
});
@override
State<ExpandComposerButton> createState() => _ExpandComposerButtonState();
}
class _ExpandComposerButtonState extends State<ExpandComposerButton> {
late final ComposerManager _composerManager;
late final ImagePaths _imagePaths;
late final ResponsiveUtils _responsiveUtils;
bool _visible = false;
@override
void initState() {
super.initState();
_composerManager = Get.find<ComposerManager>();
_imagePaths = Get.find<ImagePaths>();
_responsiveUtils = Get.find<ResponsiveUtils>();
}
@override
Widget build(BuildContext context) {
final expandButton = PointerInterceptor(
child: Card(
elevation: 16,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))
),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () => setState(() => _visible = !_visible),
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Container(
color: Colors.white,
width: ComposerUtils.composerExpandMoreButtonMaxWidth,
height: ComposerUtils.composerExpandMoreButtonMaxHeight,
padding: const EdgeInsetsDirectional.symmetric(horizontal: 8),
child: Row(
children: [
SvgPicture.asset(
_visible
? _imagePaths.icDoubleArrowDown
: _imagePaths.icDoubleArrowUp,
),
const SizedBox(width: 8),
Expanded(
child: Text(
_visible
? AppLocalizations.of(context).hideAll
: '+${widget.countComposerHidden} ${AppLocalizations.of(context).more.toLowerCase()}',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
]
)
),
),
),
);
return PortalTarget(
visible: _visible,
portalFollower: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _visible = false),
),
child: PortalTarget(
anchor: const Aligned(
follower: Alignment.bottomLeft,
target: Alignment.topLeft,
offset: Offset(0.0, 0.0),
),
portalFollower: HiddenComposerListViewOverlay(
composerManager: _composerManager,
imagePaths: _imagePaths,
responsiveUtils: _responsiveUtils,
onRemoveHiddenComposerItem: (controller) {
widget.onRemoveHiddenComposerItem(controller);
setState(() => _visible = false);
},
onShowComposerAction: (composerId) {
widget.onShowComposerAction(composerId);
setState(() => _visible = false);
}
),
visible: _visible,
child: expandButton,
)
);
}
}
@@ -0,0 +1,60 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:flutter/material.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/web/hidden_composer_item_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/title_composer_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class HiddenComposerItem extends StatelessWidget {
final ImagePaths imagePaths;
final String composerSubject;
final VoidCallback onCloseViewAction;
final VoidCallback onShowComposer;
const HiddenComposerItem({
super.key,
required this.imagePaths,
required this.composerSubject,
required this.onCloseViewAction,
required this.onShowComposer,
});
@override
Widget build(BuildContext context) {
return PointerInterceptor(
child: Card(
elevation: HiddenComposerItemStyle.elevation,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(HiddenComposerItemStyle.radius))
),
clipBehavior: Clip.antiAlias,
child: Container(
color: HiddenComposerItemStyle.backgroundColor,
width: HiddenComposerItemStyle.width,
height: HiddenComposerItemStyle.height,
padding: HiddenComposerItemStyle.padding,
child: InkWell(
onTap: onShowComposer,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
TMailButtonWidget.fromIcon(
icon: imagePaths.icCancel,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).saveAndClose,
iconSize: HiddenComposerItemStyle.iconSize,
iconColor: HiddenComposerItemStyle.iconColor,
onTapActionCallback: onCloseViewAction
),
const SizedBox(width: HiddenComposerItemStyle.space),
Expanded(child: TitleComposerWidget(emailSubject: composerSubject)),
]
),
)
),
),
);
}
}
@@ -0,0 +1,58 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/web/hidden_composer_item_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/utils/composer_utils.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/hidden_composer_item.dart';
typedef OnRemoveHiddenComposerItem = Function(ComposerController controller);
typedef OnShowComposerAction = Function(String composerId);
class HiddenComposerListViewOverlay extends StatelessWidget {
final ComposerManager composerManager;
final ImagePaths imagePaths;
final ResponsiveUtils responsiveUtils;
final OnRemoveHiddenComposerItem onRemoveHiddenComposerItem;
final OnShowComposerAction onShowComposerAction;
const HiddenComposerListViewOverlay({
super.key,
required this.composerManager,
required this.imagePaths,
required this.responsiveUtils,
required this.onRemoveHiddenComposerItem,
required this.onShowComposerAction,
});
@override
Widget build(BuildContext context) {
final hiddenComposerIds = composerManager.hiddenComposerIds;
final maxHeight = responsiveUtils.getSizeScreenHeight(context)
- ComposerUtils.composerExpandMoreButtonMaxHeight
- ComposerUtils.padding;
return Container(
constraints: BoxConstraints(maxHeight: maxHeight),
width: HiddenComposerItemStyle.width,
child: ListView.builder(
itemCount: hiddenComposerIds.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final composerId = hiddenComposerIds[index];
final controller = composerManager.getComposerView(composerId).controller;
final subjectEmail = controller.subjectEmail.value ?? '';
return HiddenComposerItem(
imagePaths: imagePaths,
composerSubject: subjectEmail,
onCloseViewAction: () => onRemoveHiddenComposerItem(controller),
onShowComposer: () => onShowComposerAction(composerId),
);
}),
);
}
}
@@ -37,52 +37,40 @@ class MinimizeComposerWidget extends StatelessWidget {
width: MinimizeComposerWidgetStyle.width,
height: MinimizeComposerWidgetStyle.height,
padding: MinimizeComposerWidgetStyle.padding,
child: Stack(
child: Row(
children: [
Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: MinimizeComposerWidgetStyle.width / 2),
child: TitleComposerWidget(emailSubject: emailSubject),
),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icCancel,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).saveAndClose,
iconSize: MinimizeComposerWidgetStyle.iconSize,
iconColor: MinimizeComposerWidgetStyle.iconColor,
padding: MinimizeComposerWidgetStyle.iconPadding,
onTapActionCallback: onCloseViewAction
),
Align(
alignment: AlignmentDirectional.centerStart,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
TMailButtonWidget.fromIcon(
icon: _imagePaths.icCancel,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).saveAndClose,
iconSize: MinimizeComposerWidgetStyle.iconSize,
iconColor: MinimizeComposerWidgetStyle.iconColor,
padding: MinimizeComposerWidgetStyle.iconPadding,
onTapActionCallback: onCloseViewAction
),
const SizedBox(width: MinimizeComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icFullScreen,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).fullscreen,
iconSize: MinimizeComposerWidgetStyle.iconSize,
iconColor: MinimizeComposerWidgetStyle.iconColor,
padding: MinimizeComposerWidgetStyle.iconPadding,
onTapActionCallback: () => onChangeDisplayModeAction(ScreenDisplayMode.fullScreen)
),
const SizedBox(width: MinimizeComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icChevronUp,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).show,
iconSize: MinimizeComposerWidgetStyle.iconSize,
iconColor: MinimizeComposerWidgetStyle.iconColor,
padding: MinimizeComposerWidgetStyle.iconPadding,
onTapActionCallback: () => onChangeDisplayModeAction(ScreenDisplayMode.normal)
),
]
),
)
],
const SizedBox(width: MinimizeComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icFullScreen,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).fullscreen,
iconSize: MinimizeComposerWidgetStyle.iconSize,
iconColor: MinimizeComposerWidgetStyle.iconColor,
padding: MinimizeComposerWidgetStyle.iconPadding,
onTapActionCallback: () => onChangeDisplayModeAction(ScreenDisplayMode.fullScreen)
),
const SizedBox(width: MinimizeComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icChevronUp,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).show,
iconSize: MinimizeComposerWidgetStyle.iconSize,
iconColor: MinimizeComposerWidgetStyle.iconColor,
padding: MinimizeComposerWidgetStyle.iconPadding,
onTapActionCallback: () => onChangeDisplayModeAction(ScreenDisplayMode.normal)
),
const SizedBox(width: MinimizeComposerWidgetStyle.space),
Expanded(child: TitleComposerWidget(emailSubject: emailSubject)),
]
)
),
);