TF-4066 Add Unread, Starred checkbox in advanced search form view
This commit is contained in:
@@ -30,7 +30,7 @@ class LabeledCheckbox extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
buildCheckboxWidget,
|
buildCheckboxWidget,
|
||||||
buildGapWidget,
|
buildGapWidget,
|
||||||
buildLabelWidget,
|
Flexible(child: buildLabelWidget),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -53,5 +53,7 @@ class LabeledCheckbox extends StatelessWidget {
|
|||||||
Widget get buildLabelWidget => Text(
|
Widget get buildLabelWidget => Text(
|
||||||
label,
|
label,
|
||||||
style: textStyle ?? ThemeUtils.textStyleM3BodyMedium3,
|
style: textStyle ?? ThemeUtils.textStyleM3BodyMedium3,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+41
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/utc_date.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/email_address.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
import 'package:super_tag_editor/tag_editor.dart';
|
import 'package:super_tag_editor/tag_editor.dart';
|
||||||
import 'package:tmail_ui_user/features/base/base_controller.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 receiveTimeType = EmailReceiveTimeType.allTime.obs;
|
||||||
final hasAttachment = false.obs;
|
final hasAttachment = false.obs;
|
||||||
|
final isStarred = false.obs;
|
||||||
|
final isUnread = false.obs;
|
||||||
final startDate = Rxn<DateTime>();
|
final startDate = Rxn<DateTime>();
|
||||||
final endDate = Rxn<DateTime>();
|
final endDate = Rxn<DateTime>();
|
||||||
final sortOrderType = SearchEmailFilter.defaultSortOrder.obs;
|
final sortOrderType = SearchEmailFilter.defaultSortOrder.obs;
|
||||||
@@ -115,6 +118,7 @@ class AdvancedFilterController extends BaseController {
|
|||||||
Option<Set<String>>? toOption,
|
Option<Set<String>>? toOption,
|
||||||
Option<SearchQuery>? textOption,
|
Option<SearchQuery>? textOption,
|
||||||
Option<String>? subjectOption,
|
Option<String>? subjectOption,
|
||||||
|
Option<Set<String>>? hasKeywordOption,
|
||||||
Option<Set<String>>? notKeywordOption,
|
Option<Set<String>>? notKeywordOption,
|
||||||
Option<PresentationMailbox>? mailboxOption,
|
Option<PresentationMailbox>? mailboxOption,
|
||||||
Option<EmailReceiveTimeType>? emailReceiveTimeTypeOption,
|
Option<EmailReceiveTimeType>? emailReceiveTimeTypeOption,
|
||||||
@@ -131,6 +135,7 @@ class AdvancedFilterController extends BaseController {
|
|||||||
toOption: toOption,
|
toOption: toOption,
|
||||||
textOption: textOption,
|
textOption: textOption,
|
||||||
subjectOption: subjectOption,
|
subjectOption: subjectOption,
|
||||||
|
hasKeywordOption: hasKeywordOption,
|
||||||
notKeywordOption: notKeywordOption,
|
notKeywordOption: notKeywordOption,
|
||||||
mailboxOption: mailboxOption,
|
mailboxOption: mailboxOption,
|
||||||
emailReceiveTimeTypeOption: emailReceiveTimeTypeOption,
|
emailReceiveTimeTypeOption: emailReceiveTimeTypeOption,
|
||||||
@@ -176,6 +181,13 @@ class AdvancedFilterController extends BaseController {
|
|||||||
|
|
||||||
final endDateOption = optionOf(endDate.value?.toUTCDate());
|
final endDateOption = optionOf(endDate.value?.toUTCDate());
|
||||||
|
|
||||||
|
final unreadOption = Some(isUnread.value);
|
||||||
|
|
||||||
|
final hasKeywordOption = option(
|
||||||
|
isStarred.isTrue,
|
||||||
|
{KeyWordIdentifier.emailFlagged.value},
|
||||||
|
);
|
||||||
|
|
||||||
_updateMemorySearchFilter(
|
_updateMemorySearchFilter(
|
||||||
textOption: textOption,
|
textOption: textOption,
|
||||||
notKeywordOption: notKeywordsOption,
|
notKeywordOption: notKeywordsOption,
|
||||||
@@ -186,6 +198,8 @@ class AdvancedFilterController extends BaseController {
|
|||||||
subjectOption: subjectOption,
|
subjectOption: subjectOption,
|
||||||
emailReceiveTimeTypeOption: emailReceiveTimeTypeOption,
|
emailReceiveTimeTypeOption: emailReceiveTimeTypeOption,
|
||||||
hasAttachmentOption: hasAttachmentOption,
|
hasAttachmentOption: hasAttachmentOption,
|
||||||
|
unreadOption: unreadOption,
|
||||||
|
hasKeywordOption: hasKeywordOption,
|
||||||
startDateOption: startDateOption,
|
startDateOption: startDateOption,
|
||||||
endDateOption: endDateOption
|
endDateOption: endDateOption
|
||||||
);
|
);
|
||||||
@@ -269,6 +283,11 @@ class AdvancedFilterController extends BaseController {
|
|||||||
|
|
||||||
hasAttachment.value = _memorySearchFilter.hasAttachment;
|
hasAttachment.value = _memorySearchFilter.hasAttachment;
|
||||||
|
|
||||||
|
isUnread.value = _memorySearchFilter.unread;
|
||||||
|
|
||||||
|
isStarred.value = _memorySearchFilter.hasKeyword
|
||||||
|
.contains(KeyWordIdentifier.emailFlagged.value);
|
||||||
|
|
||||||
if (_memorySearchFilter.from.isEmpty) {
|
if (_memorySearchFilter.from.isEmpty) {
|
||||||
listFromEmailAddress.clear();
|
listFromEmailAddress.clear();
|
||||||
} else {
|
} else {
|
||||||
@@ -455,6 +474,8 @@ class AdvancedFilterController extends BaseController {
|
|||||||
endDate.value = null;
|
endDate.value = null;
|
||||||
receiveTimeType.value = EmailReceiveTimeType.allTime;
|
receiveTimeType.value = EmailReceiveTimeType.allTime;
|
||||||
hasAttachment.value = false;
|
hasAttachment.value = false;
|
||||||
|
isUnread.value = false;
|
||||||
|
isStarred.value = false;
|
||||||
selectedFolderName.value = null;
|
selectedFolderName.value = null;
|
||||||
listFromEmailAddress.clear();
|
listFromEmailAddress.clear();
|
||||||
listToEmailAddress.clear();
|
listToEmailAddress.clear();
|
||||||
@@ -534,6 +555,26 @@ class AdvancedFilterController extends BaseController {
|
|||||||
_updateMemorySearchFilter(hasAttachmentOption: Some(hasAttachment.value));
|
_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) {
|
void onTextChanged(FilterField filterField, String value) {
|
||||||
switch (filterField) {
|
switch (filterField) {
|
||||||
case FilterField.subject:
|
case FilterField.subject:
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ class InputFieldFocusManager {
|
|||||||
late FocusNode notKeywordFieldFocusNode;
|
late FocusNode notKeywordFieldFocusNode;
|
||||||
late FocusNode mailboxFieldFocusNode;
|
late FocusNode mailboxFieldFocusNode;
|
||||||
late FocusNode attachmentCheckboxFocusNode;
|
late FocusNode attachmentCheckboxFocusNode;
|
||||||
|
late FocusNode starredCheckboxFocusNode;
|
||||||
|
late FocusNode unreadCheckboxFocusNode;
|
||||||
|
|
||||||
InputFieldFocusManager() {
|
InputFieldFocusManager() {
|
||||||
fromFieldFocusNode = FocusNode();
|
fromFieldFocusNode = FocusNode();
|
||||||
@@ -19,6 +21,8 @@ class InputFieldFocusManager {
|
|||||||
notKeywordFieldFocusNode = FocusNode();
|
notKeywordFieldFocusNode = FocusNode();
|
||||||
mailboxFieldFocusNode = FocusNode();
|
mailboxFieldFocusNode = FocusNode();
|
||||||
attachmentCheckboxFocusNode = FocusNode();
|
attachmentCheckboxFocusNode = FocusNode();
|
||||||
|
starredCheckboxFocusNode = FocusNode();
|
||||||
|
unreadCheckboxFocusNode = FocusNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
factory InputFieldFocusManager.initial() {
|
factory InputFieldFocusManager.initial() {
|
||||||
@@ -33,5 +37,7 @@ class InputFieldFocusManager {
|
|||||||
notKeywordFieldFocusNode.dispose();
|
notKeywordFieldFocusNode.dispose();
|
||||||
mailboxFieldFocusNode.dispose();
|
mailboxFieldFocusNode.dispose();
|
||||||
attachmentCheckboxFocusNode.dispose();
|
attachmentCheckboxFocusNode.dispose();
|
||||||
|
starredCheckboxFocusNode.dispose();
|
||||||
|
unreadCheckboxFocusNode.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-6
@@ -6,9 +6,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller
|
|||||||
extension SelectSearchFilterActionExtension on MailboxDashBoardController {
|
extension SelectSearchFilterActionExtension on MailboxDashBoardController {
|
||||||
void selectStarredSearchFilter() {
|
void selectStarredSearchFilter() {
|
||||||
final listHasKeywordFiltered = searchController.listHasKeywordFiltered;
|
final listHasKeywordFiltered = searchController.listHasKeywordFiltered;
|
||||||
if (!listHasKeywordFiltered.contains(KeyWordIdentifier.emailFlagged.value)) {
|
listHasKeywordFiltered.add(KeyWordIdentifier.emailFlagged.value);
|
||||||
listHasKeywordFiltered.add(KeyWordIdentifier.emailFlagged.value);
|
|
||||||
}
|
|
||||||
searchController.updateFilterEmail(
|
searchController.updateFilterEmail(
|
||||||
hasKeywordOption: Some(listHasKeywordFiltered),
|
hasKeywordOption: Some(listHasKeywordFiltered),
|
||||||
);
|
);
|
||||||
@@ -22,9 +20,7 @@ extension SelectSearchFilterActionExtension on MailboxDashBoardController {
|
|||||||
|
|
||||||
void deleteStarredSearchFilter() {
|
void deleteStarredSearchFilter() {
|
||||||
final listHasKeywordFiltered = searchController.listHasKeywordFiltered;
|
final listHasKeywordFiltered = searchController.listHasKeywordFiltered;
|
||||||
if (listHasKeywordFiltered.contains(KeyWordIdentifier.emailFlagged.value)) {
|
listHasKeywordFiltered.remove(KeyWordIdentifier.emailFlagged.value);
|
||||||
listHasKeywordFiltered.remove(KeyWordIdentifier.emailFlagged.value);
|
|
||||||
}
|
|
||||||
searchController.updateFilterEmail(
|
searchController.updateFilterEmail(
|
||||||
hasKeywordOption: Some(listHasKeywordFiltered),
|
hasKeywordOption: Some(listHasKeywordFiltered),
|
||||||
);
|
);
|
||||||
|
|||||||
+53
-3
@@ -23,10 +23,25 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildCheckboxHasAttachment(
|
Wrap(
|
||||||
context,
|
runSpacing: 12,
|
||||||
focusManager.attachmentCheckboxFocusNode,
|
spacing: 24,
|
||||||
|
children: [
|
||||||
|
_buildCheckboxHasAttachment(
|
||||||
|
context,
|
||||||
|
focusManager.attachmentCheckboxFocusNode,
|
||||||
|
),
|
||||||
|
_buildCheckboxUnread(
|
||||||
|
context,
|
||||||
|
focusManager.unreadCheckboxFocusNode,
|
||||||
|
),
|
||||||
|
_buildCheckboxStarred(
|
||||||
|
context,
|
||||||
|
focusManager.starredCheckboxFocusNode,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 25),
|
||||||
_buildListButton(context),
|
_buildListButton(context),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -82,12 +97,47 @@ class AdvancedSearchFilterFormBottomView extends GetWidget<AdvancedFilterControl
|
|||||||
svgIconPath: controller.imagePaths.icCheckboxUnselected,
|
svgIconPath: controller.imagePaths.icCheckboxUnselected,
|
||||||
selectedSvgIconPath: controller.imagePaths.icCheckboxSelected,
|
selectedSvgIconPath: controller.imagePaths.icCheckboxSelected,
|
||||||
focusNode: currentFocusNode,
|
focusNode: currentFocusNode,
|
||||||
|
gap: 8.0,
|
||||||
value: controller.hasAttachment.value,
|
value: controller.hasAttachment.value,
|
||||||
onChanged: controller.onHasAttachmentCheckboxChanged,
|
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() {
|
void _onClickCancelButton() {
|
||||||
controller.clearSearchFilter();
|
controller.clearSearchFilter();
|
||||||
popBack();
|
popBack();
|
||||||
|
|||||||
Reference in New Issue
Block a user