mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2026-01-31 14:24:58 -06:00
Added new query options for tags, added pdf preview on documents scanner page
This commit is contained in:
@@ -22,7 +22,7 @@ class DocumentsCubit extends Cubit<DocumentsState> {
|
||||
required void Function(DocumentModel document) onConsumptionFinished,
|
||||
int? documentType,
|
||||
int? correspondent,
|
||||
List<int>? tags,
|
||||
Iterable<int> tags = const [],
|
||||
DateTime? createdAt,
|
||||
}) async {
|
||||
await documentRepository.create(
|
||||
|
||||
@@ -2,18 +2,23 @@ import 'package:paperless_mobile/core/type/types.dart';
|
||||
|
||||
class BulkEditAction {
|
||||
final List<int> documents;
|
||||
final String _method;
|
||||
final BulkEditActionMethod _method;
|
||||
final Map<String, dynamic> parameters;
|
||||
|
||||
BulkEditAction.delete(this.documents)
|
||||
: _method = 'delete',
|
||||
: _method = BulkEditActionMethod.delete,
|
||||
parameters = {};
|
||||
|
||||
JSON toJson() {
|
||||
return {
|
||||
'documents': documents,
|
||||
'method': _method,
|
||||
'method': _method.name,
|
||||
'parameters': parameters,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum BulkEditActionMethod {
|
||||
delete,
|
||||
edit;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class DocumentModel extends Equatable {
|
||||
final int id;
|
||||
final String title;
|
||||
final String? content;
|
||||
final List<int> tags;
|
||||
final Iterable<int> tags;
|
||||
final int? documentType;
|
||||
final int? correspondent;
|
||||
final int? storagePath;
|
||||
@@ -78,7 +78,7 @@ class DocumentModel extends Equatable {
|
||||
modifiedKey: modified.toUtc().toIso8601String(),
|
||||
addedKey: added.toUtc().toIso8601String(),
|
||||
originalFileNameKey: originalFileName,
|
||||
tagsKey: tags,
|
||||
tagsKey: tags.toList(),
|
||||
storagePathKey: storagePath,
|
||||
};
|
||||
}
|
||||
@@ -86,10 +86,14 @@ class DocumentModel extends Equatable {
|
||||
DocumentModel copyWith({
|
||||
String? title,
|
||||
String? content,
|
||||
TagsQuery? tags,
|
||||
IdQueryParameter? documentType,
|
||||
IdQueryParameter? correspondent,
|
||||
IdQueryParameter? storagePath,
|
||||
bool overwriteTags = false,
|
||||
Iterable<int>? tags,
|
||||
bool overwriteDocumentType = false,
|
||||
int? documentType,
|
||||
bool overwriteCorrespondent = false,
|
||||
int? correspondent,
|
||||
bool overwriteStoragePath = false,
|
||||
int? storagePath,
|
||||
DateTime? created,
|
||||
DateTime? modified,
|
||||
DateTime? added,
|
||||
@@ -101,10 +105,11 @@ class DocumentModel extends Equatable {
|
||||
id: id,
|
||||
title: title ?? this.title,
|
||||
content: content ?? this.content,
|
||||
documentType: fromQuery(documentType, this.documentType),
|
||||
correspondent: fromQuery(correspondent, this.correspondent),
|
||||
storagePath: fromQuery(storagePath, this.storagePath),
|
||||
tags: fromListQuery(tags, this.tags),
|
||||
documentType: overwriteDocumentType ? documentType : this.documentType,
|
||||
correspondent:
|
||||
overwriteCorrespondent ? correspondent : this.correspondent,
|
||||
storagePath: overwriteDocumentType ? storagePath : this.storagePath,
|
||||
tags: overwriteTags ? tags ?? [] : this.tags,
|
||||
created: created ?? this.created,
|
||||
modified: modified ?? this.modified,
|
||||
added: added ?? this.added,
|
||||
@@ -114,20 +119,6 @@ class DocumentModel extends Equatable {
|
||||
);
|
||||
}
|
||||
|
||||
int? fromQuery(IdQueryParameter? query, int? previous) {
|
||||
if (query == null) {
|
||||
return previous;
|
||||
}
|
||||
return query.id;
|
||||
}
|
||||
|
||||
List<int> fromListQuery(TagsQuery? query, List<int> previous) {
|
||||
if (query == null) {
|
||||
return previous;
|
||||
}
|
||||
return query.ids;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
|
||||
@@ -43,7 +43,7 @@ class DocumentFilter with EquatableMixin {
|
||||
this.correspondent = const CorrespondentQuery.unset(),
|
||||
this.storagePath = const StoragePathQuery.unset(),
|
||||
this.asn = const AsnQuery.unset(),
|
||||
this.tags = const TagsQuery.unset(),
|
||||
this.tags = const IdsTagsQuery.unset(),
|
||||
this.sortField = SortField.created,
|
||||
this.sortOrder = SortOrder.descending,
|
||||
this.page = 1,
|
||||
|
||||
@@ -13,24 +13,24 @@ class FilterRule with EquatableMixin {
|
||||
static const int asnRule = 2;
|
||||
static const int correspondentRule = 3;
|
||||
static const int documentTypeRule = 4;
|
||||
static const int tagRule = 6;
|
||||
static const int includeTagsRule = 6;
|
||||
static const int hasAnyTag = 7; // Corresponds to Not assigned
|
||||
static const int createdBeforeRule = 8;
|
||||
static const int createdAfterRule = 9;
|
||||
static const int addedBeforeRule = 13;
|
||||
static const int addedAfterRule = 14;
|
||||
static const int excludeTagsRule = 17;
|
||||
static const int titleAndContentRule = 19;
|
||||
static const int extendedRule = 20;
|
||||
static const int storagePathRule = 25;
|
||||
// Currently unsupported view optiosn:
|
||||
// Currently unsupported view options:
|
||||
static const int _content = 1;
|
||||
static const int _isInInbox = 5;
|
||||
static const int _hasAnyTag = 7;
|
||||
static const int _createdYearIs = 10;
|
||||
static const int _createdMonthIs = 11;
|
||||
static const int _createdDayIs = 12;
|
||||
static const int _modifiedBefore = 15;
|
||||
static const int _modifiedAfter = 16;
|
||||
static const int _doesNotHaveTag = 17;
|
||||
static const int _doesNotHaveAsn = 18;
|
||||
static const int _moreLikeThis = 21;
|
||||
static const int _hasTagsIn = 22;
|
||||
@@ -76,11 +76,25 @@ class FilterRule with EquatableMixin {
|
||||
? const StoragePathQuery.notAssigned()
|
||||
: StoragePathQuery.fromId(int.parse(value!)),
|
||||
);
|
||||
case tagRule:
|
||||
case hasAnyTag:
|
||||
return filter.copyWith(
|
||||
tags: value == null
|
||||
? const TagsQuery.notAssigned()
|
||||
: TagsQuery.fromIds([...filter.tags.ids, int.parse(value!)]),
|
||||
tags: value == "true"
|
||||
? const AnyAssignedTagsQuery()
|
||||
: const OnlyNotAssignedTagsQuery(),
|
||||
);
|
||||
case includeTagsRule:
|
||||
assert(filter.tags is IdsTagsQuery);
|
||||
return filter.copyWith(
|
||||
tags: (filter.tags as IdsTagsQuery).withIdQueriesAdded([
|
||||
IncludeTagIdQuery(int.parse(value!)),
|
||||
]),
|
||||
);
|
||||
case excludeTagsRule:
|
||||
assert(filter.tags is IdsTagsQuery);
|
||||
return filter.copyWith(
|
||||
tags: (filter.tags as IdsTagsQuery).withIdQueriesAdded([
|
||||
ExcludeTagIdQuery(int.parse(value!)),
|
||||
]),
|
||||
);
|
||||
case createdBeforeRule:
|
||||
return filter.copyWith(
|
||||
@@ -131,12 +145,19 @@ class FilterRule with EquatableMixin {
|
||||
filterRules
|
||||
.add(FilterRule(storagePathRule, filter.storagePath.id!.toString()));
|
||||
}
|
||||
if (filter.tags.onlyNotAssigned) {
|
||||
filterRules.add(FilterRule(tagRule, null));
|
||||
if (filter.tags is OnlyNotAssignedTagsQuery) {
|
||||
filterRules.add(FilterRule(hasAnyTag, "false"));
|
||||
}
|
||||
if (filter.tags.isSet) {
|
||||
filterRules.addAll(
|
||||
filter.tags.ids.map((id) => FilterRule(tagRule, id.toString())));
|
||||
if (filter.tags is AnyAssignedTagsQuery) {
|
||||
filterRules.add(FilterRule(hasAnyTag, "true"));
|
||||
}
|
||||
if (filter.tags is IdsTagsQuery) {
|
||||
filterRules.addAll((filter.tags as IdsTagsQuery)
|
||||
.includedIds
|
||||
.map((id) => FilterRule(includeTagsRule, id.toString())));
|
||||
filterRules.addAll((filter.tags as IdsTagsQuery)
|
||||
.excludedIds
|
||||
.map((id) => FilterRule(excludeTagsRule, id.toString())));
|
||||
}
|
||||
|
||||
if (filter.queryText != null) {
|
||||
|
||||
@@ -1,38 +1,136 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:paperless_mobile/extensions/dart_extensions.dart';
|
||||
|
||||
class TagsQuery with EquatableMixin {
|
||||
final List<int> _ids;
|
||||
final bool? _isTagged;
|
||||
abstract class TagsQuery with EquatableMixin {
|
||||
const TagsQuery();
|
||||
String toQueryParameter();
|
||||
}
|
||||
|
||||
const TagsQuery.fromIds(List<int> ids)
|
||||
: _isTagged = null,
|
||||
_ids = ids;
|
||||
|
||||
const TagsQuery.anyAssigned()
|
||||
: _isTagged = true,
|
||||
_ids = const [];
|
||||
|
||||
const TagsQuery.notAssigned()
|
||||
: _isTagged = false,
|
||||
_ids = const [];
|
||||
|
||||
const TagsQuery.unset() : this.fromIds(const []);
|
||||
|
||||
bool get onlyNotAssigned => _isTagged == false;
|
||||
bool get onlyAssigned => _isTagged == true;
|
||||
|
||||
bool get isUnset => _ids.isEmpty && _isTagged == null;
|
||||
bool get isSet => _ids.isNotEmpty && _isTagged == null;
|
||||
|
||||
List<int> get ids => _ids;
|
||||
class OnlyNotAssignedTagsQuery extends TagsQuery {
|
||||
const OnlyNotAssignedTagsQuery();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
|
||||
@override
|
||||
String toQueryParameter() {
|
||||
if (onlyNotAssigned || onlyAssigned) {
|
||||
return '&is_tagged=$_isTagged';
|
||||
return '&is_tagged=0';
|
||||
}
|
||||
}
|
||||
|
||||
class AnyAssignedTagsQuery extends TagsQuery {
|
||||
const AnyAssignedTagsQuery();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
|
||||
@override
|
||||
String toQueryParameter() {
|
||||
return '&is_tagged=1';
|
||||
}
|
||||
}
|
||||
|
||||
class IdsTagsQuery extends TagsQuery {
|
||||
final Iterable<TagIdQuery> _idQueries;
|
||||
|
||||
const IdsTagsQuery([this._idQueries = const []]);
|
||||
|
||||
const IdsTagsQuery.unset() : _idQueries = const [];
|
||||
|
||||
IdsTagsQuery.included(Iterable<int> ids)
|
||||
: _idQueries = ids.map((id) => IncludeTagIdQuery(id));
|
||||
|
||||
IdsTagsQuery.fromIds(Iterable<int> ids) : this.included(ids);
|
||||
|
||||
IdsTagsQuery.excluded(Iterable<int> ids)
|
||||
: _idQueries = ids.map((id) => ExcludeTagIdQuery(id));
|
||||
|
||||
IdsTagsQuery withIdQueriesAdded(Iterable<TagIdQuery> idQueries) {
|
||||
final intersection = _idQueries
|
||||
.map((idQ) => idQ.id)
|
||||
.toSet()
|
||||
.intersection(_idQueries.map((idQ) => idQ.id).toSet());
|
||||
return IdsTagsQuery(
|
||||
[...withIdsRemoved(intersection).queries, ...idQueries],
|
||||
);
|
||||
}
|
||||
|
||||
IdsTagsQuery withIdsRemoved(Iterable<int> ids) {
|
||||
return IdsTagsQuery(
|
||||
_idQueries.where((idQuery) => !ids.contains(idQuery.id)),
|
||||
);
|
||||
}
|
||||
|
||||
Iterable<TagIdQuery> get queries => _idQueries;
|
||||
|
||||
Iterable<int> get includedIds {
|
||||
return _idQueries.whereType<IncludeTagIdQuery>().map((e) => e.id);
|
||||
}
|
||||
|
||||
Iterable<int> get excludedIds {
|
||||
return _idQueries.whereType<ExcludeTagIdQuery>().map((e) => e.id);
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a new instance with the type of the given [id] toggled.
|
||||
/// E.g. if the provided [id] is currently registered as a [IncludeTagIdQuery],
|
||||
/// then the new isntance will contain a [ExcludeTagIdQuery] with given id.
|
||||
///
|
||||
IdsTagsQuery withIdQueryToggled(int id) {
|
||||
return IdsTagsQuery(
|
||||
_idQueries.map((idQ) => idQ.id == id ? idQ.toggle() : idQ),
|
||||
);
|
||||
}
|
||||
|
||||
Iterable<int> get ids => [...includedIds, ...excludedIds];
|
||||
|
||||
@override
|
||||
String toQueryParameter() {
|
||||
final StringBuffer sb = StringBuffer("");
|
||||
if (includedIds.isNotEmpty) {
|
||||
sb.write('&tags__id__all=${includedIds.join(',')}');
|
||||
}
|
||||
return isUnset ? "" : '&tags__id__all=${ids.join(',')}';
|
||||
if (excludedIds.isNotEmpty) {
|
||||
sb.write('&tags__id__none=${excludedIds.join(',')}');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [_isTagged, _ids];
|
||||
List<Object?> get props => [_idQueries];
|
||||
}
|
||||
|
||||
abstract class TagIdQuery with EquatableMixin {
|
||||
final int id;
|
||||
|
||||
TagIdQuery(this.id);
|
||||
|
||||
String get methodName;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, methodName];
|
||||
|
||||
TagIdQuery toggle();
|
||||
}
|
||||
|
||||
class IncludeTagIdQuery extends TagIdQuery {
|
||||
IncludeTagIdQuery(super.id);
|
||||
|
||||
@override
|
||||
String get methodName => 'include';
|
||||
|
||||
@override
|
||||
TagIdQuery toggle() {
|
||||
return ExcludeTagIdQuery(id);
|
||||
}
|
||||
}
|
||||
|
||||
class ExcludeTagIdQuery extends TagIdQuery {
|
||||
ExcludeTagIdQuery(super.id);
|
||||
|
||||
@override
|
||||
String get methodName => 'exclude';
|
||||
|
||||
@override
|
||||
TagIdQuery toggle() {
|
||||
return IncludeTagIdQuery(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ abstract class DocumentRepository {
|
||||
required String title,
|
||||
int? documentType,
|
||||
int? correspondent,
|
||||
List<int>? tags,
|
||||
Iterable<int> tags = const [],
|
||||
DateTime? createdAt,
|
||||
});
|
||||
Future<DocumentModel> update(DocumentModel doc);
|
||||
|
||||
@@ -5,6 +5,9 @@ import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:http/src/boundary_characters.dart'; //TODO: remove once there is either a paperless API update or there is a better solution...
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_mobile/core/store/local_vault.dart';
|
||||
import 'package:paperless_mobile/core/type/types.dart';
|
||||
@@ -22,9 +25,6 @@ import 'package:paperless_mobile/features/documents/model/query_parameters/sort_
|
||||
import 'package:paperless_mobile/features/documents/model/similar_document.model.dart';
|
||||
import 'package:paperless_mobile/features/documents/repository/document_repository.dart';
|
||||
import 'package:paperless_mobile/util.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:http/src/boundary_characters.dart'; //TODO: remove once there is either a paperless API update or there is a better solution...
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
@Injectable(as: DocumentRepository)
|
||||
class DocumentRepositoryImpl implements DocumentRepository {
|
||||
@@ -45,7 +45,7 @@ class DocumentRepositoryImpl implements DocumentRepository {
|
||||
required String title,
|
||||
int? documentType,
|
||||
int? correspondent,
|
||||
List<int>? tags,
|
||||
Iterable<int> tags = const [],
|
||||
DateTime? createdAt,
|
||||
}) async {
|
||||
final auth = await localStorage.loadAuthenticationInformation();
|
||||
@@ -78,7 +78,7 @@ class DocumentRepositoryImpl implements DocumentRepository {
|
||||
bodyBuffer.write(_buildMultipartField(key, fields[key]!, boundary));
|
||||
}
|
||||
|
||||
for (final tag in tags ?? <int>[]) {
|
||||
for (final tag in tags) {
|
||||
bodyBuffer.write(_buildMultipartField('tags', tag.toString(), boundary));
|
||||
}
|
||||
|
||||
@@ -124,10 +124,10 @@ class DocumentRepositoryImpl implements DocumentRepository {
|
||||
Random _random = Random();
|
||||
var prefix = 'dart-http-boundary-';
|
||||
var list = List<int>.generate(
|
||||
70 - prefix.length,
|
||||
(index) =>
|
||||
boundaryCharacters[_random.nextInt(boundaryCharacters.length)],
|
||||
growable: false);
|
||||
70 - prefix.length,
|
||||
(index) => boundaryCharacters[_random.nextInt(boundaryCharacters.length)],
|
||||
growable: false,
|
||||
);
|
||||
return '$prefix${String.fromCharCodes(list)}';
|
||||
}
|
||||
|
||||
|
||||
@@ -420,7 +420,9 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
Future<void> _onOpen(DocumentModel document) async {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DocumentView(document: document),
|
||||
builder: (context) => DocumentView(
|
||||
documentBytes: getIt<DocumentRepository>().getPreview(document.id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -53,9 +53,8 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
documentBytes = getIt<DocumentRepository>().getPreview(widget.document.id);
|
||||
|
||||
super.initState();
|
||||
documentBytes = getIt<DocumentRepository>().getPreview(widget.document.id);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -69,10 +68,14 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
final updatedDocument = widget.document.copyWith(
|
||||
title: values[fkTitle],
|
||||
created: values[fkCreatedDate],
|
||||
documentType: values[fkDocumentType] as IdQueryParameter,
|
||||
correspondent: values[fkCorrespondent] as IdQueryParameter,
|
||||
storagePath: values[fkStoragePath] as IdQueryParameter,
|
||||
tags: values[fkTags] as TagsQuery,
|
||||
overwriteDocumentType: true,
|
||||
documentType: (values[fkDocumentType] as IdQueryParameter).id,
|
||||
overwriteCorrespondent: true,
|
||||
correspondent: (values[fkCorrespondent] as IdQueryParameter).id,
|
||||
overwriteStoragePath: true,
|
||||
storagePath: (values[fkStoragePath] as IdQueryParameter).id,
|
||||
overwriteTags: true,
|
||||
tags: (values[fkTags] as IdsTagsQuery).includedIds,
|
||||
);
|
||||
setState(() {
|
||||
_isSubmitLoading = true;
|
||||
@@ -181,7 +184,10 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
},
|
||||
).padded(),
|
||||
TagFormField(
|
||||
initialValue: TagsQuery.fromIds(widget.document.tags),
|
||||
initialValue: IdsTagsQuery.included(widget.document.tags),
|
||||
notAssignedSelectable: false,
|
||||
anyAssignedSelectable: false,
|
||||
excludeAllowed: false,
|
||||
name: fkTags,
|
||||
).padded(),
|
||||
]),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/document.model.dart';
|
||||
@@ -6,11 +7,11 @@ import 'package:paperless_mobile/generated/l10n.dart';
|
||||
import 'package:pdfx/pdfx.dart';
|
||||
|
||||
class DocumentView extends StatefulWidget {
|
||||
final DocumentModel document;
|
||||
final Future<Uint8List> documentBytes;
|
||||
|
||||
const DocumentView({
|
||||
Key? key,
|
||||
required this.document,
|
||||
required this.documentBytes,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -25,7 +26,7 @@ class _DocumentViewState extends State<DocumentView> {
|
||||
super.initState();
|
||||
_pdfController = PdfController(
|
||||
document: PdfDocument.openData(
|
||||
getIt<DocumentRepository>().getPreview(widget.document.id),
|
||||
widget.documentBytes,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,8 +66,12 @@ class DocumentGridItem extends StatelessWidget {
|
||||
tagIds: document.tags,
|
||||
isMultiLine: false,
|
||||
),
|
||||
Text(DateFormat.yMMMd(Intl.getCurrentLocale())
|
||||
.format(document.created)),
|
||||
const Spacer(),
|
||||
Text(
|
||||
DateFormat.yMMMd(Intl.getCurrentLocale())
|
||||
.format(document.created),
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -11,7 +11,6 @@ import 'package:paperless_mobile/features/documents/model/document_filter.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/query_parameters/query_type.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/search/query_type_form_field.dart';
|
||||
@@ -89,8 +88,7 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
builder: (context, state) {
|
||||
return FormBuilder(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
controller: widget.scrollController,
|
||||
child: Column(
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
@@ -127,28 +125,43 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(S.of(context).documentsFilterPageSearchLabel),
|
||||
).padded(const EdgeInsets.only(left: 8.0)),
|
||||
_buildQueryFormField(state),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(S.of(context).documentsFilterPageAdvancedLabel),
|
||||
).padded(const EdgeInsets.only(left: 8.0, top: 8.0)),
|
||||
_buildCreatedDateRangePickerFormField(state).padded(),
|
||||
_buildAddedDateRangePickerFormField(state).padded(),
|
||||
_buildCorrespondentFormField(state).padded(),
|
||||
_buildDocumentTypeFormField(state).padded(),
|
||||
_buildStoragePathFormField(state).padded(),
|
||||
TagFormField(
|
||||
name: DocumentModel.tagsKey,
|
||||
initialValue: state.filter.tags,
|
||||
allowCreation: false,
|
||||
).padded(),
|
||||
// Required in order for the storage path field to be visible when typing
|
||||
const SizedBox(
|
||||
height: 200,
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
),
|
||||
child: ListView(
|
||||
controller: widget.scrollController,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
S.of(context).documentsFilterPageSearchLabel),
|
||||
).padded(const EdgeInsets.only(left: 8.0)),
|
||||
_buildQueryFormField(state),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
S.of(context).documentsFilterPageAdvancedLabel),
|
||||
).padded(const EdgeInsets.only(left: 8.0, top: 8.0)),
|
||||
_buildCreatedDateRangePickerFormField(state).padded(),
|
||||
_buildAddedDateRangePickerFormField(state).padded(),
|
||||
_buildCorrespondentFormField(state).padded(),
|
||||
_buildDocumentTypeFormField(state).padded(),
|
||||
_buildStoragePathFormField(state).padded(),
|
||||
TagFormField(
|
||||
name: DocumentModel.tagsKey,
|
||||
initialValue: state.filter.tags,
|
||||
allowCreation: false,
|
||||
).padded(),
|
||||
// Required in order for the storage path field to be visible when typing
|
||||
const SizedBox(
|
||||
height: 150,
|
||||
),
|
||||
],
|
||||
).padded(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -374,6 +387,7 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4.0),
|
||||
_buildDateRangePickerHelper(state, fkCreatedAt),
|
||||
],
|
||||
);
|
||||
@@ -421,6 +435,7 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4.0),
|
||||
_buildDateRangePickerHelper(state, fkAddedAt),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -44,9 +44,10 @@ class _SortFieldSelectionBottomSheetState
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).documentsPageOrderByLabel,
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
textAlign: TextAlign.start,
|
||||
).padded(EdgeInsets.symmetric(horizontal: 16, vertical: 16)),
|
||||
).padded(
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 16)),
|
||||
Column(
|
||||
children: _sortFields
|
||||
.map(
|
||||
@@ -110,9 +111,9 @@ class _SortFieldSelectionBottomSheetState
|
||||
|
||||
Widget _buildOrderIcon(SortOrder order) {
|
||||
if (order == SortOrder.ascending) {
|
||||
return Icon(Icons.arrow_upward);
|
||||
return const Icon(Icons.arrow_upward);
|
||||
}
|
||||
return Icon(Icons.arrow_downward);
|
||||
return const Icon(Icons.arrow_downward);
|
||||
}
|
||||
|
||||
String _localizedSortField(SortField sortField) {
|
||||
|
||||
@@ -18,10 +18,10 @@ class ConfirmDeleteSavedViewDialog extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
"Delete view " + view.name + "?",
|
||||
S.of(context).deleteViewDialogTitleText + view.name + "?",
|
||||
softWrap: true,
|
||||
),
|
||||
content: Text("Do you really want to delete this view?"),
|
||||
content: Text(S.of(context).deleteViewDialogContentText),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(S.of(context).genericActionCancelLabel),
|
||||
|
||||
@@ -77,7 +77,7 @@ class _DocumentsPageAppBarState extends State<DocumentsPageAppBar> {
|
||||
Widget _buildFlexibleArea(bool enabled) {
|
||||
return FlexibleSpaceBar(
|
||||
background: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
|
||||
@@ -27,7 +27,7 @@ class _SortDocumentsButtonState extends State<SortDocumentsButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
icon: Icon(Icons.sort),
|
||||
icon: const Icon(Icons.sort),
|
||||
onPressed: _onOpenSortBottomSheet,
|
||||
);
|
||||
}
|
||||
@@ -45,9 +45,9 @@ class _SortDocumentsButtonState extends State<SortDocumentsButton> {
|
||||
),
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: getIt<DocumentsCubit>(),
|
||||
child: FractionallySizedBox(
|
||||
child: const FractionallySizedBox(
|
||||
heightFactor: .6,
|
||||
child: const SortFieldSelectionBottomSheet(),
|
||||
child: SortFieldSelectionBottomSheet(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user