TF-913 Fix button text line break in advanced search view

This commit is contained in:
dab246
2022-09-21 11:52:42 +07:00
committed by Dat H. Pham
parent 7fe899daf5
commit d0ff07edfb
7 changed files with 182 additions and 139 deletions
+1
View File
@@ -75,6 +75,7 @@ export 'presentation/views/quick_search/quick_search_input_form.dart';
export 'presentation/views/toast/toast_position.dart'; export 'presentation/views/toast/toast_position.dart';
export 'presentation/views/toast/tmail_toast.dart'; export 'presentation/views/toast/tmail_toast.dart';
export 'presentation/views/bottom_popup/full_screen_action_sheet_builder.dart'; export 'presentation/views/bottom_popup/full_screen_action_sheet_builder.dart';
export 'presentation/views/checkbox/labeled_checkbox.dart';
// Resources // Resources
export 'presentation/resources/assets_paths.dart'; export 'presentation/resources/assets_paths.dart';
@@ -146,6 +146,7 @@ extension AppColor on Color {
static const colorDivider = Color(0xFFE7E8EC); static const colorDivider = Color(0xFFE7E8EC);
static const colorDividerVertical = Color(0xFF99A2AD); static const colorDividerVertical = Color(0xFF99A2AD);
static const colorCloseButton = Color(0xFF818C99); static const colorCloseButton = Color(0xFF818C99);
static const colorDropShadow = Color(0x0F000000);
static const mapGradientColor = [ static const mapGradientColor = [
[Color(0xFF21D4FD), Color(0xFFB721FF)], [Color(0xFF21D4FD), Color(0xFFB721FF)],
@@ -120,9 +120,15 @@ Widget buildTextButton(String text, {
backgroundColor: MaterialStateProperty.resolveWith((states) => backgroundColor ?? AppColor.colorTextButton), backgroundColor: MaterialStateProperty.resolveWith((states) => backgroundColor ?? AppColor.colorTextButton),
elevation: MaterialStateProperty.resolveWith((states) => 0), elevation: MaterialStateProperty.resolveWith((states) => 0),
padding: MaterialStateProperty.resolveWith<EdgeInsets>( padding: MaterialStateProperty.resolveWith<EdgeInsets>(
(Set<MaterialState> states) => padding ?? EdgeInsets.zero), (Set<MaterialState> states) => padding ?? EdgeInsets.symmetric(horizontal: 8)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius ?? 0)))), shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius ?? 0)))),
child: Text(text, style: textStyle ?? TextStyle(fontSize: 17, color: Colors.white, fontWeight: FontWeight.w500)), child: Text(
text,
textAlign: TextAlign.center,
style: textStyle ?? TextStyle(
fontSize: 17,
color: Colors.white,
fontWeight: FontWeight.w500)),
onPressed: () => onTap?.call() onPressed: () => onTap?.call()
), ),
); );
@@ -134,13 +140,17 @@ Widget buildButtonWrapText(String name, {
Color? borderColor, Color? borderColor,
double? radius, double? radius,
double? height, double? height,
double? minWidth,
EdgeInsets? padding, EdgeInsets? padding,
FocusNode? focusNode,
IconWebCallback? onTap IconWebCallback? onTap
}) { }) {
return Container( return Container(
height: height ?? 40, height: height ?? 40,
padding: padding, padding: padding,
constraints: BoxConstraints(minWidth: minWidth ?? 0),
child: ElevatedButton( child: ElevatedButton(
focusNode: focusNode,
onPressed: () => onTap?.call(), onPressed: () => onTap?.call(),
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>( backgroundColor: MaterialStateProperty.resolveWith<Color>(
@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
class LabeledCheckbox extends StatelessWidget {
const LabeledCheckbox({
required this.label,
this.contentPadding,
this.value,
this.onChanged,
this.activeColor,
this.fontSize = 16,
this.gap = 4.0,
this.bold = false,
this.focusNode,
});
final String label;
final EdgeInsets? contentPadding;
final bool? value;
final Function(bool?)? onChanged;
final Color? activeColor;
final double fontSize;
final double gap;
final bool bold;
final FocusNode? focusNode;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () => onChanged?.call(!(value ?? false)),
child: Padding(
padding: contentPadding ?? const EdgeInsets.all(0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Checkbox(
value: value,
activeColor: activeColor,
visualDensity: VisualDensity.compact,
focusNode: focusNode,
onChanged: onChanged,
),
SizedBox(
width: gap,
),
Flexible(
child: Text(
label,
style: TextStyle(
fontSize: fontSize,
fontWeight: bold ? FontWeight.bold : FontWeight.normal,
color: Colors.black
),
),
),
],
),
),
);
}
}
@@ -22,71 +22,68 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return Column(
color: Colors.white, children: [
child: Column( _buildSuggestionFilterField(
children: [ listTagSelected: controller.searchEmailFilter.from,
_buildSuggestionFilterField( context: context,
listTagSelected: controller.searchEmailFilter.from, advancedSearchFilterField: AdvancedSearchFilterField.form,
listTagInitial: controller.searchEmailFilter.from,
currentFocusNode: controller.focusManager.fromFieldFocusNode,
nextFocusNode: controller.focusManager.toFieldFocusNode
),
_buildSuggestionFilterField(
listTagSelected: controller.searchEmailFilter.to,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.to,
listTagInitial: controller.searchEmailFilter.to,
currentFocusNode: controller.focusManager.toFieldFocusNode,
nextFocusNode: controller.focusManager.subjectFieldFocusNode
),
_buildFilterField(
textEditingController: controller.subjectFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.subject,
currentFocusNode: controller.focusManager.subjectFieldFocusNode,
nextFocusNode: controller.focusManager.hasKeywordFieldFocusNode
),
_buildFilterField(
textEditingController: controller.hasKeyWordFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.hasKeyword,
currentFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
nextFocusNode: controller.focusManager.notKeywordFieldFocusNode
),
_buildFilterField(
textEditingController: controller.notKeyWordFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.notKeyword,
currentFocusNode: controller.focusManager.notKeywordFieldFocusNode,
nextFocusNode: controller.focusManager.mailboxFieldFocusNode,
),
_buildFilterField(
textEditingController: controller.mailBoxFilterInputController,
context: context, context: context,
advancedSearchFilterField: AdvancedSearchFilterField.form, advancedSearchFilterField: AdvancedSearchFilterField.mailBox,
listTagInitial: controller.searchEmailFilter.from,
currentFocusNode: controller.focusManager.fromFieldFocusNode,
nextFocusNode: controller.focusManager.toFieldFocusNode
),
_buildSuggestionFilterField(
listTagSelected: controller.searchEmailFilter.to,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.to,
listTagInitial: controller.searchEmailFilter.to,
currentFocusNode: controller.focusManager.toFieldFocusNode,
nextFocusNode: controller.focusManager.subjectFieldFocusNode
),
_buildFilterField(
textEditingController: controller.subjectFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.subject,
currentFocusNode: controller.focusManager.subjectFieldFocusNode,
nextFocusNode: controller.focusManager.hasKeywordFieldFocusNode
),
_buildFilterField(
textEditingController: controller.hasKeyWordFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.hasKeyword,
currentFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
nextFocusNode: controller.focusManager.notKeywordFieldFocusNode
),
_buildFilterField(
textEditingController: controller.notKeyWordFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.notKeyword,
currentFocusNode: controller.focusManager.notKeywordFieldFocusNode,
nextFocusNode: controller.focusManager.mailboxFieldFocusNode,
),
_buildFilterField(
textEditingController: controller.mailBoxFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.mailBox,
isSelectFormList: true,
currentFocusNode: controller.focusManager.mailboxFieldFocusNode,
nextFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
mouseCursor: SystemMouseCursors.click,
onTap: () => controller.selectedMailBox()),
_buildFilterField(
textEditingController: controller.dateFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.date,
isSelectFormList: true, isSelectFormList: true,
onTap: () { currentFocusNode: controller.focusManager.mailboxFieldFocusNode,
openContextMenuAction( nextFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
context, mouseCursor: SystemMouseCursors.click,
_buildEmailReceiveTimeTypeActionTiles(context), onTap: () => controller.selectedMailBox()),
); _buildFilterField(
}, textEditingController: controller.dateFilterInputController,
), context: context,
AdvancedSearchFilterFormBottomView(focusManager: controller.focusManager) advancedSearchFilterField: AdvancedSearchFilterField.date,
], isSelectFormList: true,
), onTap: () {
openContextMenuAction(
context,
_buildEmailReceiveTimeTypeActionTiles(context),
);
},
),
AdvancedSearchFilterFormBottomView(focusManager: controller.focusManager)
],
); );
} }
@@ -347,10 +344,8 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
return RawKeyboardListener( return RawKeyboardListener(
focusNode: currentFocusNode ?? FocusNode(), focusNode: currentFocusNode ?? FocusNode(),
onKey: (event) { onKey: (event) {
log('AdvancedSearchInputForm::_buildTextField(): Event runtimeType is ${event.runtimeType}');
if (event is RawKeyDownEvent && if (event is RawKeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.tab) { event.logicalKey == LogicalKeyboardKey.tab) {
log('AdvancedSearchInputForm::_buildTextField(): PRESS TAB');
nextFocusNode?.requestFocus(); nextFocusNode?.requestFocus();
} }
}, },
@@ -382,9 +377,11 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
), ),
), ),
hintText: advancedSearchFilterField.getHintText(context), hintText: advancedSearchFilterField.getHintText(context),
hintStyle: const TextStyle( hintStyle: TextStyle(
fontSize: 14, fontSize: 16,
color: AppColor.colorHintSearchBar, color: advancedSearchFilterField == AdvancedSearchFilterField.mailBox
? Colors.black
: AppColor.colorHintSearchBar,
), ),
suffixIconConstraints: const BoxConstraints(minHeight: 24, minWidth: 24), suffixIconConstraints: const BoxConstraints(minHeight: 24, minWidth: 24),
suffixIcon: isSelectFormList suffixIcon: isSelectFormList
@@ -65,8 +65,8 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
controller.cleanSearchFilter(context); controller.cleanSearchFilter(context);
popBack(); popBack();
}, },
colorButton: AppColor.primaryColor.withOpacity(0.06), colorButton: Colors.white,
colorText: AppColor.primaryColor, colorText: AppColor.colorContentEmail,
text: AppLocalizations.of(context).clearFilter, text: AppLocalizations.of(context).clearFilter,
context: context, context: context,
responsiveUtils: responsiveUtils, responsiveUtils: responsiveUtils,
@@ -96,11 +96,12 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
controller.cleanSearchFilter(context); controller.cleanSearchFilter(context);
popBack(); popBack();
}, },
colorButton: AppColor.primaryColor.withOpacity(0.06), colorButton: Colors.white,
colorText: AppColor.primaryColor, colorText: AppColor.colorContentEmail,
text: AppLocalizations.of(context).clearFilter, text: AppLocalizations.of(context).clearFilter,
context: context, context: context,
responsiveUtils: responsiveUtils, responsiveUtils: responsiveUtils,
minWidth: 92
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
_buildButton( _buildButton(
@@ -113,6 +114,7 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
text: AppLocalizations.of(context).search, text: AppLocalizations.of(context).search,
context: context, context: context,
responsiveUtils: responsiveUtils, responsiveUtils: responsiveUtils,
minWidth: 144,
currentFocusNode: focusManager?.searchButtonFocusNode, currentFocusNode: focusManager?.searchButtonFocusNode,
nextFocusNode: focusManager?.fromFieldFocusNode nextFocusNode: focusManager?.fromFieldFocusNode
), ),
@@ -128,28 +130,21 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
} }
) { ) {
return Obx( return Obx(
() => SizedBox( () => RawKeyboardListener(
width: 220, focusNode: FocusNode(),
child: RawKeyboardListener( onKey: (event) {
focusNode: FocusNode(), if (event is RawKeyDownEvent &&
onKey: (event) { event.logicalKey == LogicalKeyboardKey.tab) {
log('AdvancedSearchFilterFormBottomView::_buildCheckboxHasAttachment(): Event runtimeType is ${event.runtimeType}'); nextFocusNode?.requestFocus();
if (event is RawKeyDownEvent && }
event.logicalKey == LogicalKeyboardKey.tab) { },
log('AdvancedSearchFilterFormBottomView::_buildCheckboxHasAttachment(): PRESS TAB'); child: LabeledCheckbox(
nextFocusNode?.requestFocus(); label: AppLocalizations.of(context).hasAttachment,
} focusNode: currentFocusNode,
}, contentPadding: EdgeInsets.zero,
child: CheckboxListTile( value: controller.hasAttachment.value,
focusNode: currentFocusNode, activeColor: AppColor.primaryColor,
contentPadding: EdgeInsets.zero, onChanged: (value) => controller.hasAttachment.value = value ?? false,
controlAffinity: ListTileControlAffinity.leading,
value: controller.hasAttachment.value,
onChanged: (value) {
controller.hasAttachment.value = value ?? false;
},
title: Text(AppLocalizations.of(context).hasAttachment),
),
), ),
), ),
); );
@@ -164,31 +159,27 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
required ResponsiveUtils responsiveUtils, required ResponsiveUtils responsiveUtils,
FocusNode? currentFocusNode, FocusNode? currentFocusNode,
FocusNode? nextFocusNode, FocusNode? nextFocusNode,
double? minWidth,
}) { }) {
return RawKeyboardListener( return RawKeyboardListener(
focusNode: FocusNode(), focusNode: FocusNode(),
onKey: (event) { onKey: (event) {
log('AdvancedSearchFilterFormBottomView::_buildButton(): Event runtimeType is ${event.runtimeType}');
if (event is RawKeyDownEvent && if (event is RawKeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.tab) { event.logicalKey == LogicalKeyboardKey.tab) {
log('AdvancedSearchFilterFormBottomView::_buildButton(): PRESS TAB');
nextFocusNode?.requestFocus(); nextFocusNode?.requestFocus();
} }
}, },
child: buildTextButton( child: buildButtonWrapText(
text, text,
focusNode: currentFocusNode, focusNode: currentFocusNode,
width: _isMobileAndLandscapeTablet(context, responsiveUtils)
? double.infinity
: 144,
height: 44,
radius: 10, radius: 10,
textStyle: TextStyle(fontSize: 17, color: colorText), height: 44,
backgroundColor: colorButton, minWidth: minWidth,
padding: EdgeInsets.symmetric( textStyle: TextStyle(
horizontal: _isMobileAndLandscapeTablet(context, responsiveUtils) fontSize: 17,
? 0 color: colorText,
: 26), fontWeight: FontWeight.w500),
bgColor: colorButton,
onTap: onAction), onTap: onAction),
); );
} }
@@ -1,6 +1,5 @@
import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/utils/app_logger.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart';
@@ -21,36 +20,28 @@ class AdvancedSearchFilterOverlay extends StatelessWidget {
return GestureDetector( return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(), onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 16), padding: const EdgeInsets.only(top: 4, bottom: 16),
child: Container( child: Container(
constraints: BoxConstraints( constraints: BoxConstraints(
minWidth: maxWidth ?? 660,
maxHeight: _getHeightOverlay(context, responsiveUtils), maxHeight: _getHeightOverlay(context, responsiveUtils),
), ),
width: maxWidth ?? 660, width: maxWidth ?? 660,
height: _getHeightOverlay(context, responsiveUtils), padding: const EdgeInsets.all(32),
padding: responsiveUtils.landscapeTabletSupported(context)
? EdgeInsets.zero
: const EdgeInsets.all(24),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: const [ boxShadow: const [
BoxShadow( BoxShadow(
color: AppColor.colorShadowBgContentEmail, color: AppColor.colorShadowComposer,
spreadRadius: 1, blurRadius: 32,
blurRadius: 1, offset: Offset.zero),
offset: Offset(0, 0.5)), BoxShadow(
color: AppColor.colorDropShadow,
blurRadius: 4,
offset: Offset.zero),
]), ]),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: AdvancedSearchInputForm(),
padding: EdgeInsets.symmetric(
horizontal: responsiveUtils.landscapeTabletSupported(context)
? 16 : 28,
vertical: responsiveUtils.landscapeTabletSupported(context)
? 16 : 12),
child: AdvancedSearchInputForm(),
),
), ),
), ),
), ),
@@ -58,18 +49,10 @@ class AdvancedSearchFilterOverlay extends StatelessWidget {
} }
double _getHeightOverlay(BuildContext context, ResponsiveUtils responsiveUtils) { double _getHeightOverlay(BuildContext context, ResponsiveUtils responsiveUtils) {
const double maxHeightTopBar = 160; const double maxHeightTopBar = 80;
const double maxHeightOverlay = 568; const double paddingBottom = 16;
final currentHeight = responsiveUtils.getSizeScreenHeight(context); final currentHeight = responsiveUtils.getSizeScreenHeight(context);
double maxHeightForm = maxHeightOverlay; double maxHeightForm = currentHeight - maxHeightTopBar - paddingBottom;
if (currentHeight < maxHeightOverlay) {
maxHeightForm = currentHeight > maxHeightTopBar
? currentHeight - maxHeightTopBar
: currentHeight;
}
log('AdvancedSearchFilterOverlay::_getHeightOverlay(): maxHeightForm: $maxHeightForm');
return maxHeightForm; return maxHeightForm;
} }
} }