Add migration scripts, remove dependencies to codegen, and cleanups

This commit is contained in:
Anton Stubenbord
2023-10-06 14:27:42 +02:00
parent 29b7c8bdc0
commit 5dcae3f0b3
32 changed files with 738 additions and 583 deletions

View File

@@ -109,11 +109,12 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
.watch<DocumentEditCubit>()
.state
.correspondents,
initialValue:
state.document.correspondent != null
? IdQueryParameter.fromId(
state.document.correspondent!)
: const IdQueryParameter.unset(),
initialValue: state
.document.correspondent !=
null
? SetIdQueryParameter(
id: state.document.correspondent!)
: const UnsetIdQueryParameter(),
name: fkCorrespondent,
prefixIcon:
const Icon(Icons.person_outlined),
@@ -135,7 +136,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
_formKey.currentState
?.fields[fkCorrespondent]
?.didChange(
IdQueryParameter.fromId(itemData),
SetIdQueryParameter(id: itemData),
);
},
),
@@ -161,11 +162,11 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
addLabelText:
S.of(context)!.addDocumentType,
labelText: S.of(context)!.documentType,
initialValue:
state.document.documentType != null
? IdQueryParameter.fromId(
state.document.documentType!)
: const IdQueryParameter.unset(),
initialValue: state.document.documentType !=
null
? SetIdQueryParameter(
id: state.document.documentType!)
: const UnsetIdQueryParameter(),
options: state.documentTypes,
name: _DocumentEditPageState.fkDocumentType,
prefixIcon:
@@ -185,7 +186,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
onPressed: () => _formKey.currentState
?.fields[fkDocumentType]
?.didChange(
IdQueryParameter.fromId(itemData),
SetIdQueryParameter(id: itemData),
),
),
),
@@ -211,9 +212,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
options: state.storagePaths,
initialValue:
state.document.storagePath != null
? IdQueryParameter.fromId(
state.document.storagePath!)
: const IdQueryParameter.unset(),
? SetIdQueryParameter(
id: state.document.storagePath!)
: const UnsetIdQueryParameter(),
name: fkStoragePath,
prefixIcon:
const Icon(Icons.folder_outlined),
@@ -229,7 +230,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
allowOnlySelection: true,
allowCreation: true,
allowExclude: false,
initialValue: TagsQuery.ids(
initialValue: IdsTagsQuery(
include: state.document.tags.toList(),
),
).padded(),
@@ -254,15 +255,17 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
?.fields[fkTags]?.value as TagsQuery;
_formKey.currentState?.fields[fkTags]
?.didChange(
currentTags.maybeWhen(
ids: (include, exclude) =>
TagsQuery.ids(include: [
...include,
itemData
], exclude: exclude),
orElse: () => TagsQuery.ids(
include: [itemData]),
),
switch (currentTags) {
IdsTagsQuery(
include: var i,
exclude: var e
) =>
IdsTagsQuery(
include: [...i, itemData],
exclude: e,
),
_ => IdsTagsQuery(include: [itemData])
},
);
},
);
@@ -301,16 +304,35 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
Future<void> _onSubmit(DocumentModel document) async {
if (_formKey.currentState?.saveAndValidate() ?? false) {
final values = _formKey.currentState!.value;
final correspondentParam = values[fkCorrespondent] as IdQueryParameter?;
final documentTypeParam = values[fkDocumentType] as IdQueryParameter?;
final storagePathParam = values[fkStoragePath] as IdQueryParameter?;
final tagsParam = values[fkTags] as TagsQuery?;
final correspondent = switch (correspondentParam) {
SetIdQueryParameter(id: var id) => id,
_ => null,
};
final documentType = switch (documentTypeParam) {
SetIdQueryParameter(id: var id) => id,
_ => null,
};
final storagePath = switch (storagePathParam) {
SetIdQueryParameter(id: var id) => id,
_ => null,
};
final tags = switch (tagsParam) {
IdsTagsQuery(include: var i) => i,
_ => null,
};
var mergedDocument = document.copyWith(
title: values[fkTitle],
created: values[fkCreatedDate],
documentType: () => (values[fkDocumentType] as IdQueryParameter?)
?.whenOrNull(fromId: (id) => id),
correspondent: () => (values[fkCorrespondent] as IdQueryParameter?)
?.whenOrNull(fromId: (id) => id),
storagePath: () => (values[fkStoragePath] as IdQueryParameter?)
?.whenOrNull(fromId: (id) => id),
tags: (values[fkTags] as IdsTagsQuery?)?.include,
correspondent: () => correspondent,
documentType: () => documentType,
storagePath: () => storagePath,
tags: tags,
content: values[fkContent],
);

View File

@@ -344,20 +344,29 @@ class _DocumentUploadPreparationPageState
final cubit = context.read<DocumentUploadCubit>();
try {
setState(() => _isUploadLoading = true);
final formValues = _formKey.currentState!.value;
final fv = _formKey.currentState!.value;
final correspondentParam =
formValues[DocumentModel.correspondentKey] as IdQueryParameter?;
final docTypeParam =
formValues[DocumentModel.documentTypeKey] as IdQueryParameter?;
final tagsParam = formValues[DocumentModel.tagsKey] as TagsQuery?;
final createdAt = formValues[DocumentModel.createdKey] as DateTime?;
final title = formValues[DocumentModel.titleKey] as String;
final correspondent = switch (correspondentParam) {
SetIdQueryParameter(id: var id) => id,
_ => null,
};
final docType = switch (docTypeParam) {
SetIdQueryParameter(id: var id) => id,
_ => null,
};
final tags = switch (tagsParam) {
IdsTagsQuery(include: var ids) => ids,
_ => const <int>[],
};
final createdAt = fv[DocumentModel.createdKey] as DateTime?;
final title = fv[DocumentModel.titleKey] as String;
final docType = (fv[DocumentModel.documentTypeKey] as IdQueryParameter?)
?.whenOrNull(fromId: (id) => id);
final tags = (fv[DocumentModel.tagsKey] as TagsQuery?)
?.whenOrNull(ids: (include, exclude) => include) ??
[];
final correspondent =
(fv[DocumentModel.correspondentKey] as IdQueryParameter?)
?.whenOrNull(fromId: (id) => id);
final asn = fv[DocumentModel.asnKey] as int?;
final asn = formValues[DocumentModel.asnKey] as int?;
final taskId = await cubit.upload(
await widget.fileBytes,
filename: _padWithExtension(

View File

@@ -12,10 +12,9 @@ import 'package:paperless_mobile/features/paged_document_view/cubit/document_pag
import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart';
import 'package:paperless_mobile/features/settings/model/view_type.dart';
part 'documents_cubit.g.dart';
part 'documents_state.dart';
class DocumentsCubit extends HydratedCubit<DocumentsState>
class DocumentsCubit extends Cubit<DocumentsState>
with DocumentPagingBlocMixin {
@override
final PaperlessDocumentsApi api;
@@ -135,13 +134,13 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
await _userState.save();
}
@override
DocumentsState? fromJson(Map<String, dynamic> json) {
return DocumentsState.fromJson(json);
}
// @override
// DocumentsState? fromJson(Map<String, dynamic> json) {
// return DocumentsState.fromJson(json);
// }
@override
Map<String, dynamic>? toJson(DocumentsState state) {
return state.toJson();
}
// @override
// Map<String, dynamic>? toJson(DocumentsState state) {
// return state.toJson();
// }
}

View File

@@ -1,17 +1,10 @@
part of 'documents_cubit.dart';
@JsonSerializable()
class DocumentsState extends DocumentPagingState {
@JsonKey(includeToJson: false, includeFromJson: false)
final List<DocumentModel> selection;
@JsonKey(includeToJson: false, includeFromJson: false)
final Map<int, Correspondent> correspondents;
@JsonKey(includeToJson: false, includeFromJson: false)
final Map<int, DocumentType> documentTypes;
@JsonKey(includeToJson: false, includeFromJson: false)
final Map<int, Tag> tags;
@JsonKey(includeToJson: false, includeFromJson: false)
final Map<int, StoragePath> storagePaths;
final ViewType viewType;
@@ -85,9 +78,4 @@ class DocumentsState extends DocumentPagingState {
value: value,
);
}
factory DocumentsState.fromJson(Map<String, dynamic> json) =>
_$DocumentsStateFromJson(json);
Map<String, dynamic> toJson() => _$DocumentsStateToJson(this);
}

View File

@@ -252,7 +252,8 @@ class _DocumentsPageState extends State<DocumentsPage> {
cubit.resetSelection();
return false;
}
if (cubit.state.filter.appliedFiltersCount > 0 || cubit.state.filter.selectedView != null) {
if (cubit.state.filter.appliedFiltersCount > 0 ||
cubit.state.filter.selectedView != null) {
await _onResetFilter();
return false;
}
@@ -512,8 +513,8 @@ class _DocumentsPageState extends State<DocumentsPage> {
void _addTagToFilter(int tagId) {
final cubit = context.read<DocumentsCubit>();
try {
cubit.state.filter.tags.maybeMap(
ids: (state) {
switch (cubit.state.filter.tags) {
case IdsTagsQuery state:
if (state.include.contains(tagId)) {
cubit.updateCurrentFilter(
(filter) => filter.copyWith(
@@ -541,13 +542,13 @@ class _DocumentsPageState extends State<DocumentsPage> {
),
);
}
},
orElse: () {
break;
default:
cubit.updateCurrentFilter(
(filter) => filter.copyWith(tags: TagsQuery.ids(include: [tagId])),
(filter) => filter.copyWith(tags: IdsTagsQuery(include: [tagId])),
);
},
);
break;
}
} on PaperlessApiException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
}
@@ -558,27 +559,26 @@ class _DocumentsPageState extends State<DocumentsPage> {
final cubit = context.read<DocumentsCubit>();
try {
cubit.state.filter.correspondent.maybeWhen(
fromId: (id) {
switch (cubit.state.filter.correspondent) {
case SetIdQueryParameter(id: var id):
if (id == correspondentId) {
cubit.updateCurrentFilter(
(filter) => filter.copyWith(
correspondent: const IdQueryParameter.unset()),
(filter) =>
filter.copyWith(correspondent: const UnsetIdQueryParameter()),
);
} else {
cubit.updateCurrentFilter(
(filter) => filter.copyWith(
correspondent: IdQueryParameter.fromId(correspondentId)),
correspondent: SetIdQueryParameter(id: correspondentId)),
);
}
},
orElse: () {
cubit.updateCurrentFilter(
(filter) => filter.copyWith(
correspondent: IdQueryParameter.fromId(correspondentId)),
);
},
);
break;
default:
cubit.updateCurrentFilter((filter) => filter.copyWith(
correspondent: SetIdQueryParameter(id: correspondentId),
));
break;
}
} on PaperlessApiException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
}
@@ -589,27 +589,27 @@ class _DocumentsPageState extends State<DocumentsPage> {
final cubit = context.read<DocumentsCubit>();
try {
cubit.state.filter.documentType.maybeWhen(
fromId: (id) {
switch (cubit.state.filter.documentType) {
case SetIdQueryParameter(id: var id):
if (id == documentTypeId) {
cubit.updateCurrentFilter(
(filter) =>
filter.copyWith(documentType: const IdQueryParameter.unset()),
filter.copyWith(documentType: const UnsetIdQueryParameter()),
);
} else {
cubit.updateCurrentFilter(
(filter) => filter.copyWith(
documentType: IdQueryParameter.fromId(documentTypeId)),
documentType: SetIdQueryParameter(id: documentTypeId)),
);
}
},
orElse: () {
break;
default:
cubit.updateCurrentFilter(
(filter) => filter.copyWith(
documentType: IdQueryParameter.fromId(documentTypeId)),
documentType: SetIdQueryParameter(id: documentTypeId)),
);
},
);
break;
}
} on PaperlessApiException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
}
@@ -620,27 +620,28 @@ class _DocumentsPageState extends State<DocumentsPage> {
final cubit = context.read<DocumentsCubit>();
try {
cubit.state.filter.storagePath.maybeWhen(
fromId: (id) {
if (id == pathId) {
switch (cubit.state.filter.storagePath){
case SetIdQueryParameter(id: var id):
if (id == pathId) {
cubit.updateCurrentFilter(
(filter) =>
filter.copyWith(storagePath: const IdQueryParameter.unset()),
filter.copyWith(storagePath: const UnsetIdQueryParameter()),
);
} else {
cubit.updateCurrentFilter(
(filter) =>
filter.copyWith(storagePath: IdQueryParameter.fromId(pathId)),
filter.copyWith(storagePath: SetIdQueryParameter(id: pathId)),
);
}
},
orElse: () {
cubit.updateCurrentFilter(
break;
default:
cubit.updateCurrentFilter(
(filter) =>
filter.copyWith(storagePath: IdQueryParameter.fromId(pathId)),
filter.copyWith(storagePath: SetIdQueryParameter(id: pathId)),
);
},
);
break;
}
} on PaperlessApiException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
}

View File

@@ -118,7 +118,7 @@ class InboxCubit extends HydratedCubit<InboxState>
updateFilter(
filter: DocumentFilter(
sortField: SortField.added,
tags: TagsQuery.ids(include: inboxTags.toList()),
tags: IdsTagsQuery(include: inboxTags.toList()),
),
);
}
@@ -160,7 +160,7 @@ class InboxCubit extends HydratedCubit<InboxState>
emitLoading: false,
filter: DocumentFilter(
sortField: SortField.added,
tags: TagsQuery.ids(include: inboxTags.toList()),
tags: IdsTagsQuery(include: inboxTags.toList()),
),
);
}

View File

@@ -116,16 +116,16 @@ class _FullscreenTagsFormState extends State<FullscreenTagsForm> {
icon: const Icon(Icons.done),
onPressed: () {
if (widget.allowOnlySelection) {
widget.onSubmit(returnValue: TagsQuery.ids(include: _include));
widget.onSubmit(returnValue: IdsTagsQuery(include: _include));
return;
}
late final TagsQuery query;
if (_notAssigned) {
query = const TagsQuery.notAssigned();
query = const NotAssignedTagsQuery();
} else if (_anyAssigned) {
query = TagsQuery.anyAssigned(tagIds: _include);
query = AnyAssignedTagsQuery(tagIds: _include);
} else {
query = TagsQuery.ids(include: _include, exclude: _exclude);
query = IdsTagsQuery(include: _include, exclude: _exclude);
}
widget.onSubmit(returnValue: query);
},

View File

@@ -96,19 +96,17 @@ class TagsFormField extends StatelessWidget {
if (query == null) {
yield Container();
} else {
final widgets = query.map(
ids: (value) => [
for (var inc in value.include)
_buildTagIdQueryWidget(context, inc, field, false),
for (var exc in value.exclude)
_buildTagIdQueryWidget(context, exc, field, true),
],
anyAssigned: (value) => [
for (var id in value.tagIds)
_buildAnyAssignedTagWidget(context, id, field, value),
],
notAssigned: (value) => [_buildNotAssignedTagWidget(context, field)],
);
final widgets = switch (query) {
IdsTagsQuery(include: var inc, exclude: var exc) => [
for (var i in inc) _buildTagIdQueryWidget(context, i, field, false),
for (var e in exc) _buildTagIdQueryWidget(context, e, field, true),
],
AnyAssignedTagsQuery query => [
for (var id in query.tagIds)
_buildAnyAssignedTagWidget(context, id, field, query),
],
NotAssignedTagsQuery() => [_buildNotAssignedTagWidget(context, field)],
};
for (var child in widgets) {
yield child;
}
@@ -185,7 +183,7 @@ class TagsFormField extends StatelessWidget {
tagIds: query.tagIds.whereNot((element) => element == e).toList(),
);
if (updatedQuery.tagIds.isEmpty) {
field.didChange(const TagsQuery.ids());
field.didChange(const IdsTagsQuery());
} else {
field.didChange(updatedQuery);
}

View File

@@ -259,7 +259,7 @@ class _LabelsPageState extends State<LabelsPage>
LabelTabView<Correspondent>(
labels: state.correspondents,
filterBuilder: (label) => DocumentFilter(
correspondent: IdQueryParameter.fromId(label.id!),
correspondent: SetIdQueryParameter(id: label.id!),
),
canEdit: user.canEditCorrespondents,
canAddNew: user.canCreateCorrespondents,
@@ -287,7 +287,7 @@ class _LabelsPageState extends State<LabelsPage>
LabelTabView<DocumentType>(
labels: state.documentTypes,
filterBuilder: (label) => DocumentFilter(
documentType: IdQueryParameter.fromId(label.id!),
documentType: SetIdQueryParameter(id: label.id!),
),
canEdit: user.canEditDocumentTypes,
canAddNew: user.canCreateDocumentTypes,
@@ -315,7 +315,7 @@ class _LabelsPageState extends State<LabelsPage>
LabelTabView<Tag>(
labels: state.tags,
filterBuilder: (label) => DocumentFilter(
tags: TagsQuery.ids(include: [label.id!]),
tags: IdsTagsQuery(include: [label.id!]),
),
canEdit: user.canEditTags,
canAddNew: user.canCreateTags,
@@ -354,7 +354,7 @@ class _LabelsPageState extends State<LabelsPage>
EditLabelRoute(label).push(context);
},
filterBuilder: (label) => DocumentFilter(
storagePath: IdQueryParameter.fromId(label.id!),
storagePath: SetIdQueryParameter(id: label.id!),
),
canEdit: user.canEditStoragePaths,
canAddNew: user.canCreateStoragePaths,

View File

@@ -32,11 +32,10 @@ class FullscreenLabelForm<T extends Label> extends StatefulWidget {
this.allowSelectUnassigned = true,
required this.canCreateNewLabel,
}) : assert(
!(initialValue?.isOnlyAssigned() ?? false) || showAnyAssignedOption,
!(initialValue?.isOnlyAssigned ?? false) || showAnyAssignedOption,
),
assert(
!(initialValue?.isOnlyNotAssigned() ?? false) ||
showNotAssignedOption,
!(initialValue?.isOnlyNotAssigned ?? false) || showNotAssignedOption,
),
assert((addNewLabelText != null) == (onCreateNewLabel != null));
@@ -87,11 +86,10 @@ class _FullscreenLabelFormState<T extends Label>
final index = AutocompleteHighlightedOption.of(context);
final value = index.isNegative ? null : options.elementAt(index);
widget.onSubmit(
returnValue: value?.maybeWhen(
fromId: (id) => IdQueryParameter.fromId(id),
orElse: () => const IdQueryParameter.unset(),
) ??
const IdQueryParameter.unset(),
returnValue: switch (value) {
SetIdQueryParameter query => query,
_ => const UnsetIdQueryParameter(),
},
);
},
autofocus: true,
@@ -169,7 +167,7 @@ class _FullscreenLabelFormState<T extends Label>
final label = await widget.onCreateNewLabel!(_textEditingController.text);
if (label?.id != null) {
widget.onSubmit(
returnValue: IdQueryParameter.fromId(label!.id!),
returnValue: SetIdQueryParameter(id: label!.id!),
);
}
}
@@ -184,21 +182,21 @@ class _FullscreenLabelFormState<T extends Label>
if (widget.initialValue == null) {
// If nothing is selected yet, show all options first.
for (final option in widget.options.values) {
yield IdQueryParameter.fromId(option.id!);
yield SetIdQueryParameter(id: option.id!);
}
if (widget.showNotAssignedOption) {
yield const IdQueryParameter.notAssigned();
yield const NotAssignedIdQueryParameter();
}
if (widget.showAnyAssignedOption) {
yield const IdQueryParameter.anyAssigned();
yield const AnyAssignedIdQueryParameter();
}
} else {
// If an initial value is given, show not assigned first, which will be selected by default when pressing "done" on keyboard.
if (widget.showNotAssignedOption) {
yield const IdQueryParameter.notAssigned();
yield const NotAssignedIdQueryParameter();
}
if (widget.showAnyAssignedOption) {
yield const IdQueryParameter.anyAssigned();
yield const AnyAssignedIdQueryParameter();
}
for (final option in widget.options.values) {
// Don't include the initial value in the selection
@@ -207,7 +205,7 @@ class _FullscreenLabelFormState<T extends Label>
option.id == initialValue.id) {
continue;
}
yield IdQueryParameter.fromId(option.id!);
yield SetIdQueryParameter(id: option.id!);
}
}
} else {
@@ -216,77 +214,76 @@ class _FullscreenLabelFormState<T extends Label>
.where((e) => e.name.trim().toLowerCase().contains(normalizedQuery));
if (matches.isNotEmpty) {
for (final match in matches) {
yield IdQueryParameter.fromId(match.id!);
yield SetIdQueryParameter(id: match.id!);
}
if (widget.showNotAssignedOption) {
yield const IdQueryParameter.notAssigned();
yield const NotAssignedIdQueryParameter();
}
if (widget.showAnyAssignedOption) {
yield const IdQueryParameter.anyAssigned();
yield const AnyAssignedIdQueryParameter();
}
} else {
if (widget.showNotAssignedOption) {
yield const IdQueryParameter.notAssigned();
yield const NotAssignedIdQueryParameter();
}
if (widget.showAnyAssignedOption) {
yield const IdQueryParameter.anyAssigned();
yield const AnyAssignedIdQueryParameter();
}
if (!(widget.showAnyAssignedOption || widget.showNotAssignedOption)) {
yield const IdQueryParameter.unset();
yield const UnsetIdQueryParameter();
}
}
}
}
String? _buildHintText() {
return widget.initialValue?.when(
unset: () => S.of(context)!.startTyping,
notAssigned: () => S.of(context)!.notAssigned,
anyAssigned: () => S.of(context)!.anyAssigned,
fromId: (id) => widget.options[id]?.name ?? S.of(context)!.startTyping,
);
return switch (widget.initialValue) {
UnsetIdQueryParameter() => S.of(context)!.startTyping,
NotAssignedIdQueryParameter() => S.of(context)!.notAssigned,
AnyAssignedIdQueryParameter() => S.of(context)!.anyAssigned,
SetIdQueryParameter(id: var id) =>
widget.options[id]?.name ?? S.of(context)!.startTyping,
_ => null,
};
}
Widget _buildOptionWidget(IdQueryParameter option, bool highlight) {
void onTap() => widget.onSubmit(returnValue: option);
if (option.isUnset()) {
return Center(
child: Column(
children: [
Text(S.of(context)!.noItemsFound).padded(),
if (widget.onCreateNewLabel != null)
TextButton(
child: Text(widget.addNewLabelText!),
onPressed: _onCreateNewLabel,
),
],
return switch (option) {
NotAssignedIdQueryParameter() => ListTile(
selected: highlight,
selectedTileColor: Theme.of(context).focusColor,
title: Text(S.of(context)!.notAssigned),
onTap: onTap,
),
);
}
return option.whenOrNull(
notAssigned: () => ListTile(
selected: highlight,
selectedTileColor: Theme.of(context).focusColor,
title: Text(S.of(context)!.notAssigned),
onTap: onTap,
),
anyAssigned: () => ListTile(
selected: highlight,
selectedTileColor: Theme.of(context).focusColor,
title: Text(S.of(context)!.anyAssigned),
onTap: onTap,
),
fromId: (id) => ListTile(
selected: highlight,
selectedTileColor: Theme.of(context).focusColor,
title: Text(widget.options[id]!.name),
onTap: onTap,
enabled: widget.allowSelectUnassigned
? true
: widget.options[id]!.documentCount != 0,
),
)!; // Never null, since we already return on unset before
AnyAssignedIdQueryParameter() => ListTile(
selected: highlight,
selectedTileColor: Theme.of(context).focusColor,
title: Text(S.of(context)!.anyAssigned),
onTap: onTap,
),
SetIdQueryParameter(id: var id) => ListTile(
selected: highlight,
selectedTileColor: Theme.of(context).focusColor,
title: Text(widget.options[id]!.name),
onTap: onTap,
enabled: widget.allowSelectUnassigned
? true
: widget.options[id]!.documentCount != 0,
),
UnsetIdQueryParameter() => Center(
child: Column(
children: [
Text(S.of(context)!.noItemsFound).padded(),
if (widget.onCreateNewLabel != null)
TextButton(
child: Text(widget.addNewLabelText!),
onPressed: _onCreateNewLabel,
),
],
),
),
};
}
}

View File

@@ -47,13 +47,13 @@ class LabelFormField<T extends Label> extends StatelessWidget {
}) : super(key: key);
String _buildText(BuildContext context, IdQueryParameter? value) {
return value?.when(
unset: () => '',
notAssigned: () => S.of(context)!.notAssigned,
anyAssigned: () => S.of(context)!.anyAssigned,
fromId: (id) => options[id]?.name,
) ??
'';
return switch (value) {
UnsetIdQueryParameter() => '',
NotAssignedIdQueryParameter() => S.of(context)!.notAssigned,
AnyAssignedIdQueryParameter() => S.of(context)!.anyAssigned,
SetIdQueryParameter(id: var id) => options[id]?.name ?? '',
_ => '',
};
}
@override
@@ -70,9 +70,14 @@ class LabelFormField<T extends Label> extends StatelessWidget {
text: _buildText(context, field.value),
);
final displayedSuggestions = suggestions
.whereNot((e) =>
e.id ==
field.value?.maybeWhen(fromId: (id) => id, orElse: () => -1))
.whereNot(
(e) =>
e.id ==
switch (field.value) {
SetIdQueryParameter(id: var id) => id,
_ => -1,
},
)
.toList();
return Column(
@@ -98,7 +103,7 @@ class LabelFormField<T extends Label> extends StatelessWidget {
? IconButton(
icon: const Icon(Icons.clear),
onPressed: () =>
field.didChange(const IdQueryParameter.unset()),
field.didChange(const UnsetIdQueryParameter()),
)
: null,
),
@@ -151,7 +156,7 @@ class LabelFormField<T extends Label> extends StatelessWidget {
child: ActionChip(
label: Text(suggestion.name),
onPressed: () => field.didChange(
IdQueryParameter.fromId(suggestion.id!),
SetIdQueryParameter(id: suggestion.id!),
),
),
);

View File

@@ -44,7 +44,8 @@ class _LandingPageState extends State<LandingPage> {
SliverToBoxAdapter(
child: Text(
S.of(context)!.welcomeUser(
currentUser.fullName ?? currentUser.username),
currentUser.fullName ?? currentUser.username,
),
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme