TF-2116 Apply new design attachment in mobile composer

(cherry picked from commit 4d8a7590e11044963093a98095948d9820f34efb)
This commit is contained in:
dab246
2023-09-07 22:49:26 +07:00
committed by Dat H. Pham
parent 655446133c
commit 27b5342132
14 changed files with 327 additions and 194 deletions
@@ -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,
@@ -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();
}
}
);
}
}
);
}
}
@@ -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