TF-2116 Apply new design attachment in mobile composer
(cherry picked from commit 4d8a7590e11044963093a98095948d9820f34efb)
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CircleLoadingWidgetStyles {
|
||||||
|
static const Color progressColor = AppColor.primaryColor;
|
||||||
|
static const double size = 24;
|
||||||
|
static const double width = 2;
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class PopupItemWidgetStyle {
|
class PopupItemWidgetStyle {
|
||||||
static const double iconSize = 20;
|
static const double iconSize = 24;
|
||||||
static const double selectedIconSize = 16;
|
static const double selectedIconSize = 16;
|
||||||
static const double space = 12;
|
static const double space = 12;
|
||||||
static const double height = 48;
|
static const double height = 48;
|
||||||
|
static const double minWidth = 256;
|
||||||
|
|
||||||
static const EdgeInsetsGeometry padding = EdgeInsets.symmetric(horizontal: 20, vertical: 16);
|
static const EdgeInsetsGeometry padding = EdgeInsets.symmetric(horizontal: 20, vertical: 16);
|
||||||
static const EdgeInsetsGeometry iconSelectedPadding = EdgeInsetsDirectional.only(start: 12);
|
static const EdgeInsetsGeometry iconSelectedPadding = EdgeInsetsDirectional.only(start: 12);
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/styles/circle_loading_widget_styles.dart';
|
||||||
|
|
||||||
|
class CircleLoadingWidget extends StatelessWidget {
|
||||||
|
|
||||||
|
final double? size;
|
||||||
|
final EdgeInsetsGeometry? padding;
|
||||||
|
|
||||||
|
const CircleLoadingWidget({super.key, this.size, this.padding});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (padding != null) {
|
||||||
|
return Padding(
|
||||||
|
padding: padding!,
|
||||||
|
child: SizedBox(
|
||||||
|
width: size ?? CircleLoadingWidgetStyles.size,
|
||||||
|
height: size ?? CircleLoadingWidgetStyles.size,
|
||||||
|
child: const CircularProgressIndicator(
|
||||||
|
color: CircleLoadingWidgetStyles.progressColor,
|
||||||
|
strokeWidth: CircleLoadingWidgetStyles.width,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return SizedBox(
|
||||||
|
width: size ?? CircleLoadingWidgetStyles.size,
|
||||||
|
height: size ?? CircleLoadingWidgetStyles.size,
|
||||||
|
child: const CircularProgressIndicator(
|
||||||
|
color: CircleLoadingWidgetStyles.progressColor,
|
||||||
|
strokeWidth: CircleLoadingWidgetStyles.width,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ class PopupItemWidget extends StatelessWidget {
|
|||||||
onTap: onCallbackAction,
|
onTap: onCallbackAction,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: PopupItemWidgetStyle.height,
|
height: PopupItemWidgetStyle.height,
|
||||||
|
constraints: const BoxConstraints(minWidth: PopupItemWidgetStyle.minWidth),
|
||||||
padding: padding,
|
padding: padding,
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
|
|||||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile_app_bar_composer_widget_style.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/mobile_container_view.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/mobile_container_view.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/mobile_editor_view.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/mobile_editor_view.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/tablet_container_view.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/tablet_container_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/insert_image_loading_bar_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/mobile_attachment_composer_widget.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/mobile_attachment_composer_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/app_bar_composer_widget.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/app_bar_composer_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/landscape_app_bar_composer_widget.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/landscape_app_bar_composer_widget.dart';
|
||||||
@@ -49,6 +51,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
onInsertImageAction: (constraints) => controller.isNetworkConnectionAvailable
|
onInsertImageAction: (constraints) => controller.isNetworkConnectionAvailable
|
||||||
? controller.insertImage(context, constraints.maxWidth)
|
? controller.insertImage(context, constraints.maxWidth)
|
||||||
: null,
|
: null,
|
||||||
|
backgroundColor: MobileAppBarComposerWidgetStyle.backgroundColor,
|
||||||
childBuilder: (context) => SafeArea(
|
childBuilder: (context) => SafeArea(
|
||||||
left: !_responsiveUtils.isLandscapeMobile(context),
|
left: !_responsiveUtils.isLandscapeMobile(context),
|
||||||
right: !_responsiveUtils.isLandscapeMobile(context),
|
right: !_responsiveUtils.isLandscapeMobile(context),
|
||||||
@@ -165,6 +168,13 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
padding: ComposerStyle.mobileSubjectPadding,
|
padding: ComposerStyle.mobileSubjectPadding,
|
||||||
margin: ComposerStyle.mobileSubjectMargin,
|
margin: ComposerStyle.mobileSubjectMargin,
|
||||||
),
|
),
|
||||||
|
Obx(() => Center(
|
||||||
|
child: InsertImageLoadingBarWidget(
|
||||||
|
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
|
||||||
|
viewState: controller.viewState.value,
|
||||||
|
padding: ComposerStyle.insertImageLoadingBarPadding,
|
||||||
|
),
|
||||||
|
)),
|
||||||
Obx(() => GestureDetector(
|
Obx(() => GestureDetector(
|
||||||
onTapDown: (_) {
|
onTapDown: (_) {
|
||||||
controller.removeFocusAllInputEditorHeader();
|
controller.removeFocusAllInputEditorHeader();
|
||||||
@@ -182,9 +192,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
||||||
return MobileAttachmentComposerWidget(
|
return MobileAttachmentComposerWidget(
|
||||||
listFileUploaded: controller.uploadController.listUploadAttachments,
|
listFileUploaded: controller.uploadController.listUploadAttachments,
|
||||||
isShowMore: controller.isAttachmentCollapsed,
|
|
||||||
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
||||||
onShowMoreAttachmentAction: (isShowMore) => controller.isAttachmentCollapsed = !isShowMore,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
@@ -300,6 +308,13 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
padding: ComposerStyle.mobileSubjectPadding,
|
padding: ComposerStyle.mobileSubjectPadding,
|
||||||
margin: ComposerStyle.mobileSubjectMargin,
|
margin: ComposerStyle.mobileSubjectMargin,
|
||||||
),
|
),
|
||||||
|
Obx(() => Center(
|
||||||
|
child: InsertImageLoadingBarWidget(
|
||||||
|
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
|
||||||
|
viewState: controller.viewState.value,
|
||||||
|
padding: ComposerStyle.insertImageLoadingBarPadding,
|
||||||
|
),
|
||||||
|
)),
|
||||||
Obx(() => GestureDetector(
|
Obx(() => GestureDetector(
|
||||||
onTapDown: (_) {
|
onTapDown: (_) {
|
||||||
controller.removeFocusAllInputEditorHeader();
|
controller.removeFocusAllInputEditorHeader();
|
||||||
@@ -317,9 +332,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
||||||
return MobileAttachmentComposerWidget(
|
return MobileAttachmentComposerWidget(
|
||||||
listFileUploaded: controller.uploadController.listUploadAttachments,
|
listFileUploaded: controller.uploadController.listUploadAttachments,
|
||||||
isShowMore: controller.isAttachmentCollapsed,
|
|
||||||
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
||||||
onShowMoreAttachmentAction: (isShowMore) => controller.isAttachmentCollapsed = !isShowMore,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import 'package:tmail_ui_user/features/composer/presentation/view/web/desktop_re
|
|||||||
import 'package:tmail_ui_user/features/composer/presentation/view/web/mobile_responsive_container_view.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/view/web/mobile_responsive_container_view.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/view/web/tablet_responsive_container_view.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/view/web/tablet_responsive_container_view.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/view/web/web_editor_view.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/view/web/web_editor_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/insert_image_loading_bar_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/desktop_app_bar_composer_widget.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/desktop_app_bar_composer_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/attachment_composer_widget.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/attachment_composer_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart';
|
||||||
@@ -142,20 +143,32 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
margin: ComposerStyle.mobileSubjectMargin,
|
margin: ComposerStyle.mobileSubjectMargin,
|
||||||
),
|
),
|
||||||
Obx(() => Expanded(
|
Obx(() => Expanded(
|
||||||
child: Padding(
|
child: Stack(
|
||||||
padding: ComposerStyle.mobileEditorPadding,
|
children: [
|
||||||
child: WebEditorView(
|
Padding(
|
||||||
editorController: controller.richTextWebController.editorController,
|
padding: ComposerStyle.mobileEditorPadding,
|
||||||
arguments: controller.composerArguments.value,
|
child: WebEditorView(
|
||||||
contentViewState: controller.emailContentsViewState.value,
|
editorController: controller.richTextWebController.editorController,
|
||||||
currentWebContent: controller.textEditorWeb,
|
arguments: controller.composerArguments.value,
|
||||||
onInitial: controller.handleInitHtmlEditorWeb,
|
contentViewState: controller.emailContentsViewState.value,
|
||||||
onChangeContent: controller.onChangeTextEditorWeb,
|
currentWebContent: controller.textEditorWeb,
|
||||||
onFocus: controller.handleOnFocusHtmlEditorWeb,
|
onInitial: controller.handleInitHtmlEditorWeb,
|
||||||
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
|
onChangeContent: controller.onChangeTextEditorWeb,
|
||||||
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
|
onFocus: controller.handleOnFocusHtmlEditorWeb,
|
||||||
onEditorSettings: controller.richTextWebController.onEditorSettingsChange,
|
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
|
||||||
),
|
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
|
||||||
|
onEditorSettings: controller.richTextWebController.onEditorSettingsChange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() => Align(
|
||||||
|
alignment: AlignmentDirectional.topCenter,
|
||||||
|
child: InsertImageLoadingBarWidget(
|
||||||
|
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
|
||||||
|
viewState: controller.viewState.value,
|
||||||
|
padding: ComposerStyle.insertImageLoadingBarPadding,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
@@ -293,51 +306,63 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
),
|
),
|
||||||
color: ComposerStyle.backgroundEditorColor
|
color: ComposerStyle.backgroundEditorColor
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Obx(() => Expanded(
|
Column(
|
||||||
child: Padding(
|
children: [
|
||||||
padding: ComposerStyle.desktopEditorPadding,
|
Obx(() => Expanded(
|
||||||
child: WebEditorView(
|
child: Padding(
|
||||||
editorController: controller.richTextWebController.editorController,
|
padding: ComposerStyle.desktopEditorPadding,
|
||||||
arguments: controller.composerArguments.value,
|
child: WebEditorView(
|
||||||
contentViewState: controller.emailContentsViewState.value,
|
editorController: controller.richTextWebController.editorController,
|
||||||
currentWebContent: controller.textEditorWeb,
|
arguments: controller.composerArguments.value,
|
||||||
onInitial: controller.handleInitHtmlEditorWeb,
|
contentViewState: controller.emailContentsViewState.value,
|
||||||
onChangeContent: controller.onChangeTextEditorWeb,
|
currentWebContent: controller.textEditorWeb,
|
||||||
onFocus: controller.handleOnFocusHtmlEditorWeb,
|
onInitial: controller.handleInitHtmlEditorWeb,
|
||||||
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
|
onChangeContent: controller.onChangeTextEditorWeb,
|
||||||
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
|
onFocus: controller.handleOnFocusHtmlEditorWeb,
|
||||||
onEditorSettings: controller.richTextWebController.onEditorSettingsChange,
|
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
|
||||||
),
|
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
|
||||||
|
onEditorSettings: controller.richTextWebController.onEditorSettingsChange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Obx(() {
|
||||||
|
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
||||||
|
return AttachmentComposerWidget(
|
||||||
|
listFileUploaded: controller.uploadController.listUploadAttachments,
|
||||||
|
isCollapsed: controller.isAttachmentCollapsed,
|
||||||
|
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
||||||
|
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Obx(() {
|
||||||
|
if (controller.richTextWebController.isFormattingOptionsEnabled) {
|
||||||
|
return ToolbarRichTextWebBuilder(
|
||||||
|
richTextWebController: controller.richTextWebController,
|
||||||
|
padding: ComposerStyle.richToolbarPadding,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: ComposerStyle.richToolbarColor,
|
||||||
|
boxShadow: ComposerStyle.richToolbarShadow
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Obx(() => Align(
|
||||||
|
alignment: AlignmentDirectional.topCenter,
|
||||||
|
child: InsertImageLoadingBarWidget(
|
||||||
|
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
|
||||||
|
viewState: controller.viewState.value,
|
||||||
|
padding: ComposerStyle.insertImageLoadingBarPadding,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
Obx(() {
|
|
||||||
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
|
||||||
return AttachmentComposerWidget(
|
|
||||||
listFileUploaded: controller.uploadController.listUploadAttachments,
|
|
||||||
isCollapsed: controller.isAttachmentCollapsed,
|
|
||||||
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
|
||||||
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Obx(() {
|
|
||||||
if (controller.richTextWebController.isFormattingOptionsEnabled) {
|
|
||||||
return ToolbarRichTextWebBuilder(
|
|
||||||
richTextWebController: controller.richTextWebController,
|
|
||||||
padding: ComposerStyle.richToolbarPadding,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ComposerStyle.richToolbarColor,
|
|
||||||
boxShadow: ComposerStyle.richToolbarShadow
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -461,64 +486,76 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
margin: ComposerStyle.tabletSubjectMargin,
|
margin: ComposerStyle.tabletSubjectMargin,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(
|
bottom: BorderSide(
|
||||||
color: ComposerStyle.borderColor,
|
color: ComposerStyle.borderColor,
|
||||||
width: 1
|
width: 1
|
||||||
)
|
)
|
||||||
),
|
|
||||||
color: ComposerStyle.backgroundEditorColor
|
|
||||||
),
|
),
|
||||||
child: Column(
|
color: ComposerStyle.backgroundEditorColor
|
||||||
children: [
|
),
|
||||||
Obx(() => Expanded(
|
child: Stack(
|
||||||
child: Padding(
|
children: [
|
||||||
padding: ComposerStyle.tabletEditorPadding,
|
Column(
|
||||||
child: WebEditorView(
|
children: [
|
||||||
editorController: controller.richTextWebController.editorController,
|
Obx(() => Expanded(
|
||||||
arguments: controller.composerArguments.value,
|
child: Padding(
|
||||||
contentViewState: controller.emailContentsViewState.value,
|
padding: ComposerStyle.tabletEditorPadding,
|
||||||
currentWebContent: controller.textEditorWeb,
|
child: WebEditorView(
|
||||||
onInitial: controller.handleInitHtmlEditorWeb,
|
editorController: controller.richTextWebController.editorController,
|
||||||
onChangeContent: controller.onChangeTextEditorWeb,
|
arguments: controller.composerArguments.value,
|
||||||
onFocus: controller.handleOnFocusHtmlEditorWeb,
|
contentViewState: controller.emailContentsViewState.value,
|
||||||
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
|
currentWebContent: controller.textEditorWeb,
|
||||||
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
|
onInitial: controller.handleInitHtmlEditorWeb,
|
||||||
onEditorSettings: controller.richTextWebController.onEditorSettingsChange,
|
onChangeContent: controller.onChangeTextEditorWeb,
|
||||||
),
|
onFocus: controller.handleOnFocusHtmlEditorWeb,
|
||||||
),
|
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
|
||||||
)),
|
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
|
||||||
Obx(() {
|
onEditorSettings: controller.richTextWebController.onEditorSettingsChange,
|
||||||
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
|
||||||
return AttachmentComposerWidget(
|
|
||||||
listFileUploaded: controller.uploadController.listUploadAttachments,
|
|
||||||
isCollapsed: controller.isAttachmentCollapsed,
|
|
||||||
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
|
||||||
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Obx(() {
|
|
||||||
if (controller.richTextWebController.isFormattingOptionsEnabled) {
|
|
||||||
return ToolbarRichTextWebBuilder(
|
|
||||||
richTextWebController: controller.richTextWebController,
|
|
||||||
padding: ComposerStyle.richToolbarPadding,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ComposerStyle.richToolbarColor,
|
|
||||||
boxShadow: ComposerStyle.richToolbarShadow
|
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
} else {
|
)),
|
||||||
return const SizedBox.shrink();
|
Obx(() {
|
||||||
}
|
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
||||||
})
|
return AttachmentComposerWidget(
|
||||||
],
|
listFileUploaded: controller.uploadController.listUploadAttachments,
|
||||||
),
|
isCollapsed: controller.isAttachmentCollapsed,
|
||||||
)
|
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
|
||||||
|
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Obx(() {
|
||||||
|
if (controller.richTextWebController.isFormattingOptionsEnabled) {
|
||||||
|
return ToolbarRichTextWebBuilder(
|
||||||
|
richTextWebController: controller.richTextWebController,
|
||||||
|
padding: ComposerStyle.richToolbarPadding,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: ComposerStyle.richToolbarColor,
|
||||||
|
boxShadow: ComposerStyle.richToolbarShadow
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Obx(() => Align(
|
||||||
|
alignment: AlignmentDirectional.topCenter,
|
||||||
|
child: InsertImageLoadingBarWidget(
|
||||||
|
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
|
||||||
|
viewState: controller.viewState.value,
|
||||||
|
padding: ComposerStyle.insertImageLoadingBarPadding,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
Obx(() => BottomBarComposerWidget(
|
Obx(() => BottomBarComposerWidget(
|
||||||
isCodeViewEnabled: controller.richTextWebController.codeViewEnabled,
|
isCodeViewEnabled: controller.richTextWebController.codeViewEnabled,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class ComposerStyle {
|
|||||||
static const EdgeInsetsGeometry mobileSubjectPadding = EdgeInsetsDirectional.only(end: 16, top: 12, bottom: 12);
|
static const EdgeInsetsGeometry mobileSubjectPadding = EdgeInsetsDirectional.only(end: 16, top: 12, bottom: 12);
|
||||||
static const EdgeInsetsGeometry mobileEditorPadding = EdgeInsetsDirectional.symmetric(horizontal: 12);
|
static const EdgeInsetsGeometry mobileEditorPadding = EdgeInsetsDirectional.symmetric(horizontal: 12);
|
||||||
static const EdgeInsetsGeometry popupItemPadding = EdgeInsetsDirectional.symmetric(horizontal: 12);
|
static const EdgeInsetsGeometry popupItemPadding = EdgeInsetsDirectional.symmetric(horizontal: 12);
|
||||||
|
static const EdgeInsetsGeometry insertImageLoadingBarPadding = EdgeInsetsDirectional.only(top: 12);
|
||||||
|
|
||||||
static const TextStyle popupItemTextStyle = TextStyle(
|
static const TextStyle popupItemTextStyle = TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
|
|||||||
+3
-10
@@ -1,17 +1,10 @@
|
|||||||
import 'package:core/presentation/extensions/color_extension.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class MobileAttachmentComposerWidgetStyle {
|
class MobileAttachmentComposerWidgetStyle {
|
||||||
static const double listItemSpace = 8;
|
static const double listItemSpace = 8;
|
||||||
|
static const int maxItemRow = 2;
|
||||||
static const Color backgroundColor = Colors.white;
|
static const double listItemHeight = 50;
|
||||||
|
|
||||||
static const EdgeInsetsGeometry padding = EdgeInsetsDirectional.symmetric(vertical: 8, horizontal: 16);
|
static const EdgeInsetsGeometry padding = EdgeInsetsDirectional.symmetric(vertical: 8, horizontal: 16);
|
||||||
static const EdgeInsetsGeometry showMoreMargin = EdgeInsetsDirectional.only(top: 8);
|
static const EdgeInsetsGeometry itemMargin = EdgeInsetsDirectional.only(top: 8);
|
||||||
|
|
||||||
static const TextStyle showMoreButtonTextStyle = TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
color: AppColor.primaryColor,
|
|
||||||
fontWeight: FontWeight.w500
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import 'package:core/presentation/utils/responsive_utils.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
|
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:rich_text_composer/rich_text_composer.dart';
|
import 'package:rich_text_composer/rich_text_composer.dart' as rich_composer;
|
||||||
import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart';
|
import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile/mobile_container_view_style.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile/mobile_container_view_style.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
@@ -12,11 +12,12 @@ typedef OnInsertImageAction = Function(BoxConstraints constraints);
|
|||||||
class MobileContainerView extends StatelessWidget {
|
class MobileContainerView extends StatelessWidget {
|
||||||
|
|
||||||
final Widget Function(BuildContext context) childBuilder;
|
final Widget Function(BuildContext context) childBuilder;
|
||||||
final RichTextController keyboardRichTextController;
|
final rich_composer.RichTextController keyboardRichTextController;
|
||||||
final VoidCallback onCloseViewAction;
|
final VoidCallback onCloseViewAction;
|
||||||
final VoidCallback? onAttachFileAction;
|
final VoidCallback? onAttachFileAction;
|
||||||
final OnInsertImageAction? onInsertImageAction;
|
final OnInsertImageAction? onInsertImageAction;
|
||||||
final VoidCallback? onClearFocusAction;
|
final VoidCallback? onClearFocusAction;
|
||||||
|
final Color? backgroundColor;
|
||||||
|
|
||||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ class MobileContainerView extends StatelessWidget {
|
|||||||
this.onAttachFileAction,
|
this.onAttachFileAction,
|
||||||
this.onInsertImageAction,
|
this.onInsertImageAction,
|
||||||
this.onClearFocusAction,
|
this.onClearFocusAction,
|
||||||
|
this.backgroundColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -40,11 +42,11 @@ class MobileContainerView extends StatelessWidget {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: onClearFocusAction,
|
onTap: onClearFocusAction,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: MobileContainerViewStyle.outSideBackgroundColor,
|
backgroundColor: backgroundColor ?? MobileContainerViewStyle.outSideBackgroundColor,
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
body: LayoutBuilder(builder: (context, constraints) {
|
body: LayoutBuilder(builder: (context, constraints) {
|
||||||
return KeyboardVisibilityBuilder(builder: (context, isKeyboardVisible) {
|
return KeyboardVisibilityBuilder(builder: (context, isKeyboardVisible) {
|
||||||
return KeyboardRichText(
|
return rich_composer.KeyboardRichText(
|
||||||
richTextController: keyboardRichTextController,
|
richTextController: keyboardRichTextController,
|
||||||
keyBroadToolbar: RichTextKeyboardToolBar(
|
keyBroadToolbar: RichTextKeyboardToolBar(
|
||||||
backgroundKeyboardToolBarColor: MobileContainerViewStyle.keyboardToolbarBackgroundColor,
|
backgroundKeyboardToolBarColor: MobileContainerViewStyle.keyboardToolbarBackgroundColor,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
|||||||
),
|
),
|
||||||
width: AttachmentItemComposerWidgetStyle.width,
|
width: AttachmentItemComposerWidgetStyle.width,
|
||||||
padding: AttachmentItemComposerWidgetStyle.padding,
|
padding: AttachmentItemComposerWidgetStyle.padding,
|
||||||
|
margin: itemMargin,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/widget/circle_loading_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_base64_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart';
|
||||||
|
|
||||||
|
class InsertImageLoadingBarWidget extends StatelessWidget {
|
||||||
|
|
||||||
|
final Either<Failure, Success> viewState;
|
||||||
|
final Either<Failure, Success> uploadInlineViewState;
|
||||||
|
final EdgeInsetsGeometry? padding;
|
||||||
|
|
||||||
|
const InsertImageLoadingBarWidget({
|
||||||
|
super.key,
|
||||||
|
required this.viewState,
|
||||||
|
required this.uploadInlineViewState,
|
||||||
|
this.padding,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return uploadInlineViewState.fold(
|
||||||
|
(failure) {
|
||||||
|
return viewState.fold(
|
||||||
|
(failure) => const SizedBox.shrink(),
|
||||||
|
(success) {
|
||||||
|
if (success is DownloadingImageAsBase64) {
|
||||||
|
return CircleLoadingWidget(padding: padding);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(success) {
|
||||||
|
if (success is UploadingAttachmentUploadState) {
|
||||||
|
return CircleLoadingWidget(padding: padding);
|
||||||
|
} else {
|
||||||
|
return viewState.fold(
|
||||||
|
(failure) => const SizedBox.shrink(),
|
||||||
|
(success) {
|
||||||
|
if (success is DownloadingImageAsBase64) {
|
||||||
|
return CircleLoadingWidget(padding: padding);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
-58
@@ -1,83 +1,72 @@
|
|||||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||||
|
import 'package:core/presentation/views/list/sliver_grid_delegate_fixed_height.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_item_composer_widget_style.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile/mobile_attachment_composer_widget_style.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile/mobile_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_item_composer_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
|
||||||
|
|
||||||
typedef OnShowMoreAttachmentAction = void Function(bool isShowMore);
|
class MobileAttachmentComposerWidget extends StatelessWidget {
|
||||||
|
|
||||||
class MobileAttachmentComposerWidget extends StatefulWidget {
|
|
||||||
|
|
||||||
final List<UploadFileState> listFileUploaded;
|
final List<UploadFileState> listFileUploaded;
|
||||||
final bool isShowMore;
|
|
||||||
final OnDeleteAttachmentAction onDeleteAttachmentAction;
|
final OnDeleteAttachmentAction onDeleteAttachmentAction;
|
||||||
final OnShowMoreAttachmentAction onShowMoreAttachmentAction;
|
|
||||||
|
|
||||||
const MobileAttachmentComposerWidget({
|
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||||
|
|
||||||
|
MobileAttachmentComposerWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.listFileUploaded,
|
required this.listFileUploaded,
|
||||||
required this.isShowMore,
|
|
||||||
required this.onDeleteAttachmentAction,
|
required this.onDeleteAttachmentAction,
|
||||||
required this.onShowMoreAttachmentAction,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
|
||||||
State<MobileAttachmentComposerWidget> createState() => _MobileAttachmentComposerWidgetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MobileAttachmentComposerWidgetState extends State<MobileAttachmentComposerWidget> {
|
|
||||||
|
|
||||||
static const int _maxDisplayedItem = 6;
|
|
||||||
|
|
||||||
bool _isShowMore = false;
|
|
||||||
int _currentCountDisplayed = _maxDisplayedItem;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_isShowMore = widget.isShowMore;
|
|
||||||
if (_isShowMore) {
|
|
||||||
_currentCountDisplayed = widget.listFileUploaded.length;
|
|
||||||
} else {
|
|
||||||
_currentCountDisplayed = widget.listFileUploaded.length > 6
|
|
||||||
? 6
|
|
||||||
: widget.listFileUploaded.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final displayedFiles = widget.listFileUploaded.sublist(0, _currentCountDisplayed);
|
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
color: MobileAttachmentComposerWidgetStyle.backgroundColor,
|
|
||||||
width: double.infinity,
|
|
||||||
padding: MobileAttachmentComposerWidgetStyle.padding,
|
padding: MobileAttachmentComposerWidgetStyle.padding,
|
||||||
|
width: double.infinity,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Wrap(
|
if (_responsiveUtils.isLandscapeMobile(context))
|
||||||
spacing: MobileAttachmentComposerWidgetStyle.listItemSpace,
|
SizedBox(
|
||||||
runSpacing: MobileAttachmentComposerWidgetStyle.listItemSpace,
|
width: _responsiveUtils.getSizeScreenWidth(context) * 0.7,
|
||||||
children: displayedFiles
|
child: GridView.builder(
|
||||||
.map((file) => AttachmentItemComposerWidget(
|
reverse: true,
|
||||||
fileState: file,
|
primary: false,
|
||||||
onDeleteAttachmentAction: widget.onDeleteAttachmentAction
|
shrinkWrap: true,
|
||||||
))
|
itemCount: listFileUploaded.length,
|
||||||
.toList(),
|
gridDelegate: const SliverGridDelegateFixedHeight(
|
||||||
),
|
height: MobileAttachmentComposerWidgetStyle.listItemHeight,
|
||||||
if (!_isShowMore)
|
crossAxisCount: MobileAttachmentComposerWidgetStyle.maxItemRow,
|
||||||
TMailButtonWidget.fromText(
|
crossAxisSpacing: MobileAttachmentComposerWidgetStyle.listItemSpace,
|
||||||
text: AppLocalizations.of(context).showMoreAttachment(widget.listFileUploaded.length),
|
),
|
||||||
textStyle: MobileAttachmentComposerWidgetStyle.showMoreButtonTextStyle,
|
itemBuilder: (context, index) {
|
||||||
margin: MobileAttachmentComposerWidgetStyle.showMoreMargin,
|
return AttachmentItemComposerWidget(
|
||||||
backgroundColor: Colors.transparent,
|
fileState: listFileUploaded[index],
|
||||||
onTapActionCallback: () {
|
itemMargin: MobileAttachmentComposerWidgetStyle.itemMargin,
|
||||||
setState(() => _isShowMore = true);
|
onDeleteAttachmentAction: onDeleteAttachmentAction
|
||||||
widget.onShowMoreAttachmentAction(_isShowMore);
|
);
|
||||||
},
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
SizedBox(
|
||||||
|
width: AttachmentItemComposerWidgetStyle.width,
|
||||||
|
child: ListView.builder(
|
||||||
|
reverse: true,
|
||||||
|
shrinkWrap: true,
|
||||||
|
primary: false,
|
||||||
|
itemCount: listFileUploaded.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return AttachmentItemComposerWidget(
|
||||||
|
fileState: listFileUploaded[index],
|
||||||
|
itemMargin: MobileAttachmentComposerWidgetStyle.itemMargin,
|
||||||
|
onDeleteAttachmentAction: onDeleteAttachmentAction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -291,8 +291,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Obx(() => EmailViewLoadingBarWidget(
|
Obx(() => EmailViewLoadingBarWidget(
|
||||||
viewState: controller.emailLoadedViewState.value,
|
viewState: controller.emailLoadedViewState.value
|
||||||
selectedEmail: presentationEmail
|
|
||||||
)),
|
)),
|
||||||
if (calendarEvent != null)
|
if (calendarEvent != null)
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -2,20 +2,17 @@ import 'package:core/presentation/state/failure.dart';
|
|||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:model/email/presentation_email.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/widget/cupertino_loading_widget.dart';
|
import 'package:tmail_ui_user/features/base/widget/cupertino_loading_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart';
|
||||||
|
|
||||||
class EmailViewLoadingBarWidget extends StatelessWidget {
|
class EmailViewLoadingBarWidget extends StatelessWidget {
|
||||||
|
|
||||||
final PresentationEmail selectedEmail;
|
|
||||||
final Either<Failure, Success> viewState;
|
final Either<Failure, Success> viewState;
|
||||||
|
|
||||||
const EmailViewLoadingBarWidget({
|
const EmailViewLoadingBarWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.viewState,
|
required this.viewState,
|
||||||
required this.selectedEmail
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
Reference in New Issue
Block a user