Added new query options for tags, added pdf preview on documents scanner page

This commit is contained in:
Anton Stubenbord
2022-11-18 00:59:14 +01:00
parent e9019bca9c
commit 070a57aafd
32 changed files with 454 additions and 205 deletions

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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);
}
}