TF-4066 Add Unread, Starred checkbox in advanced search form view

This commit is contained in:
dab246
2025-09-26 18:52:27 +07:00
committed by Dat H. Pham
parent d05904229b
commit 58dc75f8c8
5 changed files with 105 additions and 10 deletions
@@ -30,7 +30,7 @@ class LabeledCheckbox extends StatelessWidget {
children: <Widget>[
buildCheckboxWidget,
buildGapWidget,
buildLabelWidget,
Flexible(child: buildLabelWidget),
],
),
);
@@ -53,5 +53,7 @@ class LabeledCheckbox extends StatelessWidget {
Widget get buildLabelWidget => Text(
label,
style: textStyle ?? ThemeUtils.textStyleM3BodyMedium3,
maxLines: 1,
overflow: TextOverflow.ellipsis,
);
}
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/core/utc_date.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:model/model.dart';
import 'package:super_tag_editor/tag_editor.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
@@ -33,6 +34,8 @@ class AdvancedFilterController extends BaseController {
final receiveTimeType = EmailReceiveTimeType.allTime.obs;
final hasAttachment = false.obs;
final isStarred = false.obs;
final isUnread = false.obs;
final startDate = Rxn<DateTime>();
final endDate = Rxn<DateTime>();
final sortOrderType = SearchEmailFilter.defaultSortOrder.obs;
@@ -115,6 +118,7 @@ class AdvancedFilterController extends BaseController {
Option<Set<String>>? toOption,
Option<SearchQuery>? textOption,
Option<String>? subjectOption,
Option<Set<String>>? hasKeywordOption,
Option<Set<String>>? notKeywordOption,
Option<PresentationMailbox>? mailboxOption,
Option<EmailReceiveTimeType>? emailReceiveTimeTypeOption,
@@ -131,6 +135,7 @@ class AdvancedFilterController extends BaseController {
toOption: toOption,
textOption: textOption,
subjectOption: subjectOption,
hasKeywordOption: hasKeywordOption,
notKeywordOption: notKeywordOption,
mailboxOption: mailboxOption,
emailReceiveTimeTypeOption: emailReceiveTimeTypeOption,
@@ -176,6 +181,13 @@ class AdvancedFilterController extends BaseController {
final endDateOption = optionOf(endDate.value?.toUTCDate());
final unreadOption = Some(isUnread.value);
final hasKeywordOption = option(
isStarred.isTrue,
{KeyWordIdentifier.emailFlagged.value},
);
_updateMemorySearchFilter(
textOption: textOption,
notKeywordOption: notKeywordsOption,
@@ -186,6 +198,8 @@ class AdvancedFilterController extends BaseController {
subjectOption: subjectOption,
emailReceiveTimeTypeOption: emailReceiveTimeTypeOption,
hasAttachmentOption: hasAttachmentOption,
unreadOption: unreadOption,
hasKeywordOption: hasKeywordOption,
startDateOption: startDateOption,
endDateOption: endDateOption
);
@@ -269,6 +283,11 @@ class AdvancedFilterController extends BaseController {
hasAttachment.value = _memorySearchFilter.hasAttachment;
isUnread.value = _memorySearchFilter.unread;
isStarred.value = _memorySearchFilter.hasKeyword
.contains(KeyWordIdentifier.emailFlagged.value);
if (_memorySearchFilter.from.isEmpty) {
listFromEmailAddress.clear();
} else {
@@ -455,6 +474,8 @@ class AdvancedFilterController extends BaseController {
endDate.value = null;
receiveTimeType.value = EmailReceiveTimeType.allTime;
hasAttachment.value = false;
isUnread.value = false;
isStarred.value = false;
selectedFolderName.value = null;
listFromEmailAddress.clear();
listToEmailAddress.clear();
@@ -534,6 +555,26 @@ class AdvancedFilterController extends BaseController {
_updateMemorySearchFilter(hasAttachmentOption: Some(hasAttachment.value));
}
void onStarredCheckboxChanged(bool? isChecked) {
isStarred.value = isChecked ?? false;
final listHasKeywordFiltered = _memorySearchFilter.hasKeyword;
if (isStarred.isTrue) {
listHasKeywordFiltered.add(KeyWordIdentifier.emailFlagged.value);
} else {
listHasKeywordFiltered.remove(KeyWordIdentifier.emailFlagged.value);
}
_updateMemorySearchFilter(
hasKeywordOption: Some(listHasKeywordFiltered),
);
}
void onUnreadCheckboxChanged(bool? isChecked) {
isUnread.value = isChecked ?? false;
_updateMemorySearchFilter(
unreadOption: isStarred.isTrue ? const Some(true) : const None(),
);
}
void onTextChanged(FilterField filterField, String value) {
switch (filterField) {
case FilterField.subject:
@@ -10,6 +10,8 @@ class InputFieldFocusManager {
late FocusNode notKeywordFieldFocusNode;
late FocusNode mailboxFieldFocusNode;
late FocusNode attachmentCheckboxFocusNode;
late FocusNode starredCheckboxFocusNode;
late FocusNode unreadCheckboxFocusNode;
InputFieldFocusManager() {
fromFieldFocusNode = FocusNode();
@@ -19,6 +21,8 @@ class InputFieldFocusManager {
notKeywordFieldFocusNode = FocusNode();
mailboxFieldFocusNode = FocusNode();
attachmentCheckboxFocusNode = FocusNode();
starredCheckboxFocusNode = FocusNode();
unreadCheckboxFocusNode = FocusNode();
}
factory InputFieldFocusManager.initial() {
@@ -33,5 +37,7 @@ class InputFieldFocusManager {
notKeywordFieldFocusNode.dispose();
mailboxFieldFocusNode.dispose();
attachmentCheckboxFocusNode.dispose();
starredCheckboxFocusNode.dispose();
unreadCheckboxFocusNode.dispose();
}
}
@@ -6,9 +6,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller
extension SelectSearchFilterActionExtension on MailboxDashBoardController {
void selectStarredSearchFilter() {
final listHasKeywordFiltered = searchController.listHasKeywordFiltered;
if (!listHasKeywordFiltered.contains(KeyWordIdentifier.emailFlagged.value)) {
listHasKeywordFiltered.add(KeyWordIdentifier.emailFlagged.value);
}
listHasKeywordFiltered.add(KeyWordIdentifier.emailFlagged.value);
searchController.updateFilterEmail(
hasKeywordOption: Some(listHasKeywordFiltered),
);
@@ -22,9 +20,7 @@ extension SelectSearchFilterActionExtension on MailboxDashBoardController {
void deleteStarredSearchFilter() {
final listHasKeywordFiltered = searchController.listHasKeywordFiltered;
if (listHasKeywordFiltered.contains(KeyWordIdentifier.emailFlagged.value)) {
listHasKeywordFiltered.remove(KeyWordIdentifier.emailFlagged.value);
}
listHasKeywordFiltered.remove(KeyWordIdentifier.emailFlagged.value);
searchController.updateFilterEmail(
hasKeywordOption: Some(listHasKeywordFiltered),
);
@@ -23,10 +23,25 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildCheckboxHasAttachment(
context,
focusManager.attachmentCheckboxFocusNode,
Wrap(
runSpacing: 12,
spacing: 24,
children: [
_buildCheckboxHasAttachment(
context,
focusManager.attachmentCheckboxFocusNode,
),
_buildCheckboxUnread(
context,
focusManager.unreadCheckboxFocusNode,
),
_buildCheckboxStarred(
context,
focusManager.starredCheckboxFocusNode,
),
],
),
const SizedBox(height: 25),
_buildListButton(context),
],
);
@@ -82,12 +97,47 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
svgIconPath: controller.imagePaths.icCheckboxUnselected,
selectedSvgIconPath: controller.imagePaths.icCheckboxSelected,
focusNode: currentFocusNode,
gap: 8.0,
value: controller.hasAttachment.value,
onChanged: controller.onHasAttachmentCheckboxChanged,
),
);
}
Widget _buildCheckboxStarred(
BuildContext context,
FocusNode currentFocusNode,
) {
return Obx(
() => CustomIconLabeledCheckbox(
label: AppLocalizations.of(context).starred,
svgIconPath: controller.imagePaths.icCheckboxUnselected,
selectedSvgIconPath: controller.imagePaths.icCheckboxSelected,
focusNode: currentFocusNode,
gap: 8.0,
value: controller.isStarred.value,
onChanged: controller.onStarredCheckboxChanged,
),
);
}
Widget _buildCheckboxUnread(
BuildContext context,
FocusNode currentFocusNode,
) {
return Obx(
() => CustomIconLabeledCheckbox(
label: AppLocalizations.of(context).unread,
svgIconPath: controller.imagePaths.icCheckboxUnselected,
selectedSvgIconPath: controller.imagePaths.icCheckboxSelected,
focusNode: currentFocusNode,
gap: 8.0,
value: controller.isUnread.value,
onChanged: controller.onUnreadCheckboxChanged,
),
);
}
void _onClickCancelButton() {
controller.clearSearchFilter();
popBack();