mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2026-01-31 10:25:03 -06:00
WIP - Refactoring date range picker dialog
This commit is contained in:
@@ -162,7 +162,7 @@ class _DocumentUploadPreparationPageState
|
||||
S.of(context).documentCreatedPropertyLabel + " *",
|
||||
),
|
||||
),
|
||||
LabelFormField<DocumentType, DocumentTypeQuery>(
|
||||
LabelFormField<DocumentType>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialName) =>
|
||||
@@ -172,15 +172,13 @@ class _DocumentUploadPreparationPageState
|
||||
),
|
||||
child: AddDocumentTypePage(initialName: initialName),
|
||||
),
|
||||
label: S.of(context).documentDocumentTypePropertyLabel + " *",
|
||||
textFieldLabel:
|
||||
S.of(context).documentDocumentTypePropertyLabel + " *",
|
||||
name: DocumentModel.documentTypeKey,
|
||||
state: state.documentTypes,
|
||||
queryParameterIdBuilder: DocumentTypeQuery.fromId,
|
||||
queryParameterNotAssignedBuilder:
|
||||
DocumentTypeQuery.notAssigned,
|
||||
labelOptions: state.documentTypes,
|
||||
prefixIcon: const Icon(Icons.description_outlined),
|
||||
),
|
||||
LabelFormField<Correspondent, CorrespondentQuery>(
|
||||
LabelFormField<Correspondent>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialName) =>
|
||||
@@ -191,13 +189,10 @@ class _DocumentUploadPreparationPageState
|
||||
),
|
||||
child: AddCorrespondentPage(initialName: initialName),
|
||||
),
|
||||
label:
|
||||
textFieldLabel:
|
||||
S.of(context).documentCorrespondentPropertyLabel + " *",
|
||||
name: DocumentModel.correspondentKey,
|
||||
state: state.correspondents,
|
||||
queryParameterIdBuilder: CorrespondentQuery.fromId,
|
||||
queryParameterNotAssignedBuilder:
|
||||
CorrespondentQuery.notAssigned,
|
||||
labelOptions: state.correspondents,
|
||||
prefixIcon: const Icon(Icons.person_outline),
|
||||
),
|
||||
TagFormField(
|
||||
|
||||
@@ -96,26 +96,24 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
|
||||
Widget _buildStoragePathFormField(
|
||||
int? initialId, Map<int, StoragePath> options) {
|
||||
return LabelFormField<StoragePath, StoragePathQuery>(
|
||||
return LabelFormField<StoragePath>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialValue) => RepositoryProvider.value(
|
||||
value: RepositoryProvider.of<LabelRepository<StoragePath>>(context),
|
||||
child: AddStoragePathPage(initalValue: initialValue),
|
||||
),
|
||||
label: S.of(context).documentStoragePathPropertyLabel,
|
||||
state: options,
|
||||
initialValue: StoragePathQuery.fromId(initialId),
|
||||
textFieldLabel: S.of(context).documentStoragePathPropertyLabel,
|
||||
labelOptions: options,
|
||||
initialValue: IdQueryParameter.fromId(initialId),
|
||||
name: fkStoragePath,
|
||||
queryParameterIdBuilder: StoragePathQuery.fromId,
|
||||
queryParameterNotAssignedBuilder: StoragePathQuery.notAssigned,
|
||||
prefixIcon: const Icon(Icons.folder_outlined),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCorrespondentFormField(
|
||||
int? initialId, Map<int, Correspondent> options) {
|
||||
return LabelFormField<Correspondent, CorrespondentQuery>(
|
||||
return LabelFormField<Correspondent>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialValue) => RepositoryProvider.value(
|
||||
@@ -124,19 +122,17 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
),
|
||||
child: AddCorrespondentPage(initialName: initialValue),
|
||||
),
|
||||
label: S.of(context).documentCorrespondentPropertyLabel,
|
||||
state: options,
|
||||
initialValue: CorrespondentQuery.fromId(initialId),
|
||||
textFieldLabel: S.of(context).documentCorrespondentPropertyLabel,
|
||||
labelOptions: options,
|
||||
initialValue: IdQueryParameter.fromId(initialId),
|
||||
name: fkCorrespondent,
|
||||
queryParameterIdBuilder: CorrespondentQuery.fromId,
|
||||
queryParameterNotAssignedBuilder: CorrespondentQuery.notAssigned,
|
||||
prefixIcon: const Icon(Icons.person_outlined),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDocumentTypeFormField(
|
||||
int? initialId, Map<int, DocumentType> options) {
|
||||
return LabelFormField<DocumentType, DocumentTypeQuery>(
|
||||
return LabelFormField<DocumentType>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (currentInput) => RepositoryProvider.value(
|
||||
@@ -147,12 +143,10 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
initialName: currentInput,
|
||||
),
|
||||
),
|
||||
label: S.of(context).documentDocumentTypePropertyLabel,
|
||||
initialValue: DocumentTypeQuery.fromId(initialId),
|
||||
state: options,
|
||||
textFieldLabel: S.of(context).documentDocumentTypePropertyLabel,
|
||||
initialValue: IdQueryParameter.fromId(initialId),
|
||||
labelOptions: options,
|
||||
name: fkDocumentType,
|
||||
queryParameterIdBuilder: DocumentTypeQuery.fromId,
|
||||
queryParameterNotAssignedBuilder: DocumentTypeQuery.notAssigned,
|
||||
prefixIcon: const Icon(Icons.description_outlined),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
expand: false,
|
||||
snap: true,
|
||||
initialChildSize: .9,
|
||||
maxChildSize: .9,
|
||||
builder: (context, controller) => LabelsBlocProvider(
|
||||
child: DocumentFilterPanel(
|
||||
initialFilter: _documentsCubit.state.filter,
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_extended_date_range_picker.dart';
|
||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/search/query_type_form_field.dart';
|
||||
import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart';
|
||||
@@ -95,8 +96,13 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
).padded(),
|
||||
_buildCreatedDateRangePickerFormField(),
|
||||
_buildAddedDateRangePickerFormField(),
|
||||
FormBuilderExtendedDateRangePicker(
|
||||
name: DocumentModel.createdKey,
|
||||
initialValue: widget.initialFilter.created,
|
||||
labelText: S.of(context).documentCreatedPropertyLabel,
|
||||
).padded(),
|
||||
// _buildCreatedDateRangePickerFormField(),
|
||||
// _buildAddedDateRangePickerFormField(),
|
||||
_buildCorrespondentFormField().padded(),
|
||||
_buildDocumentTypeFormField().padded(),
|
||||
_buildStoragePathFormField().padded(),
|
||||
@@ -129,14 +135,12 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
Widget _buildDocumentTypeFormField() {
|
||||
return BlocBuilder<LabelCubit<DocumentType>, LabelState<DocumentType>>(
|
||||
builder: (context, state) {
|
||||
return LabelFormField<DocumentType, DocumentTypeQuery>(
|
||||
return LabelFormField<DocumentType>(
|
||||
formBuilderState: _formKey.currentState,
|
||||
name: fkDocumentType,
|
||||
state: state.labels,
|
||||
label: S.of(context).documentDocumentTypePropertyLabel,
|
||||
labelOptions: state.labels,
|
||||
textFieldLabel: S.of(context).documentDocumentTypePropertyLabel,
|
||||
initialValue: widget.initialFilter.documentType,
|
||||
queryParameterIdBuilder: DocumentTypeQuery.fromId,
|
||||
queryParameterNotAssignedBuilder: DocumentTypeQuery.notAssigned,
|
||||
prefixIcon: const Icon(Icons.description_outlined),
|
||||
);
|
||||
},
|
||||
@@ -146,14 +150,12 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
Widget _buildCorrespondentFormField() {
|
||||
return BlocBuilder<LabelCubit<Correspondent>, LabelState<Correspondent>>(
|
||||
builder: (context, state) {
|
||||
return LabelFormField<Correspondent, CorrespondentQuery>(
|
||||
return LabelFormField<Correspondent>(
|
||||
formBuilderState: _formKey.currentState,
|
||||
name: fkCorrespondent,
|
||||
state: state.labels,
|
||||
label: S.of(context).documentCorrespondentPropertyLabel,
|
||||
labelOptions: state.labels,
|
||||
textFieldLabel: S.of(context).documentCorrespondentPropertyLabel,
|
||||
initialValue: widget.initialFilter.correspondent,
|
||||
queryParameterIdBuilder: CorrespondentQuery.fromId,
|
||||
queryParameterNotAssignedBuilder: CorrespondentQuery.notAssigned,
|
||||
prefixIcon: const Icon(Icons.person_outline),
|
||||
);
|
||||
},
|
||||
@@ -163,14 +165,12 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
Widget _buildStoragePathFormField() {
|
||||
return BlocBuilder<LabelCubit<StoragePath>, LabelState<StoragePath>>(
|
||||
builder: (context, state) {
|
||||
return LabelFormField<StoragePath, StoragePathQuery>(
|
||||
return LabelFormField<StoragePath>(
|
||||
formBuilderState: _formKey.currentState,
|
||||
name: fkStoragePath,
|
||||
state: state.labels,
|
||||
label: S.of(context).documentStoragePathPropertyLabel,
|
||||
labelOptions: state.labels,
|
||||
textFieldLabel: S.of(context).documentStoragePathPropertyLabel,
|
||||
initialValue: widget.initialFilter.storagePath,
|
||||
queryParameterIdBuilder: StoragePathQuery.fromId,
|
||||
queryParameterNotAssignedBuilder: StoragePathQuery.notAssigned,
|
||||
prefixIcon: const Icon(Icons.folder_outlined),
|
||||
);
|
||||
},
|
||||
@@ -209,187 +209,99 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDateRangePickerHelper(String formFieldKey) {
|
||||
const spacer = SizedBox(width: 8.0);
|
||||
return SizedBox(
|
||||
height: 64,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: [
|
||||
spacer,
|
||||
ActionChip(
|
||||
label: Text(
|
||||
S.of(context).documentFilterDateRangeLastSevenDaysLabel,
|
||||
),
|
||||
onPressed: () {
|
||||
_formKey.currentState?.fields[formFieldKey]?.didChange(
|
||||
DateTimeRange(
|
||||
start: DateUtils.addDaysToDate(DateTime.now(), -7),
|
||||
end: DateTime.now(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
spacer,
|
||||
ActionChip(
|
||||
label: Text(
|
||||
S.of(context).documentFilterDateRangeLastMonthLabel,
|
||||
),
|
||||
onPressed: () {
|
||||
final now = DateTime.now();
|
||||
final firstDayOfLastMonth =
|
||||
DateUtils.addMonthsToMonthDate(now, -1);
|
||||
_formKey.currentState?.fields[formFieldKey]?.didChange(
|
||||
DateTimeRange(
|
||||
start: DateTime(firstDayOfLastMonth.year,
|
||||
firstDayOfLastMonth.month, now.day),
|
||||
end: DateTime.now(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
spacer,
|
||||
ActionChip(
|
||||
label: Text(
|
||||
S.of(context).documentFilterDateRangeLastThreeMonthsLabel,
|
||||
),
|
||||
onPressed: () {
|
||||
final now = DateTime.now();
|
||||
final firstDayOfLastMonth =
|
||||
DateUtils.addMonthsToMonthDate(now, -3);
|
||||
_formKey.currentState?.fields[formFieldKey]?.didChange(
|
||||
DateTimeRange(
|
||||
start: DateTime(
|
||||
firstDayOfLastMonth.year,
|
||||
firstDayOfLastMonth.month,
|
||||
now.day,
|
||||
),
|
||||
end: DateTime.now(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
spacer,
|
||||
ActionChip(
|
||||
label: Text(
|
||||
S.of(context).documentFilterDateRangeLastYearLabel,
|
||||
),
|
||||
onPressed: () {
|
||||
final now = DateTime.now();
|
||||
final firstDayOfLastMonth =
|
||||
DateUtils.addMonthsToMonthDate(now, -12);
|
||||
_formKey.currentState?.fields[formFieldKey]?.didChange(
|
||||
DateTimeRange(
|
||||
start: DateTime(
|
||||
firstDayOfLastMonth.year,
|
||||
firstDayOfLastMonth.month,
|
||||
now.day,
|
||||
),
|
||||
end: DateTime.now(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
spacer,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
// Widget _buildCreatedDateRangePickerFormField() {
|
||||
// return Column(
|
||||
// children: [
|
||||
// FormBuilderDateRangePicker(
|
||||
// initialValue: _dateTimeRangeOfNullable(
|
||||
// widget.initialFilter.createdDateAfter,
|
||||
// widget.initialFilter.createdDateBefore,
|
||||
// ),
|
||||
// // Workaround for theme data not being correctly passed to daterangepicker, see
|
||||
// // https://github.com/flutter/flutter/issues/87580
|
||||
// pickerBuilder: (context, Widget? child) => Theme(
|
||||
// data: Theme.of(context).copyWith(
|
||||
// dialogBackgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
// appBarTheme: Theme.of(context).appBarTheme.copyWith(
|
||||
// iconTheme:
|
||||
// IconThemeData(color: Theme.of(context).primaryColor),
|
||||
// ),
|
||||
// colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||
// onPrimary: Theme.of(context).primaryColor,
|
||||
// primary: Theme.of(context).colorScheme.primary,
|
||||
// ),
|
||||
// ),
|
||||
// child: child!,
|
||||
// ),
|
||||
// format: DateFormat.yMMMd(Localizations.localeOf(context).toString()),
|
||||
// fieldStartLabelText:
|
||||
// S.of(context).documentFilterDateRangeFieldStartLabel,
|
||||
// fieldEndLabelText: S.of(context).documentFilterDateRangeFieldEndLabel,
|
||||
// firstDate: DateTime.fromMicrosecondsSinceEpoch(0),
|
||||
// lastDate: DateTime.now(),
|
||||
// name: fkCreatedAt,
|
||||
// decoration: InputDecoration(
|
||||
// prefixIcon: const Icon(Icons.calendar_month_outlined),
|
||||
// labelText: S.of(context).documentCreatedPropertyLabel,
|
||||
// suffixIcon: IconButton(
|
||||
// icon: const Icon(Icons.clear),
|
||||
// onPressed: () {
|
||||
// _formKey.currentState?.fields[fkCreatedAt]?.didChange(null);
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ).paddedSymmetrically(horizontal: 8, vertical: 4.0),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget _buildCreatedDateRangePickerFormField() {
|
||||
return Column(
|
||||
children: [
|
||||
FormBuilderDateRangePicker(
|
||||
initialValue: _dateTimeRangeOfNullable(
|
||||
widget.initialFilter.createdDateAfter,
|
||||
widget.initialFilter.createdDateBefore,
|
||||
),
|
||||
// Workaround for theme data not being correctly passed to daterangepicker, see
|
||||
// https://github.com/flutter/flutter/issues/87580
|
||||
pickerBuilder: (context, Widget? child) => Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
dialogBackgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
appBarTheme: Theme.of(context).appBarTheme.copyWith(
|
||||
iconTheme:
|
||||
IconThemeData(color: Theme.of(context).primaryColor),
|
||||
),
|
||||
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||
onPrimary: Theme.of(context).primaryColor,
|
||||
primary: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
),
|
||||
format: DateFormat.yMMMd(Localizations.localeOf(context).toString()),
|
||||
fieldStartLabelText:
|
||||
S.of(context).documentFilterDateRangeFieldStartLabel,
|
||||
fieldEndLabelText: S.of(context).documentFilterDateRangeFieldEndLabel,
|
||||
firstDate: DateTime.fromMicrosecondsSinceEpoch(0),
|
||||
lastDate: DateTime.now(),
|
||||
name: fkCreatedAt,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.calendar_month_outlined),
|
||||
labelText: S.of(context).documentCreatedPropertyLabel,
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () {
|
||||
_formKey.currentState?.fields[fkCreatedAt]?.didChange(null);
|
||||
},
|
||||
),
|
||||
),
|
||||
).paddedSymmetrically(horizontal: 8, vertical: 4.0),
|
||||
_buildDateRangePickerHelper(fkCreatedAt),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAddedDateRangePickerFormField() {
|
||||
return Column(
|
||||
children: [
|
||||
FormBuilderDateRangePicker(
|
||||
initialValue: _dateTimeRangeOfNullable(
|
||||
widget.initialFilter.addedDateAfter,
|
||||
widget.initialFilter.addedDateBefore,
|
||||
),
|
||||
// Workaround for theme data not being correctly passed to daterangepicker, see
|
||||
// https://github.com/flutter/flutter/issues/87580
|
||||
pickerBuilder: (context, Widget? child) => Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
dialogBackgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
appBarTheme: Theme.of(context).appBarTheme.copyWith(
|
||||
iconTheme:
|
||||
IconThemeData(color: Theme.of(context).primaryColor),
|
||||
),
|
||||
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||
onPrimary: Theme.of(context).primaryColor,
|
||||
primary: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
),
|
||||
format: DateFormat.yMMMd(),
|
||||
fieldStartLabelText:
|
||||
S.of(context).documentFilterDateRangeFieldStartLabel,
|
||||
fieldEndLabelText: S.of(context).documentFilterDateRangeFieldEndLabel,
|
||||
firstDate: DateTime.fromMicrosecondsSinceEpoch(0),
|
||||
lastDate: DateTime.now(),
|
||||
name: fkAddedAt,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.calendar_month_outlined),
|
||||
labelText: S.of(context).documentAddedPropertyLabel,
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () {
|
||||
_formKey.currentState?.fields[fkAddedAt]?.didChange(null);
|
||||
},
|
||||
),
|
||||
),
|
||||
).paddedSymmetrically(horizontal: 8),
|
||||
const SizedBox(height: 4.0),
|
||||
_buildDateRangePickerHelper(fkAddedAt),
|
||||
],
|
||||
);
|
||||
}
|
||||
// Widget _buildAddedDateRangePickerFormField() {
|
||||
// return Column(
|
||||
// children: [
|
||||
// FormBuilderDateRangePicker(
|
||||
// initialValue: _dateTimeRangeOfNullable(
|
||||
// widget.initialFilter.addedDateAfter,
|
||||
// widget.initialFilter.addedDateBefore,
|
||||
// ),
|
||||
// // Workaround for theme data not being correctly passed to daterangepicker, see
|
||||
// // https://github.com/flutter/flutter/issues/87580
|
||||
// pickerBuilder: (context, Widget? child) => Theme(
|
||||
// data: Theme.of(context).copyWith(
|
||||
// dialogBackgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
// appBarTheme: Theme.of(context).appBarTheme.copyWith(
|
||||
// iconTheme:
|
||||
// IconThemeData(color: Theme.of(context).primaryColor),
|
||||
// ),
|
||||
// colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||
// onPrimary: Theme.of(context).primaryColor,
|
||||
// primary: Theme.of(context).colorScheme.primary,
|
||||
// ),
|
||||
// ),
|
||||
// child: child!,
|
||||
// ),
|
||||
// format: DateFormat.yMMMd(),
|
||||
// fieldStartLabelText:
|
||||
// S.of(context).documentFilterDateRangeFieldStartLabel,
|
||||
// fieldEndLabelText: S.of(context).documentFilterDateRangeFieldEndLabel,
|
||||
// firstDate: DateTime.fromMicrosecondsSinceEpoch(0),
|
||||
// lastDate: DateTime.now(),
|
||||
// name: fkAddedAt,
|
||||
// decoration: InputDecoration(
|
||||
// prefixIcon: const Icon(Icons.calendar_month_outlined),
|
||||
// labelText: S.of(context).documentAddedPropertyLabel,
|
||||
// suffixIcon: IconButton(
|
||||
// icon: const Icon(Icons.clear),
|
||||
// onPressed: () {
|
||||
// _formKey.currentState?.fields[fkAddedAt]?.didChange(null);
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ).paddedSymmetrically(horizontal: 8),
|
||||
// const SizedBox(height: 4.0),
|
||||
// _buildDateRangePickerHelper(fkAddedAt),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
|
||||
void _onApplyFilter() async {
|
||||
_formKey.currentState?.save();
|
||||
@@ -408,19 +320,17 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
DocumentFilter _assembleFilter() {
|
||||
final v = _formKey.currentState!.value;
|
||||
return DocumentFilter(
|
||||
createdDateBefore: (v[fkCreatedAt] as DateTimeRange?)?.end,
|
||||
createdDateAfter: (v[fkCreatedAt] as DateTimeRange?)?.start,
|
||||
correspondent: v[fkCorrespondent] as CorrespondentQuery? ??
|
||||
created: (v[fkCreatedAt] as DateRangeQuery),
|
||||
correspondent: v[fkCorrespondent] as IdQueryParameter? ??
|
||||
DocumentFilter.initial.correspondent,
|
||||
documentType: v[fkDocumentType] as DocumentTypeQuery? ??
|
||||
documentType: v[fkDocumentType] as IdQueryParameter? ??
|
||||
DocumentFilter.initial.documentType,
|
||||
storagePath: v[fkStoragePath] as StoragePathQuery? ??
|
||||
storagePath: v[fkStoragePath] as IdQueryParameter? ??
|
||||
DocumentFilter.initial.storagePath,
|
||||
tags:
|
||||
v[DocumentModel.tagsKey] as TagsQuery? ?? DocumentFilter.initial.tags,
|
||||
queryText: v[fkQuery] as String?,
|
||||
addedDateBefore: (v[fkAddedAt] as DateTimeRange?)?.end,
|
||||
addedDateAfter: (v[fkAddedAt] as DateTimeRange?)?.start,
|
||||
added: (v[fkAddedAt] as DateRangeQuery),
|
||||
queryType: v[QueryTypeFormField.fkQueryType] as QueryType,
|
||||
asnQuery: widget.initialFilter.asnQuery,
|
||||
page: 1,
|
||||
|
||||
@@ -52,12 +52,12 @@ class CorrespondentWidget extends StatelessWidget {
|
||||
if (cubit.state.filter.correspondent.id == correspondentId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(correspondent: const CorrespondentQuery.unset()),
|
||||
filter.copyWith(correspondent: const IdQueryParameter.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) => filter.copyWith(
|
||||
correspondent: CorrespondentQuery.fromId(correspondentId)),
|
||||
correspondent: IdQueryParameter.fromId(correspondentId)),
|
||||
);
|
||||
}
|
||||
afterSelected?.call();
|
||||
|
||||
@@ -51,12 +51,12 @@ class DocumentTypeWidget extends StatelessWidget {
|
||||
if (cubit.state.filter.documentType.id == documentTypeId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(documentType: const DocumentTypeQuery.unset()),
|
||||
filter.copyWith(documentType: const IdQueryParameter.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) => filter.copyWith(
|
||||
documentType: DocumentTypeQuery.fromId(documentTypeId)),
|
||||
documentType: IdQueryParameter.fromId(documentTypeId)),
|
||||
);
|
||||
}
|
||||
afterSelected?.call();
|
||||
|
||||
@@ -54,12 +54,12 @@ class StoragePathWidget extends StatelessWidget {
|
||||
if (cubit.state.filter.correspondent.id == pathId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(storagePath: const StoragePathQuery.unset()),
|
||||
filter.copyWith(storagePath: const IdQueryParameter.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(storagePath: StoragePathQuery.fromId(pathId)),
|
||||
filter.copyWith(storagePath: IdQueryParameter.fromId(pathId)),
|
||||
);
|
||||
}
|
||||
afterSelected?.call();
|
||||
|
||||
@@ -126,7 +126,7 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
),
|
||||
child: LabelTabView<Correspondent>(
|
||||
filterBuilder: (label) => DocumentFilter(
|
||||
correspondent: CorrespondentQuery.fromId(label.id),
|
||||
correspondent: IdQueryParameter.fromId(label.id),
|
||||
pageSize: label.documentCount ?? 0,
|
||||
),
|
||||
onEdit: _openEditCorrespondentPage,
|
||||
@@ -146,7 +146,7 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
),
|
||||
child: LabelTabView<DocumentType>(
|
||||
filterBuilder: (label) => DocumentFilter(
|
||||
documentType: DocumentTypeQuery.fromId(label.id),
|
||||
documentType: IdQueryParameter.fromId(label.id),
|
||||
pageSize: label.documentCount ?? 0,
|
||||
),
|
||||
onEdit: _openEditDocumentTypePage,
|
||||
@@ -194,7 +194,7 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
child: LabelTabView<StoragePath>(
|
||||
onEdit: _openEditStoragePathPage,
|
||||
filterBuilder: (label) => DocumentFilter(
|
||||
storagePath: StoragePathQuery.fromId(label.id),
|
||||
storagePath: IdQueryParameter.fromId(label.id),
|
||||
pageSize: label.documentCount ?? 0,
|
||||
),
|
||||
contentBuilder: (path) => Text(path.path ?? ""),
|
||||
|
||||
@@ -9,31 +9,26 @@ import 'package:paperless_mobile/generated/l10n.dart';
|
||||
/// Form field allowing to select labels (i.e. correspondent, documentType)
|
||||
/// [T] is the label type (e.g. [DocumentType], [Correspondent], ...), [R] is the return type (e.g. [CorrespondentQuery], ...).
|
||||
///
|
||||
class LabelFormField<T extends Label, R extends IdQueryParameter>
|
||||
extends StatefulWidget {
|
||||
class LabelFormField<T extends Label> extends StatefulWidget {
|
||||
final Widget prefixIcon;
|
||||
final Map<int, T> state;
|
||||
final Map<int, T> labelOptions;
|
||||
final FormBuilderState? formBuilderState;
|
||||
final IdQueryParameter? initialValue;
|
||||
final String name;
|
||||
final String label;
|
||||
final String textFieldLabel;
|
||||
final FormFieldValidator? validator;
|
||||
final Widget Function(String)? labelCreationWidgetBuilder;
|
||||
final R Function() queryParameterNotAssignedBuilder;
|
||||
final R Function(int? id) queryParameterIdBuilder;
|
||||
final Widget Function(String initialName)? labelCreationWidgetBuilder;
|
||||
final bool notAssignedSelectable;
|
||||
final void Function(R?)? onChanged;
|
||||
final void Function(IdQueryParameter?)? onChanged;
|
||||
|
||||
const LabelFormField({
|
||||
Key? key,
|
||||
required this.name,
|
||||
required this.state,
|
||||
required this.labelOptions,
|
||||
this.validator,
|
||||
this.initialValue,
|
||||
required this.label,
|
||||
required this.textFieldLabel,
|
||||
this.labelCreationWidgetBuilder,
|
||||
required this.queryParameterNotAssignedBuilder,
|
||||
required this.queryParameterIdBuilder,
|
||||
required this.formBuilderState,
|
||||
required this.prefixIcon,
|
||||
this.notAssignedSelectable = true,
|
||||
@@ -41,11 +36,10 @@ class LabelFormField<T extends Label, R extends IdQueryParameter>
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LabelFormField<T, R>> createState() => _LabelFormFieldState<T, R>();
|
||||
State<LabelFormField<T>> createState() => _LabelFormFieldState<T>();
|
||||
}
|
||||
|
||||
class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
extends State<LabelFormField<T, R>> {
|
||||
class _LabelFormFieldState<T extends Label> extends State<LabelFormField<T>> {
|
||||
bool _showCreationSuffixIcon = false;
|
||||
late bool _showClearSuffixIcon;
|
||||
|
||||
@@ -54,12 +48,13 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_showClearSuffixIcon = widget.state.containsKey(widget.initialValue?.id);
|
||||
_showClearSuffixIcon =
|
||||
widget.labelOptions.containsKey(widget.initialValue?.id);
|
||||
_textEditingController = TextEditingController(
|
||||
text: widget.state[widget.initialValue?.id]?.name ?? '',
|
||||
text: widget.labelOptions[widget.initialValue?.id]?.name ?? '',
|
||||
)..addListener(() {
|
||||
setState(() {
|
||||
_showCreationSuffixIcon = widget.state.values
|
||||
_showCreationSuffixIcon = widget.labelOptions.values
|
||||
.where(
|
||||
(item) => item.name.toLowerCase().startsWith(
|
||||
_textEditingController.text.toLowerCase(),
|
||||
@@ -74,7 +69,7 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isEnabled = widget.state.values.fold<bool>(
|
||||
final isEnabled = widget.labelOptions.values.fold<bool>(
|
||||
false,
|
||||
(previousValue, element) =>
|
||||
previousValue || (element.documentCount ?? 0) > 0) ||
|
||||
@@ -90,7 +85,7 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
TextStyle(color: Theme.of(context).disabledColor, fontSize: 18.0),
|
||||
),
|
||||
),
|
||||
initialValue: widget.initialValue ?? widget.queryParameterIdBuilder(null),
|
||||
initialValue: widget.initialValue ?? const IdQueryParameter.unset(),
|
||||
name: widget.name,
|
||||
suggestionsBoxDecoration: SuggestionsBoxDecoration(
|
||||
shape: RoundedRectangleBorder(
|
||||
@@ -103,7 +98,7 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
),
|
||||
itemBuilder: (context, suggestion) => ListTile(
|
||||
title: Text(
|
||||
widget.state[suggestion.id]?.name ??
|
||||
widget.labelOptions[suggestion.id]?.name ??
|
||||
S.of(context).labelNotAssignedText,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -112,10 +107,10 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
style: ListTileStyle.list,
|
||||
),
|
||||
suggestionsCallback: (pattern) {
|
||||
final List<IdQueryParameter> suggestions = widget.state.entries
|
||||
final List<IdQueryParameter> suggestions = widget.labelOptions.entries
|
||||
.where(
|
||||
(entry) =>
|
||||
widget.state[entry.key]!.name
|
||||
widget.labelOptions[entry.key]!.name
|
||||
.toLowerCase()
|
||||
.contains(pattern.toLowerCase()) ||
|
||||
pattern.isEmpty,
|
||||
@@ -125,34 +120,33 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
widget.labelCreationWidgetBuilder != null ||
|
||||
(entry.value.documentCount ?? 0) > 0,
|
||||
)
|
||||
.map((entry) => widget.queryParameterIdBuilder(entry.key))
|
||||
.map((entry) => IdQueryParameter.fromId(entry.key))
|
||||
.toList();
|
||||
if (widget.notAssignedSelectable) {
|
||||
suggestions.insert(0, widget.queryParameterNotAssignedBuilder());
|
||||
suggestions.insert(0, const IdQueryParameter.notAssigned());
|
||||
}
|
||||
return suggestions;
|
||||
},
|
||||
onChanged: (value) {
|
||||
setState(() => _showClearSuffixIcon = value?.isSet ?? false);
|
||||
widget.onChanged?.call(value as R);
|
||||
widget.onChanged?.call(value);
|
||||
},
|
||||
controller: _textEditingController,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: widget.prefixIcon,
|
||||
label: Text(widget.label),
|
||||
label: Text(widget.textFieldLabel),
|
||||
hintText: _getLocalizedHint(context),
|
||||
suffixIcon: _buildSuffixIcon(context),
|
||||
),
|
||||
selectionToTextTransformer: (suggestion) {
|
||||
if (suggestion == widget.queryParameterNotAssignedBuilder()) {
|
||||
if (suggestion == const IdQueryParameter.notAssigned()) {
|
||||
return S.of(context).labelNotAssignedText;
|
||||
}
|
||||
return widget.state[suggestion.id]?.name ?? "";
|
||||
return widget.labelOptions[suggestion.id]?.name ?? "";
|
||||
},
|
||||
direction: AxisDirection.up,
|
||||
onSuggestionSelected: (suggestion) => widget
|
||||
.formBuilderState?.fields[widget.name]
|
||||
?.didChange(suggestion as R),
|
||||
onSuggestionSelected: (suggestion) =>
|
||||
widget.formBuilderState?.fields[widget.name]?.didChange(suggestion),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -161,7 +155,7 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
return IconButton(
|
||||
onPressed: () async {
|
||||
FocusScope.of(context).unfocus();
|
||||
final createdLabel = await showDialog(
|
||||
final createdLabel = await showDialog<T>(
|
||||
context: context,
|
||||
builder: (context) => widget.labelCreationWidgetBuilder!(
|
||||
_textEditingController.text,
|
||||
@@ -170,7 +164,7 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
if (createdLabel != null) {
|
||||
// If new label has been created, set form field value and text of this form field and unfocus keyboard (we assume user is done).
|
||||
widget.formBuilderState?.fields[widget.name]
|
||||
?.didChange(widget.queryParameterIdBuilder(createdLabel.id));
|
||||
?.didChange(IdQueryParameter.fromId(createdLabel.id));
|
||||
_textEditingController.text = createdLabel.name;
|
||||
} else {
|
||||
_reset();
|
||||
@@ -192,7 +186,7 @@ class _LabelFormFieldState<T extends Label, R extends IdQueryParameter>
|
||||
|
||||
void _reset() {
|
||||
widget.formBuilderState?.fields[widget.name]?.didChange(
|
||||
widget.queryParameterIdBuilder(null), // equivalnt to IdQueryParam.unset()
|
||||
const IdQueryParameter.unset(),
|
||||
);
|
||||
_textEditingController.clear();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user