mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-07 22:07:49 -06:00
Add migration scripts, remove dependencies to codegen, and cleanups
This commit is contained in:
@@ -19,6 +19,14 @@ class HiveBoxes {
|
|||||||
static const localUserAccount = 'localUserAccount';
|
static const localUserAccount = 'localUserAccount';
|
||||||
static const localUserAppState = 'localUserAppState';
|
static const localUserAppState = 'localUserAppState';
|
||||||
static const hosts = 'hosts';
|
static const hosts = 'hosts';
|
||||||
|
|
||||||
|
static List<String> get all => [
|
||||||
|
globalSettings,
|
||||||
|
localUserCredentials,
|
||||||
|
localUserAccount,
|
||||||
|
localUserAppState,
|
||||||
|
hosts,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class HiveTypeIds {
|
class HiveTypeIds {
|
||||||
|
|||||||
@@ -200,19 +200,13 @@ class LabelRepository extends PersistentRepository<LabelRepositoryState> {
|
|||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Future<void> clear() async {
|
// LabelRepositoryState? fromJson(Map<String, dynamic> json) {
|
||||||
await super.clear();
|
// return LabelRepositoryState.fromJson(json);
|
||||||
emit(const LabelRepositoryState());
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
LabelRepositoryState? fromJson(Map<String, dynamic> json) {
|
// Map<String, dynamic>? toJson(LabelRepositoryState state) {
|
||||||
return LabelRepositoryState.fromJson(json);
|
// return state.toJson();
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic>? toJson(LabelRepositoryState state) {
|
|
||||||
return state.toJson();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||||
|
|
||||||
abstract class PersistentRepository<T> extends HydratedCubit<T> {
|
abstract class PersistentRepository<T> extends Cubit<T> {
|
||||||
final Map<Object, StreamSubscription> _subscribers = {};
|
final Map<Object, StreamSubscription> _subscribers = {};
|
||||||
|
|
||||||
PersistentRepository(T initialState) : super(initialState);
|
PersistentRepository(T initialState) : super(initialState);
|
||||||
|
|||||||
@@ -76,20 +76,20 @@ class SavedViewRepository
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Future<void> clear() async {
|
// Future<void> clear() async {
|
||||||
await _initialized.future;
|
// await _initialized.future;
|
||||||
await super.clear();
|
// await super.clear();
|
||||||
emit(const SavedViewRepositoryState.initial());
|
// emit(const SavedViewRepositoryState.initial());
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
SavedViewRepositoryState? fromJson(Map<String, dynamic> json) {
|
// SavedViewRepositoryState? fromJson(Map<String, dynamic> json) {
|
||||||
return SavedViewRepositoryState.fromJson(json);
|
// return SavedViewRepositoryState.fromJson(json);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Map<String, dynamic>? toJson(SavedViewRepositoryState state) {
|
// Map<String, dynamic>? toJson(SavedViewRepositoryState state) {
|
||||||
return state.toJson();
|
// return state.toJson();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
part of 'saved_view_repository.dart';
|
part of 'saved_view_repository.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SavedViewRepositoryState with _$SavedViewRepositoryState {
|
class SavedViewRepositoryState with _$SavedViewRepositoryState {
|
||||||
const factory SavedViewRepositoryState.initial({
|
const factory SavedViewRepositoryState.initial({
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
||||||
|
|
||||||
part 'user_repository_state.dart';
|
part 'user_repository_state.dart';
|
||||||
part 'user_repository.freezed.dart';
|
|
||||||
part 'user_repository.g.dart';
|
|
||||||
|
|
||||||
/// Repository for new users (API v3, server version 1.14.2+)
|
/// Repository for new users (API v3, server version 1.14.2+)
|
||||||
class UserRepository extends PersistentRepository<UserRepositoryState> {
|
class UserRepository extends PersistentRepository<UserRepositoryState> {
|
||||||
@@ -28,13 +27,13 @@ class UserRepository extends PersistentRepository<UserRepositoryState> {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
UserRepositoryState? fromJson(Map<String, dynamic> json) {
|
// UserRepositoryState? fromJson(Map<String, dynamic> json) {
|
||||||
return UserRepositoryState.fromJson(json);
|
// return UserRepositoryState.fromJson(json);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Map<String, dynamic>? toJson(UserRepositoryState state) {
|
// Map<String, dynamic>? toJson(UserRepositoryState state) {
|
||||||
return state.toJson();
|
// return state.toJson();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
part of 'user_repository.dart';
|
part of 'user_repository.dart';
|
||||||
|
|
||||||
@freezed
|
class UserRepositoryState with EquatableMixin {
|
||||||
class UserRepositoryState with _$UserRepositoryState {
|
final Map<int, UserModel> users;
|
||||||
const factory UserRepositoryState({
|
const UserRepositoryState({
|
||||||
@Default({}) Map<int, UserModel> users,
|
this.users = const {},
|
||||||
}) = _UserRepositoryState;
|
});
|
||||||
|
|
||||||
factory UserRepositoryState.fromJson(Map<String, dynamic> json) =>
|
UserRepositoryState copyWith({
|
||||||
_$UserRepositoryStateFromJson(json);
|
Map<int, UserModel>? users,
|
||||||
|
}) {
|
||||||
|
return UserRepositoryState(
|
||||||
|
users: users ?? this.users,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [users];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,11 +109,12 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
.watch<DocumentEditCubit>()
|
.watch<DocumentEditCubit>()
|
||||||
.state
|
.state
|
||||||
.correspondents,
|
.correspondents,
|
||||||
initialValue:
|
initialValue: state
|
||||||
state.document.correspondent != null
|
.document.correspondent !=
|
||||||
? IdQueryParameter.fromId(
|
null
|
||||||
state.document.correspondent!)
|
? SetIdQueryParameter(
|
||||||
: const IdQueryParameter.unset(),
|
id: state.document.correspondent!)
|
||||||
|
: const UnsetIdQueryParameter(),
|
||||||
name: fkCorrespondent,
|
name: fkCorrespondent,
|
||||||
prefixIcon:
|
prefixIcon:
|
||||||
const Icon(Icons.person_outlined),
|
const Icon(Icons.person_outlined),
|
||||||
@@ -135,7 +136,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
_formKey.currentState
|
_formKey.currentState
|
||||||
?.fields[fkCorrespondent]
|
?.fields[fkCorrespondent]
|
||||||
?.didChange(
|
?.didChange(
|
||||||
IdQueryParameter.fromId(itemData),
|
SetIdQueryParameter(id: itemData),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -161,11 +162,11 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
addLabelText:
|
addLabelText:
|
||||||
S.of(context)!.addDocumentType,
|
S.of(context)!.addDocumentType,
|
||||||
labelText: S.of(context)!.documentType,
|
labelText: S.of(context)!.documentType,
|
||||||
initialValue:
|
initialValue: state.document.documentType !=
|
||||||
state.document.documentType != null
|
null
|
||||||
? IdQueryParameter.fromId(
|
? SetIdQueryParameter(
|
||||||
state.document.documentType!)
|
id: state.document.documentType!)
|
||||||
: const IdQueryParameter.unset(),
|
: const UnsetIdQueryParameter(),
|
||||||
options: state.documentTypes,
|
options: state.documentTypes,
|
||||||
name: _DocumentEditPageState.fkDocumentType,
|
name: _DocumentEditPageState.fkDocumentType,
|
||||||
prefixIcon:
|
prefixIcon:
|
||||||
@@ -185,7 +186,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
onPressed: () => _formKey.currentState
|
onPressed: () => _formKey.currentState
|
||||||
?.fields[fkDocumentType]
|
?.fields[fkDocumentType]
|
||||||
?.didChange(
|
?.didChange(
|
||||||
IdQueryParameter.fromId(itemData),
|
SetIdQueryParameter(id: itemData),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -211,9 +212,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
options: state.storagePaths,
|
options: state.storagePaths,
|
||||||
initialValue:
|
initialValue:
|
||||||
state.document.storagePath != null
|
state.document.storagePath != null
|
||||||
? IdQueryParameter.fromId(
|
? SetIdQueryParameter(
|
||||||
state.document.storagePath!)
|
id: state.document.storagePath!)
|
||||||
: const IdQueryParameter.unset(),
|
: const UnsetIdQueryParameter(),
|
||||||
name: fkStoragePath,
|
name: fkStoragePath,
|
||||||
prefixIcon:
|
prefixIcon:
|
||||||
const Icon(Icons.folder_outlined),
|
const Icon(Icons.folder_outlined),
|
||||||
@@ -229,7 +230,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
allowOnlySelection: true,
|
allowOnlySelection: true,
|
||||||
allowCreation: true,
|
allowCreation: true,
|
||||||
allowExclude: false,
|
allowExclude: false,
|
||||||
initialValue: TagsQuery.ids(
|
initialValue: IdsTagsQuery(
|
||||||
include: state.document.tags.toList(),
|
include: state.document.tags.toList(),
|
||||||
),
|
),
|
||||||
).padded(),
|
).padded(),
|
||||||
@@ -254,15 +255,17 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
?.fields[fkTags]?.value as TagsQuery;
|
?.fields[fkTags]?.value as TagsQuery;
|
||||||
_formKey.currentState?.fields[fkTags]
|
_formKey.currentState?.fields[fkTags]
|
||||||
?.didChange(
|
?.didChange(
|
||||||
currentTags.maybeWhen(
|
switch (currentTags) {
|
||||||
ids: (include, exclude) =>
|
IdsTagsQuery(
|
||||||
TagsQuery.ids(include: [
|
include: var i,
|
||||||
...include,
|
exclude: var e
|
||||||
itemData
|
) =>
|
||||||
], exclude: exclude),
|
IdsTagsQuery(
|
||||||
orElse: () => TagsQuery.ids(
|
include: [...i, itemData],
|
||||||
include: [itemData]),
|
exclude: e,
|
||||||
),
|
),
|
||||||
|
_ => IdsTagsQuery(include: [itemData])
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -301,16 +304,35 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
Future<void> _onSubmit(DocumentModel document) async {
|
Future<void> _onSubmit(DocumentModel document) async {
|
||||||
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
||||||
final values = _formKey.currentState!.value;
|
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(
|
var mergedDocument = document.copyWith(
|
||||||
title: values[fkTitle],
|
title: values[fkTitle],
|
||||||
created: values[fkCreatedDate],
|
created: values[fkCreatedDate],
|
||||||
documentType: () => (values[fkDocumentType] as IdQueryParameter?)
|
correspondent: () => correspondent,
|
||||||
?.whenOrNull(fromId: (id) => id),
|
documentType: () => documentType,
|
||||||
correspondent: () => (values[fkCorrespondent] as IdQueryParameter?)
|
storagePath: () => storagePath,
|
||||||
?.whenOrNull(fromId: (id) => id),
|
tags: tags,
|
||||||
storagePath: () => (values[fkStoragePath] as IdQueryParameter?)
|
|
||||||
?.whenOrNull(fromId: (id) => id),
|
|
||||||
tags: (values[fkTags] as IdsTagsQuery?)?.include,
|
|
||||||
content: values[fkContent],
|
content: values[fkContent],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -344,20 +344,29 @@ class _DocumentUploadPreparationPageState
|
|||||||
final cubit = context.read<DocumentUploadCubit>();
|
final cubit = context.read<DocumentUploadCubit>();
|
||||||
try {
|
try {
|
||||||
setState(() => _isUploadLoading = true);
|
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 asn = formValues[DocumentModel.asnKey] as int?;
|
||||||
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 taskId = await cubit.upload(
|
final taskId = await cubit.upload(
|
||||||
await widget.fileBytes,
|
await widget.fileBytes,
|
||||||
filename: _padWithExtension(
|
filename: _padWithExtension(
|
||||||
|
|||||||
@@ -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/paged_document_view/cubit/paged_documents_state.dart';
|
||||||
import 'package:paperless_mobile/features/settings/model/view_type.dart';
|
import 'package:paperless_mobile/features/settings/model/view_type.dart';
|
||||||
|
|
||||||
part 'documents_cubit.g.dart';
|
|
||||||
part 'documents_state.dart';
|
part 'documents_state.dart';
|
||||||
|
|
||||||
class DocumentsCubit extends HydratedCubit<DocumentsState>
|
class DocumentsCubit extends Cubit<DocumentsState>
|
||||||
with DocumentPagingBlocMixin {
|
with DocumentPagingBlocMixin {
|
||||||
@override
|
@override
|
||||||
final PaperlessDocumentsApi api;
|
final PaperlessDocumentsApi api;
|
||||||
@@ -135,13 +134,13 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
|||||||
await _userState.save();
|
await _userState.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
DocumentsState? fromJson(Map<String, dynamic> json) {
|
// DocumentsState? fromJson(Map<String, dynamic> json) {
|
||||||
return DocumentsState.fromJson(json);
|
// return DocumentsState.fromJson(json);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Map<String, dynamic>? toJson(DocumentsState state) {
|
// Map<String, dynamic>? toJson(DocumentsState state) {
|
||||||
return state.toJson();
|
// return state.toJson();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
part of 'documents_cubit.dart';
|
part of 'documents_cubit.dart';
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class DocumentsState extends DocumentPagingState {
|
class DocumentsState extends DocumentPagingState {
|
||||||
@JsonKey(includeToJson: false, includeFromJson: false)
|
|
||||||
final List<DocumentModel> selection;
|
final List<DocumentModel> selection;
|
||||||
|
|
||||||
@JsonKey(includeToJson: false, includeFromJson: false)
|
|
||||||
final Map<int, Correspondent> correspondents;
|
final Map<int, Correspondent> correspondents;
|
||||||
@JsonKey(includeToJson: false, includeFromJson: false)
|
|
||||||
final Map<int, DocumentType> documentTypes;
|
final Map<int, DocumentType> documentTypes;
|
||||||
@JsonKey(includeToJson: false, includeFromJson: false)
|
|
||||||
final Map<int, Tag> tags;
|
final Map<int, Tag> tags;
|
||||||
@JsonKey(includeToJson: false, includeFromJson: false)
|
|
||||||
final Map<int, StoragePath> storagePaths;
|
final Map<int, StoragePath> storagePaths;
|
||||||
|
|
||||||
final ViewType viewType;
|
final ViewType viewType;
|
||||||
@@ -85,9 +78,4 @@ class DocumentsState extends DocumentPagingState {
|
|||||||
value: value,
|
value: value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory DocumentsState.fromJson(Map<String, dynamic> json) =>
|
|
||||||
_$DocumentsStateFromJson(json);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$DocumentsStateToJson(this);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,7 +252,8 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
|||||||
cubit.resetSelection();
|
cubit.resetSelection();
|
||||||
return false;
|
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();
|
await _onResetFilter();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -512,8 +513,8 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
|||||||
void _addTagToFilter(int tagId) {
|
void _addTagToFilter(int tagId) {
|
||||||
final cubit = context.read<DocumentsCubit>();
|
final cubit = context.read<DocumentsCubit>();
|
||||||
try {
|
try {
|
||||||
cubit.state.filter.tags.maybeMap(
|
switch (cubit.state.filter.tags) {
|
||||||
ids: (state) {
|
case IdsTagsQuery state:
|
||||||
if (state.include.contains(tagId)) {
|
if (state.include.contains(tagId)) {
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) => filter.copyWith(
|
(filter) => filter.copyWith(
|
||||||
@@ -541,13 +542,13 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
break;
|
||||||
orElse: () {
|
default:
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) => filter.copyWith(tags: TagsQuery.ids(include: [tagId])),
|
(filter) => filter.copyWith(tags: IdsTagsQuery(include: [tagId])),
|
||||||
);
|
);
|
||||||
},
|
break;
|
||||||
);
|
}
|
||||||
} on PaperlessApiException catch (error, stackTrace) {
|
} on PaperlessApiException catch (error, stackTrace) {
|
||||||
showErrorMessage(context, error, stackTrace);
|
showErrorMessage(context, error, stackTrace);
|
||||||
}
|
}
|
||||||
@@ -558,27 +559,26 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
|||||||
final cubit = context.read<DocumentsCubit>();
|
final cubit = context.read<DocumentsCubit>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cubit.state.filter.correspondent.maybeWhen(
|
switch (cubit.state.filter.correspondent) {
|
||||||
fromId: (id) {
|
case SetIdQueryParameter(id: var id):
|
||||||
if (id == correspondentId) {
|
if (id == correspondentId) {
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) => filter.copyWith(
|
(filter) =>
|
||||||
correspondent: const IdQueryParameter.unset()),
|
filter.copyWith(correspondent: const UnsetIdQueryParameter()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) => filter.copyWith(
|
(filter) => filter.copyWith(
|
||||||
correspondent: IdQueryParameter.fromId(correspondentId)),
|
correspondent: SetIdQueryParameter(id: correspondentId)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
break;
|
||||||
orElse: () {
|
default:
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter((filter) => filter.copyWith(
|
||||||
(filter) => filter.copyWith(
|
correspondent: SetIdQueryParameter(id: correspondentId),
|
||||||
correspondent: IdQueryParameter.fromId(correspondentId)),
|
));
|
||||||
);
|
break;
|
||||||
},
|
}
|
||||||
);
|
|
||||||
} on PaperlessApiException catch (error, stackTrace) {
|
} on PaperlessApiException catch (error, stackTrace) {
|
||||||
showErrorMessage(context, error, stackTrace);
|
showErrorMessage(context, error, stackTrace);
|
||||||
}
|
}
|
||||||
@@ -589,27 +589,27 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
|||||||
final cubit = context.read<DocumentsCubit>();
|
final cubit = context.read<DocumentsCubit>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cubit.state.filter.documentType.maybeWhen(
|
switch (cubit.state.filter.documentType) {
|
||||||
fromId: (id) {
|
case SetIdQueryParameter(id: var id):
|
||||||
if (id == documentTypeId) {
|
if (id == documentTypeId) {
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) =>
|
(filter) =>
|
||||||
filter.copyWith(documentType: const IdQueryParameter.unset()),
|
filter.copyWith(documentType: const UnsetIdQueryParameter()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) => filter.copyWith(
|
(filter) => filter.copyWith(
|
||||||
documentType: IdQueryParameter.fromId(documentTypeId)),
|
documentType: SetIdQueryParameter(id: documentTypeId)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
break;
|
||||||
orElse: () {
|
default:
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) => filter.copyWith(
|
(filter) => filter.copyWith(
|
||||||
documentType: IdQueryParameter.fromId(documentTypeId)),
|
documentType: SetIdQueryParameter(id: documentTypeId)),
|
||||||
);
|
);
|
||||||
},
|
break;
|
||||||
);
|
}
|
||||||
} on PaperlessApiException catch (error, stackTrace) {
|
} on PaperlessApiException catch (error, stackTrace) {
|
||||||
showErrorMessage(context, error, stackTrace);
|
showErrorMessage(context, error, stackTrace);
|
||||||
}
|
}
|
||||||
@@ -620,27 +620,28 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
|||||||
final cubit = context.read<DocumentsCubit>();
|
final cubit = context.read<DocumentsCubit>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cubit.state.filter.storagePath.maybeWhen(
|
switch (cubit.state.filter.storagePath){
|
||||||
fromId: (id) {
|
case SetIdQueryParameter(id: var id):
|
||||||
if (id == pathId) {
|
if (id == pathId) {
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) =>
|
(filter) =>
|
||||||
filter.copyWith(storagePath: const IdQueryParameter.unset()),
|
filter.copyWith(storagePath: const UnsetIdQueryParameter()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) =>
|
(filter) =>
|
||||||
filter.copyWith(storagePath: IdQueryParameter.fromId(pathId)),
|
filter.copyWith(storagePath: SetIdQueryParameter(id: pathId)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
break;
|
||||||
orElse: () {
|
default:
|
||||||
cubit.updateCurrentFilter(
|
cubit.updateCurrentFilter(
|
||||||
(filter) =>
|
(filter) =>
|
||||||
filter.copyWith(storagePath: IdQueryParameter.fromId(pathId)),
|
filter.copyWith(storagePath: SetIdQueryParameter(id: pathId)),
|
||||||
);
|
);
|
||||||
},
|
break;
|
||||||
);
|
}
|
||||||
|
|
||||||
} on PaperlessApiException catch (error, stackTrace) {
|
} on PaperlessApiException catch (error, stackTrace) {
|
||||||
showErrorMessage(context, error, stackTrace);
|
showErrorMessage(context, error, stackTrace);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class InboxCubit extends HydratedCubit<InboxState>
|
|||||||
updateFilter(
|
updateFilter(
|
||||||
filter: DocumentFilter(
|
filter: DocumentFilter(
|
||||||
sortField: SortField.added,
|
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,
|
emitLoading: false,
|
||||||
filter: DocumentFilter(
|
filter: DocumentFilter(
|
||||||
sortField: SortField.added,
|
sortField: SortField.added,
|
||||||
tags: TagsQuery.ids(include: inboxTags.toList()),
|
tags: IdsTagsQuery(include: inboxTags.toList()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,16 +116,16 @@ class _FullscreenTagsFormState extends State<FullscreenTagsForm> {
|
|||||||
icon: const Icon(Icons.done),
|
icon: const Icon(Icons.done),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (widget.allowOnlySelection) {
|
if (widget.allowOnlySelection) {
|
||||||
widget.onSubmit(returnValue: TagsQuery.ids(include: _include));
|
widget.onSubmit(returnValue: IdsTagsQuery(include: _include));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
late final TagsQuery query;
|
late final TagsQuery query;
|
||||||
if (_notAssigned) {
|
if (_notAssigned) {
|
||||||
query = const TagsQuery.notAssigned();
|
query = const NotAssignedTagsQuery();
|
||||||
} else if (_anyAssigned) {
|
} else if (_anyAssigned) {
|
||||||
query = TagsQuery.anyAssigned(tagIds: _include);
|
query = AnyAssignedTagsQuery(tagIds: _include);
|
||||||
} else {
|
} else {
|
||||||
query = TagsQuery.ids(include: _include, exclude: _exclude);
|
query = IdsTagsQuery(include: _include, exclude: _exclude);
|
||||||
}
|
}
|
||||||
widget.onSubmit(returnValue: query);
|
widget.onSubmit(returnValue: query);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -96,19 +96,17 @@ class TagsFormField extends StatelessWidget {
|
|||||||
if (query == null) {
|
if (query == null) {
|
||||||
yield Container();
|
yield Container();
|
||||||
} else {
|
} else {
|
||||||
final widgets = query.map(
|
final widgets = switch (query) {
|
||||||
ids: (value) => [
|
IdsTagsQuery(include: var inc, exclude: var exc) => [
|
||||||
for (var inc in value.include)
|
for (var i in inc) _buildTagIdQueryWidget(context, i, field, false),
|
||||||
_buildTagIdQueryWidget(context, inc, field, false),
|
for (var e in exc) _buildTagIdQueryWidget(context, e, field, true),
|
||||||
for (var exc in value.exclude)
|
],
|
||||||
_buildTagIdQueryWidget(context, exc, field, true),
|
AnyAssignedTagsQuery query => [
|
||||||
],
|
for (var id in query.tagIds)
|
||||||
anyAssigned: (value) => [
|
_buildAnyAssignedTagWidget(context, id, field, query),
|
||||||
for (var id in value.tagIds)
|
],
|
||||||
_buildAnyAssignedTagWidget(context, id, field, value),
|
NotAssignedTagsQuery() => [_buildNotAssignedTagWidget(context, field)],
|
||||||
],
|
};
|
||||||
notAssigned: (value) => [_buildNotAssignedTagWidget(context, field)],
|
|
||||||
);
|
|
||||||
for (var child in widgets) {
|
for (var child in widgets) {
|
||||||
yield child;
|
yield child;
|
||||||
}
|
}
|
||||||
@@ -185,7 +183,7 @@ class TagsFormField extends StatelessWidget {
|
|||||||
tagIds: query.tagIds.whereNot((element) => element == e).toList(),
|
tagIds: query.tagIds.whereNot((element) => element == e).toList(),
|
||||||
);
|
);
|
||||||
if (updatedQuery.tagIds.isEmpty) {
|
if (updatedQuery.tagIds.isEmpty) {
|
||||||
field.didChange(const TagsQuery.ids());
|
field.didChange(const IdsTagsQuery());
|
||||||
} else {
|
} else {
|
||||||
field.didChange(updatedQuery);
|
field.didChange(updatedQuery);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ class _LabelsPageState extends State<LabelsPage>
|
|||||||
LabelTabView<Correspondent>(
|
LabelTabView<Correspondent>(
|
||||||
labels: state.correspondents,
|
labels: state.correspondents,
|
||||||
filterBuilder: (label) => DocumentFilter(
|
filterBuilder: (label) => DocumentFilter(
|
||||||
correspondent: IdQueryParameter.fromId(label.id!),
|
correspondent: SetIdQueryParameter(id: label.id!),
|
||||||
),
|
),
|
||||||
canEdit: user.canEditCorrespondents,
|
canEdit: user.canEditCorrespondents,
|
||||||
canAddNew: user.canCreateCorrespondents,
|
canAddNew: user.canCreateCorrespondents,
|
||||||
@@ -287,7 +287,7 @@ class _LabelsPageState extends State<LabelsPage>
|
|||||||
LabelTabView<DocumentType>(
|
LabelTabView<DocumentType>(
|
||||||
labels: state.documentTypes,
|
labels: state.documentTypes,
|
||||||
filterBuilder: (label) => DocumentFilter(
|
filterBuilder: (label) => DocumentFilter(
|
||||||
documentType: IdQueryParameter.fromId(label.id!),
|
documentType: SetIdQueryParameter(id: label.id!),
|
||||||
),
|
),
|
||||||
canEdit: user.canEditDocumentTypes,
|
canEdit: user.canEditDocumentTypes,
|
||||||
canAddNew: user.canCreateDocumentTypes,
|
canAddNew: user.canCreateDocumentTypes,
|
||||||
@@ -315,7 +315,7 @@ class _LabelsPageState extends State<LabelsPage>
|
|||||||
LabelTabView<Tag>(
|
LabelTabView<Tag>(
|
||||||
labels: state.tags,
|
labels: state.tags,
|
||||||
filterBuilder: (label) => DocumentFilter(
|
filterBuilder: (label) => DocumentFilter(
|
||||||
tags: TagsQuery.ids(include: [label.id!]),
|
tags: IdsTagsQuery(include: [label.id!]),
|
||||||
),
|
),
|
||||||
canEdit: user.canEditTags,
|
canEdit: user.canEditTags,
|
||||||
canAddNew: user.canCreateTags,
|
canAddNew: user.canCreateTags,
|
||||||
@@ -354,7 +354,7 @@ class _LabelsPageState extends State<LabelsPage>
|
|||||||
EditLabelRoute(label).push(context);
|
EditLabelRoute(label).push(context);
|
||||||
},
|
},
|
||||||
filterBuilder: (label) => DocumentFilter(
|
filterBuilder: (label) => DocumentFilter(
|
||||||
storagePath: IdQueryParameter.fromId(label.id!),
|
storagePath: SetIdQueryParameter(id: label.id!),
|
||||||
),
|
),
|
||||||
canEdit: user.canEditStoragePaths,
|
canEdit: user.canEditStoragePaths,
|
||||||
canAddNew: user.canCreateStoragePaths,
|
canAddNew: user.canCreateStoragePaths,
|
||||||
|
|||||||
@@ -32,11 +32,10 @@ class FullscreenLabelForm<T extends Label> extends StatefulWidget {
|
|||||||
this.allowSelectUnassigned = true,
|
this.allowSelectUnassigned = true,
|
||||||
required this.canCreateNewLabel,
|
required this.canCreateNewLabel,
|
||||||
}) : assert(
|
}) : assert(
|
||||||
!(initialValue?.isOnlyAssigned() ?? false) || showAnyAssignedOption,
|
!(initialValue?.isOnlyAssigned ?? false) || showAnyAssignedOption,
|
||||||
),
|
),
|
||||||
assert(
|
assert(
|
||||||
!(initialValue?.isOnlyNotAssigned() ?? false) ||
|
!(initialValue?.isOnlyNotAssigned ?? false) || showNotAssignedOption,
|
||||||
showNotAssignedOption,
|
|
||||||
),
|
),
|
||||||
assert((addNewLabelText != null) == (onCreateNewLabel != null));
|
assert((addNewLabelText != null) == (onCreateNewLabel != null));
|
||||||
|
|
||||||
@@ -87,11 +86,10 @@ class _FullscreenLabelFormState<T extends Label>
|
|||||||
final index = AutocompleteHighlightedOption.of(context);
|
final index = AutocompleteHighlightedOption.of(context);
|
||||||
final value = index.isNegative ? null : options.elementAt(index);
|
final value = index.isNegative ? null : options.elementAt(index);
|
||||||
widget.onSubmit(
|
widget.onSubmit(
|
||||||
returnValue: value?.maybeWhen(
|
returnValue: switch (value) {
|
||||||
fromId: (id) => IdQueryParameter.fromId(id),
|
SetIdQueryParameter query => query,
|
||||||
orElse: () => const IdQueryParameter.unset(),
|
_ => const UnsetIdQueryParameter(),
|
||||||
) ??
|
},
|
||||||
const IdQueryParameter.unset(),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
@@ -169,7 +167,7 @@ class _FullscreenLabelFormState<T extends Label>
|
|||||||
final label = await widget.onCreateNewLabel!(_textEditingController.text);
|
final label = await widget.onCreateNewLabel!(_textEditingController.text);
|
||||||
if (label?.id != null) {
|
if (label?.id != null) {
|
||||||
widget.onSubmit(
|
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 (widget.initialValue == null) {
|
||||||
// If nothing is selected yet, show all options first.
|
// If nothing is selected yet, show all options first.
|
||||||
for (final option in widget.options.values) {
|
for (final option in widget.options.values) {
|
||||||
yield IdQueryParameter.fromId(option.id!);
|
yield SetIdQueryParameter(id: option.id!);
|
||||||
}
|
}
|
||||||
if (widget.showNotAssignedOption) {
|
if (widget.showNotAssignedOption) {
|
||||||
yield const IdQueryParameter.notAssigned();
|
yield const NotAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
if (widget.showAnyAssignedOption) {
|
if (widget.showAnyAssignedOption) {
|
||||||
yield const IdQueryParameter.anyAssigned();
|
yield const AnyAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If an initial value is given, show not assigned first, which will be selected by default when pressing "done" on keyboard.
|
// If an initial value is given, show not assigned first, which will be selected by default when pressing "done" on keyboard.
|
||||||
if (widget.showNotAssignedOption) {
|
if (widget.showNotAssignedOption) {
|
||||||
yield const IdQueryParameter.notAssigned();
|
yield const NotAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
if (widget.showAnyAssignedOption) {
|
if (widget.showAnyAssignedOption) {
|
||||||
yield const IdQueryParameter.anyAssigned();
|
yield const AnyAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
for (final option in widget.options.values) {
|
for (final option in widget.options.values) {
|
||||||
// Don't include the initial value in the selection
|
// Don't include the initial value in the selection
|
||||||
@@ -207,7 +205,7 @@ class _FullscreenLabelFormState<T extends Label>
|
|||||||
option.id == initialValue.id) {
|
option.id == initialValue.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
yield IdQueryParameter.fromId(option.id!);
|
yield SetIdQueryParameter(id: option.id!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -216,77 +214,76 @@ class _FullscreenLabelFormState<T extends Label>
|
|||||||
.where((e) => e.name.trim().toLowerCase().contains(normalizedQuery));
|
.where((e) => e.name.trim().toLowerCase().contains(normalizedQuery));
|
||||||
if (matches.isNotEmpty) {
|
if (matches.isNotEmpty) {
|
||||||
for (final match in matches) {
|
for (final match in matches) {
|
||||||
yield IdQueryParameter.fromId(match.id!);
|
yield SetIdQueryParameter(id: match.id!);
|
||||||
}
|
}
|
||||||
if (widget.showNotAssignedOption) {
|
if (widget.showNotAssignedOption) {
|
||||||
yield const IdQueryParameter.notAssigned();
|
yield const NotAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
if (widget.showAnyAssignedOption) {
|
if (widget.showAnyAssignedOption) {
|
||||||
yield const IdQueryParameter.anyAssigned();
|
yield const AnyAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (widget.showNotAssignedOption) {
|
if (widget.showNotAssignedOption) {
|
||||||
yield const IdQueryParameter.notAssigned();
|
yield const NotAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
if (widget.showAnyAssignedOption) {
|
if (widget.showAnyAssignedOption) {
|
||||||
yield const IdQueryParameter.anyAssigned();
|
yield const AnyAssignedIdQueryParameter();
|
||||||
}
|
}
|
||||||
if (!(widget.showAnyAssignedOption || widget.showNotAssignedOption)) {
|
if (!(widget.showAnyAssignedOption || widget.showNotAssignedOption)) {
|
||||||
yield const IdQueryParameter.unset();
|
yield const UnsetIdQueryParameter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _buildHintText() {
|
String? _buildHintText() {
|
||||||
return widget.initialValue?.when(
|
return switch (widget.initialValue) {
|
||||||
unset: () => S.of(context)!.startTyping,
|
UnsetIdQueryParameter() => S.of(context)!.startTyping,
|
||||||
notAssigned: () => S.of(context)!.notAssigned,
|
NotAssignedIdQueryParameter() => S.of(context)!.notAssigned,
|
||||||
anyAssigned: () => S.of(context)!.anyAssigned,
|
AnyAssignedIdQueryParameter() => S.of(context)!.anyAssigned,
|
||||||
fromId: (id) => widget.options[id]?.name ?? S.of(context)!.startTyping,
|
SetIdQueryParameter(id: var id) =>
|
||||||
);
|
widget.options[id]?.name ?? S.of(context)!.startTyping,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildOptionWidget(IdQueryParameter option, bool highlight) {
|
Widget _buildOptionWidget(IdQueryParameter option, bool highlight) {
|
||||||
void onTap() => widget.onSubmit(returnValue: option);
|
void onTap() => widget.onSubmit(returnValue: option);
|
||||||
|
|
||||||
if (option.isUnset()) {
|
return switch (option) {
|
||||||
return Center(
|
NotAssignedIdQueryParameter() => ListTile(
|
||||||
child: Column(
|
selected: highlight,
|
||||||
children: [
|
selectedTileColor: Theme.of(context).focusColor,
|
||||||
Text(S.of(context)!.noItemsFound).padded(),
|
title: Text(S.of(context)!.notAssigned),
|
||||||
if (widget.onCreateNewLabel != null)
|
onTap: onTap,
|
||||||
TextButton(
|
|
||||||
child: Text(widget.addNewLabelText!),
|
|
||||||
onPressed: _onCreateNewLabel,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
AnyAssignedIdQueryParameter() => ListTile(
|
||||||
}
|
selected: highlight,
|
||||||
|
selectedTileColor: Theme.of(context).focusColor,
|
||||||
return option.whenOrNull(
|
title: Text(S.of(context)!.anyAssigned),
|
||||||
notAssigned: () => ListTile(
|
onTap: onTap,
|
||||||
selected: highlight,
|
),
|
||||||
selectedTileColor: Theme.of(context).focusColor,
|
SetIdQueryParameter(id: var id) => ListTile(
|
||||||
title: Text(S.of(context)!.notAssigned),
|
selected: highlight,
|
||||||
onTap: onTap,
|
selectedTileColor: Theme.of(context).focusColor,
|
||||||
),
|
title: Text(widget.options[id]!.name),
|
||||||
anyAssigned: () => ListTile(
|
onTap: onTap,
|
||||||
selected: highlight,
|
enabled: widget.allowSelectUnassigned
|
||||||
selectedTileColor: Theme.of(context).focusColor,
|
? true
|
||||||
title: Text(S.of(context)!.anyAssigned),
|
: widget.options[id]!.documentCount != 0,
|
||||||
onTap: onTap,
|
),
|
||||||
),
|
UnsetIdQueryParameter() => Center(
|
||||||
fromId: (id) => ListTile(
|
child: Column(
|
||||||
selected: highlight,
|
children: [
|
||||||
selectedTileColor: Theme.of(context).focusColor,
|
Text(S.of(context)!.noItemsFound).padded(),
|
||||||
title: Text(widget.options[id]!.name),
|
if (widget.onCreateNewLabel != null)
|
||||||
onTap: onTap,
|
TextButton(
|
||||||
enabled: widget.allowSelectUnassigned
|
child: Text(widget.addNewLabelText!),
|
||||||
? true
|
onPressed: _onCreateNewLabel,
|
||||||
: widget.options[id]!.documentCount != 0,
|
),
|
||||||
),
|
],
|
||||||
)!; // Never null, since we already return on unset before
|
),
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,13 +47,13 @@ class LabelFormField<T extends Label> extends StatelessWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
String _buildText(BuildContext context, IdQueryParameter? value) {
|
String _buildText(BuildContext context, IdQueryParameter? value) {
|
||||||
return value?.when(
|
return switch (value) {
|
||||||
unset: () => '',
|
UnsetIdQueryParameter() => '',
|
||||||
notAssigned: () => S.of(context)!.notAssigned,
|
NotAssignedIdQueryParameter() => S.of(context)!.notAssigned,
|
||||||
anyAssigned: () => S.of(context)!.anyAssigned,
|
AnyAssignedIdQueryParameter() => S.of(context)!.anyAssigned,
|
||||||
fromId: (id) => options[id]?.name,
|
SetIdQueryParameter(id: var id) => options[id]?.name ?? '',
|
||||||
) ??
|
_ => '',
|
||||||
'';
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -70,9 +70,14 @@ class LabelFormField<T extends Label> extends StatelessWidget {
|
|||||||
text: _buildText(context, field.value),
|
text: _buildText(context, field.value),
|
||||||
);
|
);
|
||||||
final displayedSuggestions = suggestions
|
final displayedSuggestions = suggestions
|
||||||
.whereNot((e) =>
|
.whereNot(
|
||||||
e.id ==
|
(e) =>
|
||||||
field.value?.maybeWhen(fromId: (id) => id, orElse: () => -1))
|
e.id ==
|
||||||
|
switch (field.value) {
|
||||||
|
SetIdQueryParameter(id: var id) => id,
|
||||||
|
_ => -1,
|
||||||
|
},
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
@@ -98,7 +103,7 @@ class LabelFormField<T extends Label> extends StatelessWidget {
|
|||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.clear),
|
icon: const Icon(Icons.clear),
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
field.didChange(const IdQueryParameter.unset()),
|
field.didChange(const UnsetIdQueryParameter()),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
@@ -151,7 +156,7 @@ class LabelFormField<T extends Label> extends StatelessWidget {
|
|||||||
child: ActionChip(
|
child: ActionChip(
|
||||||
label: Text(suggestion.name),
|
label: Text(suggestion.name),
|
||||||
onPressed: () => field.didChange(
|
onPressed: () => field.didChange(
|
||||||
IdQueryParameter.fromId(suggestion.id!),
|
SetIdQueryParameter(id: suggestion.id!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ class _LandingPageState extends State<LandingPage> {
|
|||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Text(
|
child: Text(
|
||||||
S.of(context)!.welcomeUser(
|
S.of(context)!.welcomeUser(
|
||||||
currentUser.fullName ?? currentUser.username),
|
currentUser.fullName ?? currentUser.username,
|
||||||
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import 'package:paperless_mobile/routes/typed/top_level/settings_route.dart';
|
|||||||
import 'package:paperless_mobile/theme.dart';
|
import 'package:paperless_mobile/theme.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
String get defaultPreferredLocaleSubtag {
|
String get defaultPreferredLocaleSubtag {
|
||||||
String preferredLocale = Platform.localeName.split("_").first;
|
String preferredLocale = Platform.localeName.split("_").first;
|
||||||
@@ -62,9 +63,42 @@ String get defaultPreferredLocaleSubtag {
|
|||||||
return preferredLocale;
|
return preferredLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, Future<void> Function()> _migrations = {
|
||||||
|
'3.0.0': () {
|
||||||
|
// Remove all stored data due to updates in schema
|
||||||
|
return Future.wait([
|
||||||
|
for (var box in HiveBoxes.all) Hive.deleteBoxFromDisk(box),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Future<void> performMigrations() async {
|
||||||
|
final sp = await SharedPreferences.getInstance();
|
||||||
|
final currentVersion = packageInfo.version;
|
||||||
|
final migrationExists = _migrations.containsKey(currentVersion);
|
||||||
|
if (!migrationExists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final migrationProcedure = _migrations[currentVersion]!;
|
||||||
|
final performedMigrations = sp.getStringList("performed_migrations") ?? [];
|
||||||
|
final requiresMigrationForCurrentVersion =
|
||||||
|
!performedMigrations.contains(currentVersion);
|
||||||
|
if (requiresMigrationForCurrentVersion) {
|
||||||
|
debugPrint("Applying migration scripts for version $currentVersion");
|
||||||
|
await migrationProcedure();
|
||||||
|
await sp.setStringList(
|
||||||
|
'performed_migrations',
|
||||||
|
[...performedMigrations, currentVersion],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _initHive() async {
|
Future<void> _initHive() async {
|
||||||
await Hive.initFlutter();
|
await Hive.initFlutter();
|
||||||
|
|
||||||
|
await performMigrations();
|
||||||
registerHiveAdapters();
|
registerHiveAdapters();
|
||||||
|
|
||||||
// await getApplicationDocumentsDirectory().then((value) => value.deleteSync(recursive: true));
|
// await getApplicationDocumentsDirectory().then((value) => value.deleteSync(recursive: true));
|
||||||
await Hive.openBox<LocalUserAccount>(HiveBoxes.localUserAccount);
|
await Hive.openBox<LocalUserAccount>(HiveBoxes.localUserAccount);
|
||||||
await Hive.openBox<LocalUserAppState>(HiveBoxes.localUserAppState);
|
await Hive.openBox<LocalUserAppState>(HiveBoxes.localUserAppState);
|
||||||
@@ -81,6 +115,7 @@ Future<void> _initHive() async {
|
|||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
runZonedGuarded(() async {
|
runZonedGuarded(() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
Paint.enableDithering = true;
|
Paint.enableDithering = true;
|
||||||
// if (kDebugMode) {
|
// if (kDebugMode) {
|
||||||
// // URL: http://localhost:3131
|
// // URL: http://localhost:3131
|
||||||
@@ -93,13 +128,6 @@ void main() async {
|
|||||||
// )
|
// )
|
||||||
// .start();
|
// .start();
|
||||||
// }
|
// }
|
||||||
await _initHive();
|
|
||||||
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
|
||||||
final globalSettingsBox =
|
|
||||||
Hive.box<GlobalSettings>(HiveBoxes.globalSettings);
|
|
||||||
final globalSettings = globalSettingsBox.getValue()!;
|
|
||||||
|
|
||||||
await findSystemLocale();
|
|
||||||
packageInfo = await PackageInfo.fromPlatform();
|
packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
@@ -108,6 +136,14 @@ void main() async {
|
|||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
iosInfo = await DeviceInfoPlugin().iosInfo;
|
iosInfo = await DeviceInfoPlugin().iosInfo;
|
||||||
}
|
}
|
||||||
|
await _initHive();
|
||||||
|
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final globalSettingsBox =
|
||||||
|
Hive.box<GlobalSettings>(HiveBoxes.globalSettings);
|
||||||
|
final globalSettings = globalSettingsBox.getValue()!;
|
||||||
|
|
||||||
|
await findSystemLocale();
|
||||||
|
|
||||||
final connectivityStatusService = ConnectivityStatusServiceImpl(
|
final connectivityStatusService = ConnectivityStatusServiceImpl(
|
||||||
Connectivity(),
|
Connectivity(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ class PaperlessApiHiveTypeIds {
|
|||||||
void registerPaperlessApiHiveTypeAdapters() {
|
void registerPaperlessApiHiveTypeAdapters() {
|
||||||
Hive.registerAdapter(DocumentFilterAdapter());
|
Hive.registerAdapter(DocumentFilterAdapter());
|
||||||
// TagsQuery
|
// TagsQuery
|
||||||
Hive.registerAdapter(AnyAssignedTagsQueryImplAdapter());
|
Hive.registerAdapter(AnyAssignedTagsQueryAdapter());
|
||||||
Hive.registerAdapter(NotAssignedTagsQueryImplAdapter());
|
Hive.registerAdapter(NotAssignedTagsQueryAdapter());
|
||||||
Hive.registerAdapter(IdsTagsQueryImplAdapter());
|
Hive.registerAdapter(IdsTagsQueryAdapter());
|
||||||
|
|
||||||
Hive.registerAdapter(SortFieldAdapter());
|
Hive.registerAdapter(SortFieldAdapter());
|
||||||
Hive.registerAdapter(SortOrderAdapter());
|
Hive.registerAdapter(SortOrderAdapter());
|
||||||
@@ -49,13 +49,13 @@ void registerPaperlessApiHiveTypeAdapters() {
|
|||||||
Hive.registerAdapter(TextQueryAdapter());
|
Hive.registerAdapter(TextQueryAdapter());
|
||||||
Hive.registerAdapter(QueryTypeAdapter());
|
Hive.registerAdapter(QueryTypeAdapter());
|
||||||
// IdQueryParameter
|
// IdQueryParameter
|
||||||
Hive.registerAdapter(SetIdQueryParameterImplAdapter());
|
Hive.registerAdapter(SetIdQueryParameterAdapter());
|
||||||
Hive.registerAdapter(UnsetIdQueryParameterImplAdapter());
|
Hive.registerAdapter(UnsetIdQueryParameterAdapter());
|
||||||
Hive.registerAdapter(AnyAssignedIdQueryParameterImplAdapter());
|
Hive.registerAdapter(AnyAssignedIdQueryParameterAdapter());
|
||||||
Hive.registerAdapter(NotAssignedIdQueryParameterImplAdapter());
|
Hive.registerAdapter(NotAssignedIdQueryParameterAdapter());
|
||||||
// Users and permissions
|
// Users and permissions
|
||||||
Hive.registerAdapter(UserModelV3ImplAdapter());
|
Hive.registerAdapter(UserModelV3Adapter());
|
||||||
Hive.registerAdapter(UserModelV2ImplAdapter());
|
Hive.registerAdapter(UserModelV2Adapter());
|
||||||
Hive.registerAdapter(GroupModelAdapter());
|
Hive.registerAdapter(GroupModelAdapter());
|
||||||
Hive.registerAdapter(PermissionsAdapter());
|
Hive.registerAdapter(PermissionsAdapter());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query.dart';
|
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart';
|
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart';
|
||||||
|
|
||||||
part 'document_filter.g.dart';
|
part 'document_filter.g.dart';
|
||||||
|
|
||||||
@DateRangeQueryJsonConverter()
|
@DateRangeQueryJsonConverter()
|
||||||
@JsonSerializable(explicitToJson: true)
|
// @JsonSerializable(explicitToJson: true)
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.documentFilter)
|
@HiveType(typeId: PaperlessApiHiveTypeIds.documentFilter)
|
||||||
class DocumentFilter extends Equatable {
|
class DocumentFilter extends Equatable {
|
||||||
static const DocumentFilter initial = DocumentFilter();
|
static const DocumentFilter initial = DocumentFilter();
|
||||||
@@ -67,11 +66,11 @@ class DocumentFilter extends Equatable {
|
|||||||
final int? selectedView;
|
final int? selectedView;
|
||||||
|
|
||||||
const DocumentFilter({
|
const DocumentFilter({
|
||||||
this.documentType = const IdQueryParameter.unset(),
|
this.documentType = const UnsetIdQueryParameter(),
|
||||||
this.correspondent = const IdQueryParameter.unset(),
|
this.correspondent = const UnsetIdQueryParameter(),
|
||||||
this.storagePath = const IdQueryParameter.unset(),
|
this.storagePath = const UnsetIdQueryParameter(),
|
||||||
this.asnQuery = const IdQueryParameter.unset(),
|
this.asnQuery = const UnsetIdQueryParameter(),
|
||||||
this.tags = const TagsQuery.ids(),
|
this.tags = const IdsTagsQuery(),
|
||||||
this.sortField = SortField.created,
|
this.sortField = SortField.created,
|
||||||
this.sortOrder = SortOrder.descending,
|
this.sortOrder = SortOrder.descending,
|
||||||
this.page = 1,
|
this.page = 1,
|
||||||
@@ -164,7 +163,8 @@ class DocumentFilter extends Equatable {
|
|||||||
created: created ?? this.created,
|
created: created ?? this.created,
|
||||||
modified: modified ?? this.modified,
|
modified: modified ?? this.modified,
|
||||||
moreLike: moreLike != null ? moreLike.call() : this.moreLike,
|
moreLike: moreLike != null ? moreLike.call() : this.moreLike,
|
||||||
selectedView: selectedView != null ? selectedView.call() : this.selectedView,
|
selectedView:
|
||||||
|
selectedView != null ? selectedView.call() : this.selectedView,
|
||||||
);
|
);
|
||||||
if (query?.queryType != QueryType.extended &&
|
if (query?.queryType != QueryType.extended &&
|
||||||
newFilter.forceExtendedQuery) {
|
newFilter.forceExtendedQuery) {
|
||||||
@@ -195,24 +195,23 @@ class DocumentFilter extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int get appliedFiltersCount => [
|
int get appliedFiltersCount => [
|
||||||
documentType.maybeWhen(
|
switch (documentType) {
|
||||||
unset: () => 0,
|
UnsetIdQueryParameter() => 0,
|
||||||
orElse: () => 1,
|
_ => 1,
|
||||||
),
|
},
|
||||||
correspondent.maybeWhen(
|
switch (correspondent) {
|
||||||
unset: () => 0,
|
UnsetIdQueryParameter() => 0,
|
||||||
orElse: () => 1,
|
_ => 1,
|
||||||
),
|
},
|
||||||
storagePath.maybeWhen(
|
switch (storagePath) {
|
||||||
unset: () => 0,
|
UnsetIdQueryParameter() => 0,
|
||||||
orElse: () => 1,
|
_ => 1,
|
||||||
),
|
},
|
||||||
tags.maybeWhen(
|
switch (tags) {
|
||||||
ids: (include, exclude) => include.length + exclude.length,
|
NotAssignedTagsQuery() => 1,
|
||||||
anyAssigned: (tagIds) => tagIds.length,
|
AnyAssignedTagsQuery(tagIds: var tags) => tags.length,
|
||||||
notAssigned: () => 1,
|
IdsTagsQuery(include: var i, exclude: var e) => e.length + i.length,
|
||||||
orElse: () => 0,
|
},
|
||||||
),
|
|
||||||
switch (added) {
|
switch (added) {
|
||||||
RelativeDateRangeQuery() => 1,
|
RelativeDateRangeQuery() => 1,
|
||||||
AbsoluteDateRangeQuery() => 1,
|
AbsoluteDateRangeQuery() => 1,
|
||||||
@@ -228,10 +227,10 @@ class DocumentFilter extends Equatable {
|
|||||||
AbsoluteDateRangeQuery() => 1,
|
AbsoluteDateRangeQuery() => 1,
|
||||||
UnsetDateRangeQuery() => 0,
|
UnsetDateRangeQuery() => 0,
|
||||||
},
|
},
|
||||||
asnQuery.maybeWhen(
|
switch (asnQuery) {
|
||||||
unset: () => 0,
|
UnsetIdQueryParameter() => 0,
|
||||||
orElse: () => 1,
|
_ => 1,
|
||||||
),
|
},
|
||||||
(query.queryText?.isNotEmpty ?? false) ? 1 : 0,
|
(query.queryText?.isNotEmpty ?? false) ? 1 : 0,
|
||||||
].fold(0, (previousValue, element) => previousValue + element);
|
].fold(0, (previousValue, element) => previousValue + element);
|
||||||
|
|
||||||
@@ -254,8 +253,8 @@ class DocumentFilter extends Equatable {
|
|||||||
selectedView,
|
selectedView,
|
||||||
];
|
];
|
||||||
|
|
||||||
factory DocumentFilter.fromJson(Map<String, dynamic> json) =>
|
// factory DocumentFilter.fromJson(Map<String, dynamic> json) =>
|
||||||
_$DocumentFilterFromJson(json);
|
// _$DocumentFilterFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$DocumentFilterToJson(this);
|
// Map<String, dynamic> toJson() => _$DocumentFilterToJson(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import 'package:json_annotation/json_annotation.dart';
|
|||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_api/src/constants.dart';
|
import 'package:paperless_api/src/constants.dart';
|
||||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query.dart';
|
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart';
|
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart';
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_unit.dart';
|
|
||||||
|
|
||||||
part 'filter_rule_model.g.dart';
|
part 'filter_rule_model.g.dart';
|
||||||
|
|
||||||
@@ -59,48 +57,49 @@ class FilterRule with EquatableMixin {
|
|||||||
case documentTypeRule:
|
case documentTypeRule:
|
||||||
return filter.copyWith(
|
return filter.copyWith(
|
||||||
documentType: value == null
|
documentType: value == null
|
||||||
? const IdQueryParameter.notAssigned()
|
? const NotAssignedIdQueryParameter()
|
||||||
: IdQueryParameter.fromId(int.parse(value!)),
|
: SetIdQueryParameter(id: int.parse(value!)),
|
||||||
);
|
);
|
||||||
case correspondentRule:
|
case correspondentRule:
|
||||||
return filter.copyWith(
|
return filter.copyWith(
|
||||||
correspondent: value == null
|
correspondent: value == null
|
||||||
? const IdQueryParameter.notAssigned()
|
? const NotAssignedIdQueryParameter()
|
||||||
: IdQueryParameter.fromId(int.parse(value!)),
|
: SetIdQueryParameter(id: int.parse(value!)),
|
||||||
);
|
);
|
||||||
case storagePathRule:
|
case storagePathRule:
|
||||||
return filter.copyWith(
|
return filter.copyWith(
|
||||||
storagePath: value == null
|
storagePath: value == null
|
||||||
? const IdQueryParameter.notAssigned()
|
? const NotAssignedIdQueryParameter()
|
||||||
: IdQueryParameter.fromId(int.parse(value!)),
|
: SetIdQueryParameter(id: int.parse(value!)),
|
||||||
);
|
);
|
||||||
case hasAnyTag:
|
case hasAnyTag:
|
||||||
return filter.copyWith(
|
return filter.copyWith(
|
||||||
tags: value == "true"
|
tags: value == "true"
|
||||||
? const TagsQuery.anyAssigned()
|
? const AnyAssignedTagsQuery()
|
||||||
: const TagsQuery.notAssigned(),
|
: const NotAssignedTagsQuery(),
|
||||||
);
|
);
|
||||||
case includeTagsRule:
|
case includeTagsRule:
|
||||||
assert(filter.tags is IdsTagsQuery);
|
assert(filter.tags is IdsTagsQuery);
|
||||||
return filter.copyWith(
|
return filter.copyWith(
|
||||||
tags: filter.tags.maybeWhen(
|
tags: switch (filter.tags) {
|
||||||
ids: (include, exclude) => TagsQuery.ids(
|
// TODO: Handle this case.
|
||||||
include: [...include, int.parse(value!)],
|
IdsTagsQuery(include: var i, exclude: var e) => IdsTagsQuery(
|
||||||
exclude: exclude,
|
include: [...i, int.parse(value!)],
|
||||||
),
|
exclude: e,
|
||||||
orElse: () => filter.tags,
|
),
|
||||||
),
|
_ => filter.tags,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
case excludeTagsRule:
|
case excludeTagsRule:
|
||||||
assert(filter.tags is IdsTagsQuery);
|
assert(filter.tags is IdsTagsQuery);
|
||||||
return filter.copyWith(
|
return filter.copyWith(
|
||||||
tags: filter.tags.maybeWhen(
|
tags: switch (filter.tags) {
|
||||||
ids: (include, exclude) => TagsQuery.ids(
|
IdsTagsQuery(include: var i, exclude: var e) => IdsTagsQuery(
|
||||||
include: include,
|
include: i,
|
||||||
exclude: [...exclude, int.parse(value!)],
|
exclude: [...e, int.parse(value!)],
|
||||||
),
|
),
|
||||||
orElse: () => filter.tags,
|
_ => filter.tags,
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
case createdBeforeRule:
|
case createdBeforeRule:
|
||||||
if (filter.created is AbsoluteDateRangeQuery) {
|
if (filter.created is AbsoluteDateRangeQuery) {
|
||||||
@@ -245,37 +244,46 @@ class FilterRule with EquatableMixin {
|
|||||||
///
|
///
|
||||||
static List<FilterRule> fromFilter(final DocumentFilter filter) {
|
static List<FilterRule> fromFilter(final DocumentFilter filter) {
|
||||||
List<FilterRule> filterRules = [];
|
List<FilterRule> filterRules = [];
|
||||||
final corrRule = filter.correspondent.whenOrNull(
|
final corrRule = switch (filter.correspondent) {
|
||||||
notAssigned: () => FilterRule(correspondentRule, null),
|
NotAssignedIdQueryParameter() => FilterRule(correspondentRule, null),
|
||||||
fromId: (id) => FilterRule(correspondentRule, id.toString()),
|
SetIdQueryParameter(id: var id) =>
|
||||||
);
|
FilterRule(correspondentRule, id.toString()),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
if (corrRule != null) {
|
if (corrRule != null) {
|
||||||
filterRules.add(corrRule);
|
filterRules.add(corrRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
final docTypeRule = filter.documentType.whenOrNull(
|
final docTypeRule = switch (filter.documentType) {
|
||||||
notAssigned: () => FilterRule(documentTypeRule, null),
|
NotAssignedIdQueryParameter() => FilterRule(documentTypeRule, null),
|
||||||
fromId: (id) => FilterRule(documentTypeRule, id.toString()),
|
SetIdQueryParameter(id: var id) =>
|
||||||
);
|
FilterRule(documentTypeRule, id.toString()),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
if (docTypeRule != null) {
|
if (docTypeRule != null) {
|
||||||
filterRules.add(docTypeRule);
|
filterRules.add(docTypeRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
final sPathRule = filter.storagePath.whenOrNull(
|
final sPathRule = switch (filter.storagePath) {
|
||||||
notAssigned: () => FilterRule(storagePathRule, null),
|
NotAssignedIdQueryParameter() => FilterRule(storagePathRule, null),
|
||||||
fromId: (id) => FilterRule(storagePathRule, id.toString()),
|
SetIdQueryParameter(id: var id) =>
|
||||||
);
|
FilterRule(storagePathRule, id.toString()),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
if (sPathRule != null) {
|
if (sPathRule != null) {
|
||||||
filterRules.add(sPathRule);
|
filterRules.add(sPathRule);
|
||||||
}
|
}
|
||||||
final tagRules = filter.tags.when(
|
final tagRules = switch (filter.tags) {
|
||||||
notAssigned: () => [FilterRule(hasAnyTag, 'false')],
|
NotAssignedTagsQuery() => [FilterRule(hasAnyTag, 'false')],
|
||||||
anyAssigned: (_) => [FilterRule(hasAnyTag, 'true')],
|
AnyAssignedTagsQuery() => [FilterRule(hasAnyTag, 'true')],
|
||||||
ids: (include, exclude) => [
|
IdsTagsQuery(include: var i, exclude: var e) => [
|
||||||
...include.map((id) => FilterRule(includeTagsRule, id.toString())),
|
...i.map((id) => FilterRule(includeTagsRule, id.toString())),
|
||||||
...exclude.map((id) => FilterRule(excludeTagsRule, id.toString())),
|
...e.map((id) => FilterRule(excludeTagsRule, id.toString())),
|
||||||
],
|
],
|
||||||
);
|
};
|
||||||
|
|
||||||
filterRules.addAll(tagRules);
|
filterRules.addAll(tagRules);
|
||||||
|
|
||||||
if (filter.query.queryText != null) {
|
if (filter.query.queryText != null) {
|
||||||
|
|||||||
@@ -2,32 +2,36 @@ import 'package:paperless_api/paperless_api.dart';
|
|||||||
|
|
||||||
extension UserPermissionExtension on UserModel {
|
extension UserPermissionExtension on UserModel {
|
||||||
bool hasPermission(PermissionAction action, PermissionTarget target) {
|
bool hasPermission(PermissionAction action, PermissionTarget target) {
|
||||||
return map(
|
final permission = [action.value, target.value].join("_");
|
||||||
v3: (user) {
|
return switch (this) {
|
||||||
final permission = [action.value, target.value].join("_");
|
UserModelV2() => true,
|
||||||
return user.userPermissions.any((element) => element == permission) ||
|
UserModelV3(
|
||||||
user.inheritedPermissions
|
userPermissions: var userPermissions,
|
||||||
.any((element) => element.split(".").last == permission);
|
inheritedPermissions: var inheritedPermissions,
|
||||||
},
|
) =>
|
||||||
v2: (_) => true,
|
userPermissions.any((p) => p == permission) ||
|
||||||
);
|
inheritedPermissions.any((p) => p.split(".").last == permission)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasPermissions(
|
bool hasPermissions(
|
||||||
List<PermissionAction> actions, List<PermissionTarget> targets) {
|
List<PermissionAction> actions,
|
||||||
return map(
|
List<PermissionTarget> targets,
|
||||||
v3: (user) {
|
) {
|
||||||
final permissions = [
|
final permissions = [
|
||||||
for (var action in actions)
|
for (var action in actions)
|
||||||
for (var target in targets) [action, target].join("_")
|
for (var target in targets) [action, target].join("_")
|
||||||
];
|
];
|
||||||
return permissions.every((requestedPermission) =>
|
return switch (this) {
|
||||||
user.userPermissions.contains(requestedPermission) ||
|
UserModelV2() => true,
|
||||||
user.inheritedPermissions.any(
|
UserModelV3(
|
||||||
(element) => element.split(".").last == requestedPermission));
|
userPermissions: var userPermissions,
|
||||||
},
|
inheritedPermissions: var inheritedPermissions,
|
||||||
v2: (_) => true,
|
) =>
|
||||||
);
|
permissions.every((p) =>
|
||||||
|
userPermissions.contains(p) ||
|
||||||
|
inheritedPermissions.any((ip) => ip.split(".").last == p))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get canViewDocuments =>
|
bool get canViewDocuments =>
|
||||||
|
|||||||
@@ -1,110 +1,79 @@
|
|||||||
|
import 'dart:isolate';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
part 'id_query_parameter.freezed.dart';
|
part 'id_query_parameter.freezed.dart';
|
||||||
part 'id_query_parameter.g.dart';
|
part 'id_query_parameter.g.dart';
|
||||||
|
|
||||||
@freezed
|
sealed class IdQueryParameter {
|
||||||
class IdQueryParameter with _$IdQueryParameter {
|
const IdQueryParameter();
|
||||||
const IdQueryParameter._();
|
Map<String, String> toQueryParameter(String field);
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.unsetIdQueryParameter)
|
bool matches(int? id);
|
||||||
const factory IdQueryParameter.unset() = UnsetIdQueryParameter;
|
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.notAssignedIdQueryParameter)
|
|
||||||
const factory IdQueryParameter.notAssigned() = NotAssignedIdQueryParameter;
|
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedIdQueryParameter)
|
|
||||||
const factory IdQueryParameter.anyAssigned() = AnyAssignedIdQueryParameter;
|
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.setIdQueryParameter)
|
|
||||||
const factory IdQueryParameter.fromId(@HiveField(0) int id) = SetIdQueryParameter;
|
|
||||||
|
|
||||||
Map<String, String> toQueryParameter(String field) {
|
bool get isUnset => this is UnsetIdQueryParameter;
|
||||||
return when(
|
bool get isSet => this is SetIdQueryParameter;
|
||||||
unset: () => {},
|
bool get isOnlyNotAssigned => this is NotAssignedIdQueryParameter;
|
||||||
notAssigned: () => {
|
bool get isOnlyAssigned => this is AnyAssignedIdQueryParameter;
|
||||||
'${field}__isnull': '1',
|
|
||||||
},
|
|
||||||
anyAssigned: () => {
|
|
||||||
'${field}__isnull': '0',
|
|
||||||
},
|
|
||||||
fromId: (id) {
|
|
||||||
return {'${field}__id': '$id'};
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isOnlyNotAssigned() => this is NotAssignedIdQueryParameter;
|
|
||||||
|
|
||||||
bool isOnlyAssigned() => this is AnyAssignedIdQueryParameter;
|
|
||||||
|
|
||||||
bool isSet() => this is SetIdQueryParameter;
|
|
||||||
|
|
||||||
bool isUnset() => this is UnsetIdQueryParameter;
|
|
||||||
|
|
||||||
bool matches(int? id) {
|
|
||||||
return when(
|
|
||||||
unset: () => true,
|
|
||||||
notAssigned: () => id == null,
|
|
||||||
anyAssigned: () => id != null,
|
|
||||||
fromId: (id_) => id == id_,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
factory IdQueryParameter.fromJson(Map<String, dynamic> json) => _$IdQueryParameterFromJson(json);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @JsonSerializable()
|
@HiveType(typeId: PaperlessApiHiveTypeIds.unsetIdQueryParameter)
|
||||||
// @HiveType(typeId: PaperlessApiHiveTypeIds.idQueryParameter)
|
@Freezed(toJson: false, fromJson: false)
|
||||||
// class IdQueryParameter extends Equatable {
|
class UnsetIdQueryParameter extends IdQueryParameter
|
||||||
// @HiveField(0)
|
with _$UnsetIdQueryParameter {
|
||||||
// final int? assignmentStatus;
|
const UnsetIdQueryParameter._();
|
||||||
// @HiveField(1)
|
const factory UnsetIdQueryParameter() = _UnsetIdQueryParameter;
|
||||||
// final int? id;
|
@override
|
||||||
|
Map<String, String> toQueryParameter(String field) => {};
|
||||||
|
|
||||||
// @Deprecated("Use named constructors, this is only meant for code generation")
|
@override
|
||||||
// const IdQueryParameter(this.assignmentStatus, this.id);
|
bool matches(int? id) => true;
|
||||||
|
}
|
||||||
|
|
||||||
// const IdQueryParameter.notAssigned()
|
@HiveType(typeId: PaperlessApiHiveTypeIds.notAssignedIdQueryParameter)
|
||||||
// : assignmentStatus = 1,
|
@Freezed(toJson: false, fromJson: false)
|
||||||
// id = null;
|
class NotAssignedIdQueryParameter extends IdQueryParameter
|
||||||
|
with _$NotAssignedIdQueryParameter {
|
||||||
|
const NotAssignedIdQueryParameter._();
|
||||||
|
const factory NotAssignedIdQueryParameter() = _NotAssignedIdQueryParameter;
|
||||||
|
@override
|
||||||
|
Map<String, String> toQueryParameter(String field) {
|
||||||
|
return {'${field}__isnull': '1'};
|
||||||
|
}
|
||||||
|
|
||||||
// const IdQueryParameter.anyAssigned()
|
@override
|
||||||
// : assignmentStatus = 0,
|
bool matches(int? id) => id == null;
|
||||||
// id = null;
|
}
|
||||||
|
|
||||||
// const IdQueryParameter.fromId(this.id) : assignmentStatus = null;
|
@HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedIdQueryParameter)
|
||||||
|
@Freezed(toJson: false, fromJson: false)
|
||||||
|
class AnyAssignedIdQueryParameter extends IdQueryParameter
|
||||||
|
with _$AnyAssignedIdQueryParameter {
|
||||||
|
const factory AnyAssignedIdQueryParameter() = _AnyAssignedIdQueryParameter;
|
||||||
|
const AnyAssignedIdQueryParameter._();
|
||||||
|
@override
|
||||||
|
Map<String, String> toQueryParameter(String field) {
|
||||||
|
return {'${field}__isnull': '0'};
|
||||||
|
}
|
||||||
|
|
||||||
// const IdQueryParameter.unset() : this.fromId(null);
|
@override
|
||||||
|
bool matches(int? id) => id != null;
|
||||||
|
}
|
||||||
|
|
||||||
// bool get isUnset => id == null && assignmentStatus == null;
|
@HiveType(typeId: PaperlessApiHiveTypeIds.setIdQueryParameter)
|
||||||
|
@Freezed(toJson: false, fromJson: false)
|
||||||
// bool get isSet => id != null && assignmentStatus == null;
|
class SetIdQueryParameter extends IdQueryParameter with _$SetIdQueryParameter {
|
||||||
|
const SetIdQueryParameter._();
|
||||||
// bool get onlyNotAssigned => assignmentStatus == 1;
|
const factory SetIdQueryParameter({
|
||||||
|
@HiveField(0) required int id,
|
||||||
// bool get onlyAssigned => assignmentStatus == 0;
|
}) = _SetIdQueryParameter;
|
||||||
|
@override
|
||||||
// Map<String, String> toQueryParameter(String field) {
|
Map<String, String> toQueryParameter(String field) {
|
||||||
// final Map<String, String> params = {};
|
return {'${field}__id': '$id'};
|
||||||
// if (onlyNotAssigned || onlyAssigned) {
|
}
|
||||||
// params.putIfAbsent('${field}__isnull', () => assignmentStatus!.toString());
|
|
||||||
// }
|
|
||||||
// if (isSet) {
|
|
||||||
// params.putIfAbsent("${field}__id", () => id!.toString());
|
|
||||||
// }
|
|
||||||
// return params;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bool matches(int? id) {
|
|
||||||
// return onlyAssigned && id != null ||
|
|
||||||
// onlyNotAssigned && id == null ||
|
|
||||||
// isSet && id == this.id ||
|
|
||||||
// isUnset;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// List<Object?> get props => [assignmentStatus, id];
|
|
||||||
|
|
||||||
// Map<String, dynamic> toJson() => _$IdQueryParameterToJson(this);
|
|
||||||
|
|
||||||
// factory IdQueryParameter.fromJson(Map<String, dynamic> json) => _$IdQueryParameterFromJson(json);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool matches(int? id) => id == this.id;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,54 +4,68 @@ import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
|||||||
part 'tags_query.freezed.dart';
|
part 'tags_query.freezed.dart';
|
||||||
part 'tags_query.g.dart';
|
part 'tags_query.g.dart';
|
||||||
|
|
||||||
@freezed
|
sealed class TagsQuery {
|
||||||
class TagsQuery with _$TagsQuery {
|
const TagsQuery();
|
||||||
const TagsQuery._();
|
Map<String, String> toQueryParameter();
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.notAssignedTagsQuery)
|
bool matches(Iterable<int> ids);
|
||||||
const factory TagsQuery.notAssigned() = NotAssignedTagsQuery;
|
}
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedTagsQuery)
|
|
||||||
const factory TagsQuery.anyAssigned({
|
@HiveType(typeId: PaperlessApiHiveTypeIds.notAssignedTagsQuery)
|
||||||
@Default([]) List<int> tagIds,
|
@Freezed(toJson: false, fromJson: false)
|
||||||
}) = AnyAssignedTagsQuery;
|
class NotAssignedTagsQuery extends TagsQuery with _$NotAssignedTagsQuery {
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.idsTagsQuery)
|
const NotAssignedTagsQuery._();
|
||||||
const factory TagsQuery.ids({
|
const factory NotAssignedTagsQuery() = _NotAssignedTagsQuery;
|
||||||
@Default([]) List<int> include,
|
@override
|
||||||
@Default([]) List<int> exclude,
|
Map<String, String> toQueryParameter() {
|
||||||
}) = IdsTagsQuery;
|
return {'is_tagged': '0'};
|
||||||
|
}
|
||||||
Map<String, String> toQueryParameter() {
|
|
||||||
return when(
|
@override
|
||||||
anyAssigned: (tagIds) {
|
bool matches(Iterable<int> ids) => ids.isEmpty;
|
||||||
if (tagIds.isEmpty) {
|
}
|
||||||
return {'is_tagged': '1'};
|
|
||||||
}
|
@HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedTagsQuery)
|
||||||
return {'tags__id__in': tagIds.join(',')};
|
@Freezed(toJson: false, fromJson: false)
|
||||||
},
|
class AnyAssignedTagsQuery extends TagsQuery with _$AnyAssignedTagsQuery {
|
||||||
ids: (include, exclude) {
|
const AnyAssignedTagsQuery._();
|
||||||
final Map<String, String> params = {};
|
const factory AnyAssignedTagsQuery({
|
||||||
if (include.isNotEmpty) {
|
@HiveField(0) @Default([]) List<int> tagIds,
|
||||||
params.putIfAbsent('tags__id__all', () => include.join(','));
|
}) = _AnyAssignedTagsQuery;
|
||||||
}
|
@override
|
||||||
if (exclude.isNotEmpty) {
|
Map<String, String> toQueryParameter() {
|
||||||
params.putIfAbsent('tags__id__none', () => exclude.join(','));
|
if (tagIds.isEmpty) {
|
||||||
}
|
return {'is_tagged': '1'};
|
||||||
return params;
|
}
|
||||||
},
|
return {'tags__id__in': tagIds.join(',')};
|
||||||
notAssigned: () {
|
}
|
||||||
return {'is_tagged': '0'};
|
|
||||||
},
|
@override
|
||||||
);
|
bool matches(Iterable<int> ids) => ids.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matches(Iterable<int> ids) {
|
@HiveType(typeId: PaperlessApiHiveTypeIds.idsTagsQuery)
|
||||||
return when(
|
@Freezed(toJson: false, fromJson: false)
|
||||||
anyAssigned: (_) => ids.isNotEmpty,
|
class IdsTagsQuery extends TagsQuery with _$IdsTagsQuery {
|
||||||
ids: (include, exclude) =>
|
const IdsTagsQuery._();
|
||||||
include.toSet().difference(ids.toSet()).isEmpty &&
|
const factory IdsTagsQuery({
|
||||||
exclude.toSet().intersection(ids.toSet()).isEmpty,
|
@HiveField(0) @Default([]) List<int> include,
|
||||||
notAssigned: () => ids.isEmpty,
|
@HiveField(1) @Default([]) List<int> exclude,
|
||||||
);
|
}) = _IdsTagsQuery;
|
||||||
}
|
@override
|
||||||
|
Map<String, String> toQueryParameter() {
|
||||||
factory TagsQuery.fromJson(Map<String, dynamic> json) => _$TagsQueryFromJson(json);
|
final Map<String, String> params = {};
|
||||||
|
if (include.isNotEmpty) {
|
||||||
|
params.putIfAbsent('tags__id__all', () => include.join(','));
|
||||||
|
}
|
||||||
|
if (exclude.isNotEmpty) {
|
||||||
|
params.putIfAbsent('tags__id__none', () => exclude.join(','));
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool matches(Iterable<int> ids) {
|
||||||
|
return include.toSet().difference(ids.toSet()).isEmpty &&
|
||||||
|
exclude.toSet().intersection(ids.toSet()).isEmpty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,55 +4,93 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
||||||
|
|
||||||
part 'user_model.freezed.dart';
|
|
||||||
part 'user_model.g.dart';
|
part 'user_model.g.dart';
|
||||||
|
|
||||||
@freezed
|
sealed class UserModel {
|
||||||
class UserModel with _$UserModel {
|
@HiveField(0)
|
||||||
const UserModel._();
|
final int id;
|
||||||
|
@HiveField(1)
|
||||||
|
final String username;
|
||||||
|
const UserModel({
|
||||||
|
required this.id,
|
||||||
|
required this.username,
|
||||||
|
});
|
||||||
|
|
||||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
String? get fullName;
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.userModelv3)
|
}
|
||||||
const factory UserModel.v3({
|
|
||||||
@HiveField(0) required int id,
|
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||||
@HiveField(1) required String username,
|
@HiveType(typeId: PaperlessApiHiveTypeIds.userModelv2)
|
||||||
@HiveField(2) String? email,
|
class UserModelV2 extends UserModel {
|
||||||
@HiveField(3) String? firstName,
|
@HiveField(2)
|
||||||
@HiveField(4) String? lastName,
|
final String? displayName;
|
||||||
@HiveField(5) DateTime? dateJoined,
|
const UserModelV2({
|
||||||
@HiveField(6) @Default(true) bool isStaff,
|
required super.id,
|
||||||
@HiveField(7) @Default(true) bool isActive,
|
required super.username,
|
||||||
@HiveField(8) @Default(true) bool isSuperuser,
|
this.displayName,
|
||||||
@HiveField(9) @Default([]) List<int> groups,
|
});
|
||||||
@HiveField(10) @Default([]) List<String> userPermissions,
|
Map<String, dynamic> toJson() => _$UserModelV2ToJson(this);
|
||||||
@HiveField(11) @Default([]) List<String> inheritedPermissions,
|
factory UserModelV2.fromJson(Map<String, dynamic> json) =>
|
||||||
}) = UserModelV3;
|
_$UserModelV2FromJson(json);
|
||||||
|
|
||||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
@override
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.userModelv2)
|
String? get fullName => displayName;
|
||||||
const factory UserModel.v2({
|
}
|
||||||
@HiveField(0) @JsonKey(name: "user_id") required int id,
|
|
||||||
@HiveField(1) required String username,
|
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||||
@HiveField(2) String? displayName,
|
@HiveType(typeId: PaperlessApiHiveTypeIds.userModelv3)
|
||||||
}) = UserModelV2;
|
class UserModelV3 extends UserModel {
|
||||||
|
@HiveField(2)
|
||||||
factory UserModel.fromJson(Map<String, dynamic> json) =>
|
final String? email;
|
||||||
_$UserModelFromJson(json);
|
@HiveField(3)
|
||||||
|
final String? firstName;
|
||||||
String? get fullName => map(
|
@HiveField(4)
|
||||||
v2: (value) => value.displayName,
|
final String? lastName;
|
||||||
v3: (value) {
|
@HiveField(5)
|
||||||
bool hasFirstName = value.firstName?.trim().isNotEmpty ?? false;
|
final DateTime? dateJoined;
|
||||||
bool hasLastName = value.lastName?.trim().isNotEmpty ?? false;
|
@HiveField(6)
|
||||||
if (hasFirstName && hasLastName) {
|
final bool isStaff;
|
||||||
return "${value.firstName!} ${value.lastName!}";
|
@HiveField(7)
|
||||||
} else if (hasFirstName) {
|
final bool isActive;
|
||||||
return value.firstName!;
|
@HiveField(8)
|
||||||
} else if (hasLastName) {
|
final bool isSuperuser;
|
||||||
return value.lastName;
|
@HiveField(9)
|
||||||
} else {
|
final List<int> groups;
|
||||||
return null;
|
@HiveField(10)
|
||||||
}
|
final List<String> userPermissions;
|
||||||
},
|
@HiveField(11)
|
||||||
);
|
final List<String> inheritedPermissions;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get fullName {
|
||||||
|
bool hasFirstName = firstName?.trim().isNotEmpty ?? false;
|
||||||
|
bool hasLastName = lastName?.trim().isNotEmpty ?? false;
|
||||||
|
if (hasFirstName && hasLastName) {
|
||||||
|
return "${firstName!} ${lastName!}";
|
||||||
|
} else if (hasFirstName) {
|
||||||
|
return firstName!;
|
||||||
|
} else if (hasLastName) {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserModelV3({
|
||||||
|
required super.id,
|
||||||
|
required super.username,
|
||||||
|
this.email,
|
||||||
|
this.firstName,
|
||||||
|
this.lastName,
|
||||||
|
this.dateJoined,
|
||||||
|
required this.isStaff,
|
||||||
|
required this.isActive,
|
||||||
|
required this.isSuperuser,
|
||||||
|
required this.groups,
|
||||||
|
required this.userPermissions,
|
||||||
|
required this.inheritedPermissions,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$UserModelV3ToJson(this);
|
||||||
|
factory UserModelV3.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$UserModelV3FromJson(json);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
|||||||
const DocumentFilter asnQueryFilter = DocumentFilter(
|
const DocumentFilter asnQueryFilter = DocumentFilter(
|
||||||
sortField: SortField.archiveSerialNumber,
|
sortField: SortField.archiveSerialNumber,
|
||||||
sortOrder: SortOrder.descending,
|
sortOrder: SortOrder.descending,
|
||||||
asnQuery: IdQueryParameter.anyAssigned(),
|
asnQuery: AnyAssignedIdQueryParameter(),
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 1,
|
pageSize: 1,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import 'package:paperless_api/src/models/models.dart';
|
import 'package:paperless_api/src/models/models.dart';
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ void main() {
|
|||||||
}).toDocumentFilter(),
|
}).toDocumentFilter(),
|
||||||
equals(
|
equals(
|
||||||
DocumentFilter.initial.copyWith(
|
DocumentFilter.initial.copyWith(
|
||||||
correspondent: const IdQueryParameter.fromId(42),
|
correspondent: const SetIdQueryParameter(id: 42),
|
||||||
documentType: const IdQueryParameter.fromId(69),
|
documentType: const SetIdQueryParameter(id: 69),
|
||||||
storagePath: const IdQueryParameter.fromId(14),
|
storagePath: const SetIdQueryParameter(id: 14),
|
||||||
tags: const TagsQuery.ids(
|
tags: const IdsTagsQuery(
|
||||||
include: [1, 2],
|
include: [1, 2],
|
||||||
exclude: [3, 4],
|
exclude: [3, 4],
|
||||||
),
|
),
|
||||||
@@ -131,10 +131,10 @@ void main() {
|
|||||||
],
|
],
|
||||||
}).toDocumentFilter();
|
}).toDocumentFilter();
|
||||||
final expected = DocumentFilter.initial.copyWith(
|
final expected = DocumentFilter.initial.copyWith(
|
||||||
correspondent: const IdQueryParameter.notAssigned(),
|
correspondent: const NotAssignedIdQueryParameter(),
|
||||||
documentType: const IdQueryParameter.notAssigned(),
|
documentType: const NotAssignedIdQueryParameter(),
|
||||||
storagePath: const IdQueryParameter.notAssigned(),
|
storagePath: const NotAssignedIdQueryParameter(),
|
||||||
tags: const TagsQuery.notAssigned(),
|
tags: const NotAssignedTagsQuery(),
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
actual,
|
actual,
|
||||||
@@ -148,10 +148,10 @@ void main() {
|
|||||||
expect(
|
expect(
|
||||||
SavedView.fromDocumentFilter(
|
SavedView.fromDocumentFilter(
|
||||||
DocumentFilter(
|
DocumentFilter(
|
||||||
correspondent: const IdQueryParameter.fromId(1),
|
correspondent: const SetIdQueryParameter(id: 1),
|
||||||
documentType: const IdQueryParameter.fromId(2),
|
documentType: const SetIdQueryParameter(id: 2),
|
||||||
storagePath: const IdQueryParameter.fromId(3),
|
storagePath: const SetIdQueryParameter(id: 3),
|
||||||
tags: const TagsQuery.ids(
|
tags: const IdsTagsQuery(
|
||||||
include: [4, 5],
|
include: [4, 5],
|
||||||
exclude: [6, 7, 8],
|
exclude: [6, 7, 8],
|
||||||
),
|
),
|
||||||
@@ -202,9 +202,9 @@ void main() {
|
|||||||
expect(
|
expect(
|
||||||
SavedView.fromDocumentFilter(
|
SavedView.fromDocumentFilter(
|
||||||
const DocumentFilter(
|
const DocumentFilter(
|
||||||
correspondent: IdQueryParameter.unset(),
|
correspondent: UnsetIdQueryParameter(),
|
||||||
documentType: IdQueryParameter.unset(),
|
documentType: UnsetIdQueryParameter(),
|
||||||
storagePath: IdQueryParameter.unset(),
|
storagePath: UnsetIdQueryParameter(),
|
||||||
tags: IdsTagsQuery(),
|
tags: IdsTagsQuery(),
|
||||||
sortField: SortField.created,
|
sortField: SortField.created,
|
||||||
sortOrder: SortOrder.descending,
|
sortOrder: SortOrder.descending,
|
||||||
@@ -233,10 +233,10 @@ void main() {
|
|||||||
expect(
|
expect(
|
||||||
SavedView.fromDocumentFilter(
|
SavedView.fromDocumentFilter(
|
||||||
const DocumentFilter(
|
const DocumentFilter(
|
||||||
correspondent: IdQueryParameter.notAssigned(),
|
correspondent: NotAssignedIdQueryParameter(),
|
||||||
documentType: IdQueryParameter.notAssigned(),
|
documentType: NotAssignedIdQueryParameter(),
|
||||||
storagePath: IdQueryParameter.notAssigned(),
|
storagePath: NotAssignedIdQueryParameter(),
|
||||||
tags: TagsQuery.notAssigned(),
|
tags: NotAssignedTagsQuery(),
|
||||||
sortField: SortField.created,
|
sortField: SortField.created,
|
||||||
sortOrder: SortOrder.ascending,
|
sortOrder: SortOrder.ascending,
|
||||||
),
|
),
|
||||||
|
|||||||
56
pubspec.lock
56
pubspec.lock
@@ -1459,6 +1459,62 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.1"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
sha256: b7f41bad7e521d205998772545de63ff4e6c97714775902c199353f8bf1511ac
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
shared_preferences_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_android
|
||||||
|
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
shared_preferences_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_foundation
|
||||||
|
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.4"
|
||||||
|
shared_preferences_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_linux
|
||||||
|
sha256: c2eb5bf57a2fe9ad6988121609e47d3e07bb3bdca5b6f8444e4cf302428a128a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
|
shared_preferences_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_platform_interface
|
||||||
|
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
|
shared_preferences_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_web
|
||||||
|
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
shared_preferences_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_windows
|
||||||
|
sha256: f763a101313bd3be87edffe0560037500967de9c394a714cd598d945517f694f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ dependencies:
|
|||||||
defer_pointer: ^0.0.2
|
defer_pointer: ^0.0.2
|
||||||
transparent_image: ^2.0.1
|
transparent_image: ^2.0.1
|
||||||
flutter_animate: ^4.2.0+1
|
flutter_animate: ^4.2.0+1
|
||||||
|
shared_preferences: ^2.2.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
intl: ^0.18.1
|
intl: ^0.18.1
|
||||||
|
|||||||
Reference in New Issue
Block a user