TF-2717 Display attachment bar below subject field on mobile

This commit is contained in:
dab246
2024-03-19 12:20:48 +07:00
committed by Dat H. Pham
parent d9f4005bdf
commit e6e25fc06d
8 changed files with 171 additions and 58 deletions
@@ -98,7 +98,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
final networkConnectionController = Get.find<NetworkConnectionController>();
final _dynamicUrlInterceptors = Get.find<DynamicUrlInterceptors>();
final expandModeAttachments = ExpandMode.EXPAND.obs;
final composerArguments = Rxn<ComposerArguments>();
final isEnableEmailSendButton = false.obs;
final isInitialRecipient = false.obs;
@@ -1320,12 +1319,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
mailboxDashBoardController.closeComposerOverlay();
}
void toggleDisplayAttachments() {
final newExpandMode = expandModeAttachments.value == ExpandMode.COLLAPSE
? ExpandMode.EXPAND : ExpandMode.COLLAPSE;
expandModeAttachments.value = newExpandMode;
}
void addEmailAddressType(PrefixEmailAddress prefixEmailAddress) {
switch(prefixEmailAddress) {
case PrefixEmailAddress.from:
@@ -185,6 +185,16 @@ class ComposerView extends GetWidget<ComposerController> {
margin: ComposerStyle.mobileSubjectMargin,
onTapOutside: controller.onTapOutsideSubject,
),
Obx(() {
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
return MobileAttachmentComposerWidget(
listFileUploaded: controller.uploadController.listUploadAttachments,
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
);
} else {
return const SizedBox.shrink();
}
}),
Obx(() => Center(
child: InsertImageLoadingBarWidget(
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
@@ -201,16 +211,6 @@ class ComposerView extends GetWidget<ComposerController> {
onLoadCompletedEditorAction: controller.onLoadCompletedMobileEditorAction,
),
)),
Obx(() {
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
return MobileAttachmentComposerWidget(
listFileUploaded: controller.uploadController.listUploadAttachments,
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
);
} else {
return const SizedBox.shrink();
}
}),
const SizedBox(height: ComposerStyle.keyboardMaxHeight),
],
),
@@ -331,6 +331,16 @@ class ComposerView extends GetWidget<ComposerController> {
margin: ComposerStyle.mobileSubjectMargin,
onTapOutside: controller.onTapOutsideSubject,
),
Obx(() {
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
return MobileAttachmentComposerWidget(
listFileUploaded: controller.uploadController.listUploadAttachments,
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
);
} else {
return const SizedBox.shrink();
}
}),
Obx(() => Center(
child: InsertImageLoadingBarWidget(
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
@@ -347,16 +357,6 @@ class ComposerView extends GetWidget<ComposerController> {
onLoadCompletedEditorAction: controller.onLoadCompletedMobileEditorAction,
),
)),
Obx(() {
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
return MobileAttachmentComposerWidget(
listFileUploaded: controller.uploadController.listUploadAttachments,
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
);
} else {
return const SizedBox.shrink();
}
})
],
),
)
@@ -190,7 +190,7 @@ class ComposerView extends GetWidget<ComposerController> {
return AttachmentComposerWidget(
listFileUploaded: controller.uploadController.listUploadAttachments,
isCollapsed: controller.isAttachmentCollapsed,
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
);
} else {
@@ -423,7 +423,7 @@ class ComposerView extends GetWidget<ComposerController> {
return AttachmentComposerWidget(
listFileUploaded: controller.uploadController.listUploadAttachments,
isCollapsed: controller.isAttachmentCollapsed,
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
);
} else {
@@ -675,7 +675,7 @@ class ComposerView extends GetWidget<ComposerController> {
return AttachmentComposerWidget(
listFileUploaded: controller.uploadController.listUploadAttachments,
isCollapsed: controller.isAttachmentCollapsed,
onDeleteAttachmentAction: (fileState) => controller.deleteAttachmentUploaded(fileState.uploadTaskId),
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
);
} else {
@@ -9,9 +9,10 @@ import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_item_composer_widget_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_progress_loading_composer_widget.dart';
import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
typedef OnDeleteAttachmentAction = void Function(UploadFileState fileState);
typedef OnDeleteAttachmentAction = void Function(UploadTaskId uploadTaskId);
class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
@@ -100,7 +101,7 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
borderRadius: AttachmentItemComposerWidgetStyle.deleteIconRadius,
padding: AttachmentItemComposerWidgetStyle.deleteIconPadding,
iconColor: AttachmentItemComposerWidgetStyle.deleteIconColor,
onTapActionCallback: () => onDeleteAttachmentAction?.call(fileState),
onTapActionCallback: () => onDeleteAttachmentAction?.call(fileState.uploadTaskId),
)
],
),
@@ -1,4 +1,7 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/presentation/views/list/sliver_grid_delegate_fixed_height.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -6,20 +9,47 @@ import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_i
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/upload/presentation/model/upload_file_state.dart';
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class MobileAttachmentComposerWidget extends StatelessWidget {
class MobileAttachmentComposerWidget extends StatefulWidget {
final List<UploadFileState> listFileUploaded;
final OnDeleteAttachmentAction onDeleteAttachmentAction;
final _responsiveUtils = Get.find<ResponsiveUtils>();
MobileAttachmentComposerWidget({
const MobileAttachmentComposerWidget({
super.key,
required this.listFileUploaded,
required this.onDeleteAttachmentAction,
});
@override
State<MobileAttachmentComposerWidget> createState() => _MobileAttachmentComposerWidgetState();
}
class _MobileAttachmentComposerWidgetState extends State<MobileAttachmentComposerWidget> {
static const int _maxCountDisplayedAttachments = 2;
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
List<UploadFileState> _listFileDisplayed = [];
bool _isCollapsed = false;
@override
void initState() {
super.initState();
_updateListFileDisplayed();
}
@override
void didUpdateWidget(covariant MobileAttachmentComposerWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.listFileUploaded != widget.listFileUploaded) {
_updateListFileDisplayed();
}
}
@override
Widget build(BuildContext context) {
return Container(
@@ -33,10 +63,9 @@ class MobileAttachmentComposerWidget extends StatelessWidget {
SizedBox(
width: _responsiveUtils.getSizeScreenWidth(context) * 0.7,
child: GridView.builder(
reverse: true,
primary: false,
shrinkWrap: true,
itemCount: listFileUploaded.length,
itemCount: _listFileDisplayed.length,
gridDelegate: const SliverGridDelegateFixedHeight(
height: MobileAttachmentComposerWidgetStyle.listItemHeight,
crossAxisCount: MobileAttachmentComposerWidgetStyle.maxItemRow,
@@ -44,32 +73,93 @@ class MobileAttachmentComposerWidget extends StatelessWidget {
),
itemBuilder: (context, index) {
return AttachmentItemComposerWidget(
fileState: listFileUploaded[index],
fileState: _listFileDisplayed[index],
itemMargin: MobileAttachmentComposerWidgetStyle.itemMargin,
onDeleteAttachmentAction: onDeleteAttachmentAction
onDeleteAttachmentAction: widget.onDeleteAttachmentAction
);
}
),
)
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
);
}
...[
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(child: SizedBox(
width: AttachmentItemComposerWidgetStyle.width,
child: ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: _listFileDisplayed.length,
itemBuilder: (context, index) {
return AttachmentItemComposerWidget(
fileState: _listFileDisplayed[index],
itemMargin: MobileAttachmentComposerWidgetStyle.itemMargin,
onDeleteAttachmentAction: widget.onDeleteAttachmentAction
);
}
),
)),
if (!_isCollapsed && _isExceededDisplayedAttachments)
TMailButtonWidget(
text: AppLocalizations.of(context).showLess,
icon: _imagePaths.icChevronUp,
iconAlignment: TextDirection.rtl,
iconSpace: 2,
iconSize: 24,
iconColor: AppColor.primaryColor,
backgroundColor: Colors.transparent,
textStyle: Theme.of(context).textTheme.labelSmall?.copyWith(
fontSize: 15,
color: AppColor.primaryColor
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
margin: const EdgeInsetsDirectional.only(start: 8),
onTapActionCallback: _toggleListAttachments
)
],
),
)
if (_isCollapsed && _isExceededDisplayedAttachments)
TMailButtonWidget.fromText(
text: AppLocalizations.of(context).showMore(_countRemainingAttachments),
backgroundColor: Colors.transparent,
textStyle: Theme.of(context).textTheme.labelSmall?.copyWith(
fontSize: 15,
color: AppColor.primaryColor
),
margin: const EdgeInsetsDirectional.only(top: 5),
onTapActionCallback: _toggleListAttachments
)
]
]
),
);
}
bool get _listFileUploadedSuccess =>
widget.listFileUploaded.every((uploadFile) => uploadFile.uploadStatus.completed);
bool get _isExceededDisplayedAttachments =>
_listFileUploadedSuccess &&
widget.listFileUploaded.length > _maxCountDisplayedAttachments;
int get _countRemainingAttachments =>
widget.listFileUploaded.length - _maxCountDisplayedAttachments;
void _updateListFileDisplayed() {
final reversedList = widget.listFileUploaded.reversed.toList();
if (_isCollapsed) {
_listFileDisplayed = reversedList.sublist(0, _maxCountDisplayedAttachments);
} else {
_listFileDisplayed = reversedList;
}
}
void _toggleListAttachments() {
setState(() {
_isCollapsed = !_isCollapsed;
_updateListFileDisplayed();
});
}
}
@@ -338,9 +338,9 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
TMailButtonWidget.fromIcon(
icon: _isAllRecipientInputEnabled
? _imagePaths.icChevronUp
: _imagePaths.icChevronDown,
: _imagePaths.icChevronDownOutline,
backgroundColor: Colors.transparent,
iconSize: 20,
iconSize: 24,
padding: const EdgeInsets.all(5),
iconColor: AppColor.colorLabelComposer,
margin: RecipientComposerWidgetStyle.enableRecipientButtonMargin,
+17 -1
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2024-03-13T01:12:22.224880",
"@@last_modified": "2024-03-19T12:10:23.549474",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -3857,5 +3857,21 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"showMore": "Show more (+{count})",
"@showMore": {
"type": "text",
"placeholders_order": [
"count"
],
"placeholders": {
"count": {}
}
},
"showLess": "Show less",
"@showLess": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
@@ -4030,4 +4030,17 @@ class AppLocalizations {
name: 'mailToAttendees'
);
}
String showMore(int count) {
return Intl.message(
'Show more (+$count)',
name: 'showMore',
args: [count]);
}
String get showLess {
return Intl.message(
'Show less',
name: 'showLess');
}
}