TF-2717 Display attachment bar below subject field on mobile
This commit is contained in:
@@ -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),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
+113
-23
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user