TF-2116 Apply new design composer mobile
(cherry picked from commit fe4ec144d1a18a94de782f87fff56bbf1cd3a00a)
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/web/attachment_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_item_composer_widget.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_header_composer_widget.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||
|
||||
typedef OnToggleExpandAttachmentAction = void Function(bool isCollapsed);
|
||||
|
||||
class AttachmentComposerWidget extends StatefulWidget {
|
||||
|
||||
final List<UploadFileState> listFileUploaded;
|
||||
final bool isCollapsed;
|
||||
final OnDeleteAttachmentAction onDeleteAttachmentAction;
|
||||
final OnToggleExpandAttachmentAction onToggleExpandAttachmentAction;
|
||||
|
||||
const AttachmentComposerWidget({
|
||||
super.key,
|
||||
required this.listFileUploaded,
|
||||
required this.isCollapsed,
|
||||
required this.onDeleteAttachmentAction,
|
||||
required this.onToggleExpandAttachmentAction,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AttachmentComposerWidget> createState() => _AttachmentComposerWidgetState();
|
||||
}
|
||||
|
||||
class _AttachmentComposerWidgetState extends State<AttachmentComposerWidget> {
|
||||
|
||||
bool _isCollapsed = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_isCollapsed = widget.isCollapsed;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: AttachmentComposerWidgetStyle.backgroundColor,
|
||||
boxShadow: AttachmentComposerWidgetStyle.shadow
|
||||
),
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
AttachmentHeaderComposerWidget(
|
||||
listFileUploaded: widget.listFileUploaded,
|
||||
isCollapsed: _isCollapsed,
|
||||
onToggleExpandAction: (isCollapsed) {
|
||||
setState(() => _isCollapsed = !isCollapsed);
|
||||
widget.onToggleExpandAttachmentAction(!isCollapsed);
|
||||
},
|
||||
),
|
||||
if (!_isCollapsed)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: AttachmentComposerWidgetStyle.listItemPadding,
|
||||
constraints: const BoxConstraints(maxHeight: AttachmentComposerWidgetStyle.maxHeight),
|
||||
child: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
spacing: AttachmentComposerWidgetStyle.listItemSpace,
|
||||
runSpacing: AttachmentComposerWidgetStyle.listItemSpace,
|
||||
children: widget.listFileUploaded
|
||||
.map((file) => AttachmentItemComposerWidget(
|
||||
fileState: file,
|
||||
onDeleteAttachmentAction: widget.onDeleteAttachmentAction
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
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:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/web/bottom_bar_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class BottomBarComposerWidget extends StatelessWidget {
|
||||
|
||||
final bool isCodeViewEnabled;
|
||||
final bool isFormattingOptionsEnabled;
|
||||
final VoidCallback openRichToolbarAction;
|
||||
final VoidCallback attachFileAction;
|
||||
final VoidCallback insertImageAction;
|
||||
final VoidCallback showCodeViewAction;
|
||||
final VoidCallback deleteComposerAction;
|
||||
final VoidCallback saveToDraftAction;
|
||||
final VoidCallback sendMessageAction;
|
||||
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
BottomBarComposerWidget({
|
||||
super.key,
|
||||
required this.isCodeViewEnabled,
|
||||
required this.isFormattingOptionsEnabled,
|
||||
required this.openRichToolbarAction,
|
||||
required this.attachFileAction,
|
||||
required this.insertImageAction,
|
||||
required this.showCodeViewAction,
|
||||
required this.deleteComposerAction,
|
||||
required this.saveToDraftAction,
|
||||
required this.sendMessageAction,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: BottomBarComposerWidgetStyle.padding,
|
||||
color: BottomBarComposerWidgetStyle.backgroundColor,
|
||||
child: Row(
|
||||
children: [
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icRichToolbar,
|
||||
borderRadius: BottomBarComposerWidgetStyle.iconRadius,
|
||||
padding: BottomBarComposerWidgetStyle.richTextIconPadding,
|
||||
backgroundColor: isFormattingOptionsEnabled
|
||||
? BottomBarComposerWidgetStyle.selectedBackgroundColor
|
||||
: Colors.transparent,
|
||||
iconSize: BottomBarComposerWidgetStyle.richTextIconSize,
|
||||
iconColor: isFormattingOptionsEnabled
|
||||
? BottomBarComposerWidgetStyle.selectedIconColor
|
||||
: BottomBarComposerWidgetStyle.iconColor,
|
||||
tooltipMessage: AppLocalizations.of(context).formattingOptions,
|
||||
onTapActionCallback: openRichToolbarAction,
|
||||
),
|
||||
const SizedBox(width: BottomBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icAttachFile,
|
||||
iconColor: BottomBarComposerWidgetStyle.iconColor,
|
||||
borderRadius: BottomBarComposerWidgetStyle.iconRadius,
|
||||
backgroundColor: Colors.transparent,
|
||||
padding: BottomBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: BottomBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).attach_file,
|
||||
onTapActionCallback: attachFileAction,
|
||||
),
|
||||
const SizedBox(width: BottomBarComposerWidgetStyle.space),
|
||||
AbsorbPointer(
|
||||
absorbing: isCodeViewEnabled,
|
||||
child: TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icInsertImage,
|
||||
iconColor: BottomBarComposerWidgetStyle.iconColor,
|
||||
borderRadius: BottomBarComposerWidgetStyle.iconRadius,
|
||||
backgroundColor: Colors.transparent,
|
||||
padding: BottomBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: BottomBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).insertImage,
|
||||
onTapActionCallback: insertImageAction,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: BottomBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icStyleCodeView,
|
||||
iconColor: isCodeViewEnabled
|
||||
? BottomBarComposerWidgetStyle.selectedIconColor
|
||||
: BottomBarComposerWidgetStyle.iconColor,
|
||||
borderRadius: BottomBarComposerWidgetStyle.iconRadius,
|
||||
backgroundColor: isCodeViewEnabled
|
||||
? BottomBarComposerWidgetStyle.selectedBackgroundColor
|
||||
: Colors.transparent,
|
||||
padding: BottomBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: BottomBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).embedCode,
|
||||
onTapActionCallback: showCodeViewAction,
|
||||
),
|
||||
const Spacer(),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icDeleteMailbox,
|
||||
borderRadius: BottomBarComposerWidgetStyle.iconRadius,
|
||||
padding: BottomBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: BottomBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).delete,
|
||||
onTapActionCallback: deleteComposerAction,
|
||||
),
|
||||
const SizedBox(width: BottomBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icSaveToDraft,
|
||||
borderRadius: BottomBarComposerWidgetStyle.iconRadius,
|
||||
padding: BottomBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: BottomBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).save_to_drafts,
|
||||
onTapActionCallback: saveToDraftAction,
|
||||
),
|
||||
const SizedBox(width: BottomBarComposerWidgetStyle.sendButtonSpace),
|
||||
TMailButtonWidget(
|
||||
text: AppLocalizations.of(context).send,
|
||||
icon: _imagePaths.icSend,
|
||||
iconAlignment: TextDirection.rtl,
|
||||
padding: BottomBarComposerWidgetStyle.sendButtonPadding,
|
||||
iconSize: BottomBarComposerWidgetStyle.iconSize,
|
||||
iconSpace: BottomBarComposerWidgetStyle.sendButtonIconSpace,
|
||||
textStyle: BottomBarComposerWidgetStyle.sendButtonTextStyle,
|
||||
backgroundColor: BottomBarComposerWidgetStyle.sendButtonBackgroundColor,
|
||||
borderRadius: BottomBarComposerWidgetStyle.sendButtonRadius,
|
||||
onTapActionCallback: sendMessageAction,
|
||||
)
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
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:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/app_bar_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/minimize_composer_widget.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 DesktopAppBarComposerWidget extends StatelessWidget {
|
||||
|
||||
final String emailSubject;
|
||||
final VoidCallback onCloseViewAction;
|
||||
final ScreenDisplayMode? displayMode;
|
||||
final OnChangeDisplayModeAction? onChangeDisplayModeAction;
|
||||
final BoxConstraints? constraints;
|
||||
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
DesktopAppBarComposerWidget({
|
||||
super.key,
|
||||
required this.emailSubject,
|
||||
required this.onCloseViewAction,
|
||||
this.displayMode,
|
||||
this.onChangeDisplayModeAction,
|
||||
this.constraints,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: AppBarComposerWidgetStyle.height,
|
||||
padding: AppBarComposerWidgetStyle.padding,
|
||||
color: AppBarComposerWidgetStyle.backgroundColor,
|
||||
child: Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: Container(
|
||||
constraints: constraints != null
|
||||
? BoxConstraints(maxWidth: constraints!.maxWidth / 2)
|
||||
: null,
|
||||
child: TitleComposerWidget(emailSubject: emailSubject),
|
||||
),
|
||||
),
|
||||
if (onChangeDisplayModeAction != null)
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icMinimize,
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).minimize,
|
||||
iconSize: AppBarComposerWidgetStyle.iconSize,
|
||||
iconColor: AppBarComposerWidgetStyle.iconColor,
|
||||
padding: AppBarComposerWidgetStyle.iconPadding,
|
||||
onTapActionCallback: () => onChangeDisplayModeAction!(ScreenDisplayMode.minimize)
|
||||
),
|
||||
const SizedBox(width: AppBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: displayMode == ScreenDisplayMode.fullScreen
|
||||
? _imagePaths.icFullScreenExit
|
||||
: _imagePaths.icFullScreen,
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).fullscreen,
|
||||
iconSize: AppBarComposerWidgetStyle.iconSize,
|
||||
iconColor: AppBarComposerWidgetStyle.iconColor,
|
||||
padding: AppBarComposerWidgetStyle.iconPadding,
|
||||
onTapActionCallback: () => onChangeDisplayModeAction!(
|
||||
displayMode == ScreenDisplayMode.fullScreen
|
||||
? ScreenDisplayMode.normal
|
||||
: ScreenDisplayMode.fullScreen
|
||||
)
|
||||
),
|
||||
const SizedBox(width: AppBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icCancel,
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).saveAndClose,
|
||||
iconSize: AppBarComposerWidgetStyle.iconSize,
|
||||
iconColor: AppBarComposerWidgetStyle.iconColor,
|
||||
padding: AppBarComposerWidgetStyle.iconPadding,
|
||||
onTapActionCallback: onCloseViewAction
|
||||
),
|
||||
]
|
||||
),
|
||||
)
|
||||
else
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icCancel,
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).saveAndClose,
|
||||
iconSize: AppBarComposerWidgetStyle.iconSize,
|
||||
iconColor: AppBarComposerWidgetStyle.iconColor,
|
||||
padding: AppBarComposerWidgetStyle.iconPadding,
|
||||
onTapActionCallback: onCloseViewAction
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
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:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/minimize_composer_widget_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';
|
||||
|
||||
typedef OnChangeDisplayModeAction = Function(ScreenDisplayMode mode);
|
||||
|
||||
class MinimizeComposerWidget extends StatelessWidget {
|
||||
|
||||
final OnChangeDisplayModeAction onChangeDisplayModeAction;
|
||||
final VoidCallback onCloseViewAction;
|
||||
final String emailSubject;
|
||||
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
MinimizeComposerWidget({
|
||||
super.key,
|
||||
required this.emailSubject,
|
||||
required this.onChangeDisplayModeAction,
|
||||
required this.onCloseViewAction,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
elevation: MinimizeComposerWidgetStyle.elevation,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(MinimizeComposerWidgetStyle.radius))
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Container(
|
||||
color: MinimizeComposerWidgetStyle.backgroundColor,
|
||||
width: MinimizeComposerWidgetStyle.width,
|
||||
height: MinimizeComposerWidgetStyle.height,
|
||||
padding: MinimizeComposerWidgetStyle.padding,
|
||||
child: Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: MinimizeComposerWidgetStyle.width / 2),
|
||||
child: TitleComposerWidget(emailSubject: emailSubject),
|
||||
),
|
||||
),
|
||||
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)
|
||||
),
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
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:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile_app_bar_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
|
||||
|
||||
final bool isCodeViewEnabled;
|
||||
final bool isSendButtonEnabled;
|
||||
final bool isFormattingOptionsEnabled;
|
||||
final VoidCallback onCloseViewAction;
|
||||
final VoidCallback attachFileAction;
|
||||
final VoidCallback insertImageAction;
|
||||
final VoidCallback sendMessageAction;
|
||||
final VoidCallback openContextMenuAction;
|
||||
final VoidCallback openRichToolbarAction;
|
||||
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
MobileResponsiveAppBarComposerWidget({
|
||||
super.key,
|
||||
required this.isCodeViewEnabled,
|
||||
required this.isFormattingOptionsEnabled,
|
||||
required this.isSendButtonEnabled,
|
||||
required this.openRichToolbarAction,
|
||||
required this.onCloseViewAction,
|
||||
required this.attachFileAction,
|
||||
required this.insertImageAction,
|
||||
required this.sendMessageAction,
|
||||
required this.openContextMenuAction,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: MobileAppBarComposerWidgetStyle.height,
|
||||
color: MobileAppBarComposerWidgetStyle.backgroundColor,
|
||||
padding: MobileAppBarComposerWidgetStyle.padding,
|
||||
child: Row(
|
||||
children: [
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icCancel,
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).saveAndClose,
|
||||
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
|
||||
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
|
||||
padding: MobileAppBarComposerWidgetStyle.iconPadding,
|
||||
onTapActionCallback: onCloseViewAction
|
||||
),
|
||||
const Spacer(),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icRichToolbar,
|
||||
borderRadius: MobileAppBarComposerWidgetStyle.iconRadius,
|
||||
padding: MobileAppBarComposerWidgetStyle.richTextIconPadding,
|
||||
backgroundColor: isFormattingOptionsEnabled
|
||||
? MobileAppBarComposerWidgetStyle.selectedBackgroundColor
|
||||
: Colors.transparent,
|
||||
iconSize: MobileAppBarComposerWidgetStyle.richTextIconSize,
|
||||
iconColor: isFormattingOptionsEnabled
|
||||
? MobileAppBarComposerWidgetStyle.selectedIconColor
|
||||
: MobileAppBarComposerWidgetStyle.iconColor,
|
||||
tooltipMessage: AppLocalizations.of(context).formattingOptions,
|
||||
onTapActionCallback: openRichToolbarAction,
|
||||
),
|
||||
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icAttachFile,
|
||||
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
|
||||
borderRadius: MobileAppBarComposerWidgetStyle.iconRadius,
|
||||
backgroundColor: Colors.transparent,
|
||||
padding: MobileAppBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).attach_file,
|
||||
onTapActionCallback: attachFileAction,
|
||||
),
|
||||
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
|
||||
AbsorbPointer(
|
||||
absorbing: isCodeViewEnabled,
|
||||
child: TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icInsertImage,
|
||||
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
|
||||
borderRadius: MobileAppBarComposerWidgetStyle.iconRadius,
|
||||
backgroundColor: Colors.transparent,
|
||||
padding: MobileAppBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).insertImage,
|
||||
onTapActionCallback: insertImageAction,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: isSendButtonEnabled
|
||||
? _imagePaths.icSendMobile
|
||||
: _imagePaths.icSendDisable,
|
||||
backgroundColor: Colors.transparent,
|
||||
padding: MobileAppBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: MobileAppBarComposerWidgetStyle.sendButtonIconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).send,
|
||||
onTapActionCallback: sendMessageAction,
|
||||
),
|
||||
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icMore,
|
||||
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
|
||||
borderRadius: MobileAppBarComposerWidgetStyle.iconRadius,
|
||||
backgroundColor: Colors.transparent,
|
||||
padding: MobileAppBarComposerWidgetStyle.iconPadding,
|
||||
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
|
||||
tooltipMessage: AppLocalizations.of(context).more,
|
||||
onTapActionCallback: openContextMenuAction,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/utils/app_logger.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/drop_down_button_widget.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/mixin/rich_text_button_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/dropdown_menu_font_status.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/header_style_type.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/order_list_type.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/paragraph_type.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/drop_down_menu_header_style_widget.dart';
|
||||
|
||||
class ToolbarRichTextWebBuilder extends StatelessWidget with RichTextButtonMixin {
|
||||
|
||||
final RichTextWebController richTextWebController;
|
||||
final ImagePaths _imagePaths = Get.find<ImagePaths>();
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final List<Widget>? extendedOption;
|
||||
final AlignmentGeometry? alignment;
|
||||
final Decoration? decoration;
|
||||
|
||||
ToolbarRichTextWebBuilder({
|
||||
Key? key,
|
||||
required this.richTextWebController,
|
||||
this.padding,
|
||||
this.extendedOption,
|
||||
this.alignment,
|
||||
this.decoration,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
final codeViewEnabled = richTextWebController.codeViewEnabled;
|
||||
final opacity = codeViewEnabled ? 0.5 : 1.0;
|
||||
|
||||
return PointerInterceptor(
|
||||
child: Container(
|
||||
padding: padding ?? const EdgeInsetsDirectional.only(start: 20, top: 8, bottom: 8),
|
||||
decoration: decoration,
|
||||
width: double.infinity,
|
||||
child: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
if (extendedOption?.isNotEmpty == true)
|
||||
...extendedOption!,
|
||||
AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: DropDownMenuHeaderStyleWidget(
|
||||
icon: buildWrapIconStyleText(
|
||||
isSelected: richTextWebController.isMenuHeaderStyleOpen,
|
||||
icon: SvgPicture.asset(
|
||||
RichTextStyleType.headerStyle.getIcon(_imagePaths),
|
||||
colorFilter: AppColor.colorDefaultRichTextButton.withOpacity(opacity).asFilter(),
|
||||
fit: BoxFit.fill),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||||
tooltip: RichTextStyleType.headerStyle.getTooltipButton(context)
|
||||
),
|
||||
items: HeaderStyleType.values,
|
||||
onMenuStateChange: (isOpen) {
|
||||
log('ComposerView::_buildToolbarRichTextWidget(): MenuHeaderStyleStatus: $isOpen');
|
||||
final newStatus = isOpen
|
||||
? DropdownMenuFontStatus.open
|
||||
: DropdownMenuFontStatus.closed;
|
||||
richTextWebController.menuHeaderStyleStatus.value = newStatus;
|
||||
},
|
||||
onChanged: (newStyle) => richTextWebController.applyHeaderStyle(newStyle)),
|
||||
),
|
||||
AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: Container(
|
||||
width: 130,
|
||||
padding: const EdgeInsets.only(left: 4.0, right: 4.0),
|
||||
child: DropDownButtonWidget<FontNameType>(
|
||||
items: FontNameType.values,
|
||||
itemSelected: richTextWebController.selectedFontName.value,
|
||||
onChanged: (newFont) => richTextWebController.applyNewFontStyle(newFont),
|
||||
onMenuStateChange: (isOpen) {
|
||||
log('ComposerView::_buildToolbarRichTextWidget(): MenuFontStatus: $isOpen');
|
||||
final newStatus = isOpen
|
||||
? DropdownMenuFontStatus.open
|
||||
: DropdownMenuFontStatus.closed;
|
||||
richTextWebController.menuFontStatus.value = newStatus;
|
||||
},
|
||||
heightItem: 40,
|
||||
sizeIconChecked: 16,
|
||||
radiusButton: 8,
|
||||
opacity: opacity,
|
||||
dropdownWidth: 200,
|
||||
colorButton: richTextWebController.isMenuFontOpen
|
||||
? AppColor.colorBackgroundWrapIconStyleCode
|
||||
: Colors.white,
|
||||
iconArrowDown: SvgPicture.asset(_imagePaths.icStyleArrowDown),
|
||||
tooltip: RichTextStyleType.fontName.getTooltipButton(context),
|
||||
supportSelectionIcon: true)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4.0),
|
||||
child: AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: buildWrapIconStyleText(
|
||||
icon: buildIconWithTooltip(
|
||||
path: RichTextStyleType.textColor.getIcon(_imagePaths),
|
||||
color: richTextWebController.selectedTextColor.value,
|
||||
tooltip: RichTextStyleType.textColor.getTooltipButton(context),
|
||||
opacity: opacity),
|
||||
onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.textColor)),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4.0),
|
||||
child: AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: buildWrapIconStyleText(
|
||||
padding: const EdgeInsets.symmetric(vertical: 9, horizontal: 7),
|
||||
spacing: 3,
|
||||
icon: buildIconColorBackgroundText(
|
||||
iconData: RichTextStyleType.textBackgroundColor.getIconData(),
|
||||
colorSelected: richTextWebController.selectedTextBackgroundColor.value,
|
||||
tooltip: RichTextStyleType.textBackgroundColor.getTooltipButton(context),
|
||||
opacity: opacity),
|
||||
onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.textBackgroundColor)),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4.0),
|
||||
child: buildWrapIconStyleText(
|
||||
hasDropdown: false,
|
||||
padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 5),
|
||||
icon: Wrap(children: [
|
||||
AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: buildIconStyleText(
|
||||
path: RichTextStyleType.bold.getIcon(_imagePaths),
|
||||
isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.bold),
|
||||
tooltip: RichTextStyleType.bold.getTooltipButton(context),
|
||||
opacity: opacity,
|
||||
onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.bold)),
|
||||
),
|
||||
AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: buildIconStyleText(
|
||||
path: RichTextStyleType.italic.getIcon(_imagePaths),
|
||||
isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.italic),
|
||||
tooltip: RichTextStyleType.italic.getTooltipButton(context),
|
||||
opacity: opacity,
|
||||
onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.italic)),
|
||||
),
|
||||
AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: buildIconStyleText(
|
||||
path: RichTextStyleType.underline.getIcon(_imagePaths),
|
||||
isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.underline),
|
||||
tooltip: RichTextStyleType.underline.getTooltipButton(context),
|
||||
opacity: opacity,
|
||||
onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.underline)),
|
||||
),
|
||||
AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: buildIconStyleText(
|
||||
path: RichTextStyleType.strikeThrough.getIcon(_imagePaths),
|
||||
isSelected: richTextWebController.isTextStyleTypeSelected(
|
||||
RichTextStyleType.strikeThrough),
|
||||
tooltip: RichTextStyleType.strikeThrough.getTooltipButton(context),
|
||||
opacity: opacity,
|
||||
onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.strikeThrough)),
|
||||
)
|
||||
])),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4.0),
|
||||
child: AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: PopupMenuOverlayWidget(
|
||||
controller: richTextWebController.menuParagraphController,
|
||||
listButtonAction: ParagraphType.values
|
||||
.map((paragraph) => paragraph.buildButtonWidget(
|
||||
context,
|
||||
_imagePaths,
|
||||
(paragraph) => richTextWebController.applyParagraphType(paragraph)))
|
||||
.toList(),
|
||||
iconButton: buildWrapIconStyleText(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||||
spacing: 3,
|
||||
isSelected: richTextWebController.focusMenuParagraph.value,
|
||||
icon: buildIconWithTooltip(
|
||||
path: richTextWebController.selectedParagraph.value.getIcon(_imagePaths),
|
||||
color: AppColor.colorDefaultRichTextButton,
|
||||
opacity: opacity,
|
||||
tooltip: RichTextStyleType.paragraph.getTooltipButton(context))),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4.0),
|
||||
child: AbsorbPointer(
|
||||
absorbing: codeViewEnabled,
|
||||
child: PopupMenuOverlayWidget(
|
||||
controller: richTextWebController.menuOrderListController,
|
||||
listButtonAction: OrderListType.values
|
||||
.map((orderType) => orderType.buildButtonWidget(
|
||||
context,
|
||||
_imagePaths,
|
||||
(orderType) => richTextWebController.applyOrderListType(orderType)))
|
||||
.toList(),
|
||||
iconButton: buildWrapIconStyleText(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||||
spacing: 3,
|
||||
isSelected: richTextWebController.focusMenuOrderList.value,
|
||||
icon: buildIconWithTooltip(
|
||||
path: richTextWebController.selectedOrderList.value.getIcon(_imagePaths),
|
||||
color: AppColor.colorDefaultRichTextButton,
|
||||
opacity: opacity,
|
||||
tooltip: RichTextStyleType.orderList.getTooltipButton(context))),
|
||||
),
|
||||
),
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
import 'package:core/presentation/utils/html_transformer/html_utils.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:html_editor_enhanced/html_editor.dart';
|
||||
|
||||
typedef OnChangeContentEditorAction = Function(String? text);
|
||||
typedef OnInitialContentEditorAction = Function(String text);
|
||||
typedef OnMouseDownEditorAction = Function(BuildContext context);
|
||||
typedef OnEditorSettingsChange = Function(EditorSettings settings);
|
||||
|
||||
class WebEditorWidget extends StatefulWidget {
|
||||
|
||||
final String content;
|
||||
final TextDirection direction;
|
||||
final HtmlEditorController editorController;
|
||||
final OnInitialContentEditorAction? onInitial;
|
||||
final OnChangeContentEditorAction? onChangeContent;
|
||||
final VoidCallback? onFocus;
|
||||
final VoidCallback? onUnFocus;
|
||||
final OnMouseDownEditorAction? onMouseDown;
|
||||
final OnEditorSettingsChange? onEditorSettings;
|
||||
|
||||
const WebEditorWidget({
|
||||
super.key,
|
||||
required this.content,
|
||||
required this.direction,
|
||||
required this.editorController,
|
||||
this.onInitial,
|
||||
this.onChangeContent,
|
||||
this.onFocus,
|
||||
this.onUnFocus,
|
||||
this.onMouseDown,
|
||||
this.onEditorSettings,
|
||||
});
|
||||
|
||||
@override
|
||||
State<WebEditorWidget> createState() => _WebEditorState();
|
||||
}
|
||||
|
||||
class _WebEditorState extends State<WebEditorWidget> {
|
||||
|
||||
late HtmlEditorController _editorController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_editorController = widget.editorController;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant WebEditorWidget oldWidget) {
|
||||
log('_EmailEditorState::didUpdateWidget():Old: ${oldWidget.direction} | current: ${widget.direction}');
|
||||
if (oldWidget.direction != widget.direction) {
|
||||
_editorController.updateBodyDirection(widget.direction.name);
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return HtmlEditor(
|
||||
key: const Key('web_editor'),
|
||||
controller: _editorController,
|
||||
htmlEditorOptions: HtmlEditorOptions(
|
||||
shouldEnsureVisible: true,
|
||||
hint: '',
|
||||
darkMode: false,
|
||||
customBodyCssStyle: HtmlUtils.customCssStyleHtmlEditor(direction: widget.direction),
|
||||
),
|
||||
blockQuotedContent: widget.content,
|
||||
htmlToolbarOptions: const HtmlToolbarOptions(
|
||||
toolbarType: ToolbarType.hide,
|
||||
defaultToolbarButtons: []
|
||||
),
|
||||
otherOptions: const OtherOptions(height: 550),
|
||||
callbacks: Callbacks(
|
||||
onBeforeCommand: widget.onChangeContent,
|
||||
onChangeContent: widget.onChangeContent,
|
||||
onInit: () => widget.onInitial?.call(widget.content),
|
||||
onFocus: widget.onFocus,
|
||||
onBlur: widget.onUnFocus,
|
||||
onMouseDown: () => widget.onMouseDown?.call(context),
|
||||
onChangeSelection: widget.onEditorSettings,
|
||||
onChangeCodeview: widget.onChangeContent
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user