fix: Add custom fields, translations, add app logs to login routes

This commit is contained in:
Anton Stubenbord
2023-12-10 12:48:32 +01:00
parent 5e5e5d2df3
commit 9f6b95f506
102 changed files with 2399 additions and 1088 deletions

View File

@@ -1,192 +1,190 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository_state.dart';
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
class LabelRepository extends PersistentRepository<LabelRepositoryState> {
class LabelRepository extends ChangeNotifier {
final PaperlessLabelsApi _api;
LabelRepository(this._api) : super(const LabelRepositoryState());
Map<int, Correspondent> correspondents = {};
Map<int, DocumentType> documentTypes = {};
Map<int, StoragePath> storagePaths = {};
Map<int, Tag> tags = {};
Future<void> initialize() async {
LabelRepository(this._api);
// Resets the repository to its initial state and loads all data from the API.
Future<void> initialize({
required bool loadCorrespondents,
required bool loadDocumentTypes,
required bool loadStoragePaths,
required bool loadTags,
}) async {
correspondents = {};
documentTypes = {};
storagePaths = {};
tags = {};
await Future.wait([
findAllCorrespondents(),
findAllDocumentTypes(),
findAllStoragePaths(),
findAllTags(),
if (loadCorrespondents) findAllCorrespondents(),
if (loadDocumentTypes) findAllDocumentTypes(),
if (loadStoragePaths) findAllStoragePaths(),
if (loadTags) findAllTags(),
]);
}
Future<Tag> createTag(Tag object) async {
final created = await _api.saveTag(object);
final updatedState = {...state.tags}
..putIfAbsent(created.id!, () => created);
emit(state.copyWith(tags: updatedState));
tags = {...tags, created.id!: created};
notifyListeners();
return created;
}
Future<int> deleteTag(Tag tag) async {
await _api.deleteTag(tag);
final updatedState = {...state.tags}..removeWhere((k, v) => k == tag.id);
emit(state.copyWith(tags: updatedState));
tags.remove(tag.id!);
notifyListeners();
return tag.id!;
}
Future<Tag?> findTag(int id) async {
final tag = await _api.getTag(id);
if (tag != null) {
final updatedState = {...state.tags}..[id] = tag;
emit(state.copyWith(tags: updatedState));
tags = {...tags, id: tag};
notifyListeners();
return tag;
}
return null;
}
Future<Iterable<Tag>> findAllTags([Iterable<int>? ids]) async {
final tags = await _api.getTags(ids);
final updatedState = {...state.tags}
..addEntries(tags.map((e) => MapEntry(e.id!, e)));
emit(state.copyWith(tags: updatedState));
return tags;
final data = await _api.getTags(ids);
tags = {for (var tag in data) tag.id!: tag};
notifyListeners();
return data;
}
Future<Tag> updateTag(Tag tag) async {
final updated = await _api.updateTag(tag);
final updatedState = {...state.tags}..update(updated.id!, (_) => updated);
emit(state.copyWith(tags: updatedState));
tags = {...tags, updated.id!: updated};
notifyListeners();
return updated;
}
Future<Correspondent> createCorrespondent(Correspondent correspondent) async {
final created = await _api.saveCorrespondent(correspondent);
final updatedState = {...state.correspondents}
..putIfAbsent(created.id!, () => created);
emit(state.copyWith(correspondents: updatedState));
correspondents = {...correspondents, created.id!: created};
notifyListeners();
return created;
}
Future<int> deleteCorrespondent(Correspondent correspondent) async {
await _api.deleteCorrespondent(correspondent);
final updatedState = {...state.correspondents}
..removeWhere((k, v) => k == correspondent.id);
emit(state.copyWith(correspondents: updatedState));
correspondents.remove(correspondent.id!);
notifyListeners();
return correspondent.id!;
}
Future<Correspondent?> findCorrespondent(int id) async {
final correspondent = await _api.getCorrespondent(id);
if (correspondent != null) {
final updatedState = {...state.correspondents}..[id] = correspondent;
emit(state.copyWith(correspondents: updatedState));
correspondents = {...correspondents, id: correspondent};
notifyListeners();
return correspondent;
}
return null;
}
Future<Iterable<Correspondent>> findAllCorrespondents(
[Iterable<int>? ids]) async {
final correspondents = await _api.getCorrespondents(ids);
final updatedState = {
...state.correspondents,
}..addAll({for (var element in correspondents) element.id!: element});
emit(state.copyWith(correspondents: updatedState));
return correspondents;
Future<Iterable<Correspondent>> findAllCorrespondents() async {
final data = await _api.getCorrespondents();
correspondents = {for (var element in data) element.id!: element};
notifyListeners();
return data;
}
Future<Correspondent> updateCorrespondent(Correspondent correspondent) async {
final updated = await _api.updateCorrespondent(correspondent);
final updatedState = {...state.correspondents}
..update(updated.id!, (_) => updated);
emit(state.copyWith(correspondents: updatedState));
correspondents = {...correspondents, updated.id!: updated};
notifyListeners();
return updated;
}
Future<DocumentType> createDocumentType(DocumentType documentType) async {
final created = await _api.saveDocumentType(documentType);
final updatedState = {...state.documentTypes}
..putIfAbsent(created.id!, () => created);
emit(state.copyWith(documentTypes: updatedState));
documentTypes = {...documentTypes, created.id!: created};
notifyListeners();
return created;
}
Future<int> deleteDocumentType(DocumentType documentType) async {
await _api.deleteDocumentType(documentType);
final updatedState = {...state.documentTypes}
..removeWhere((k, v) => k == documentType.id);
emit(state.copyWith(documentTypes: updatedState));
documentTypes.remove(documentType.id!);
notifyListeners();
return documentType.id!;
}
Future<DocumentType?> findDocumentType(int id) async {
final documentType = await _api.getDocumentType(id);
if (documentType != null) {
final updatedState = {...state.documentTypes}..[id] = documentType;
emit(state.copyWith(documentTypes: updatedState));
documentTypes = {...documentTypes, id: documentType};
notifyListeners();
return documentType;
}
return null;
}
Future<Iterable<DocumentType>> findAllDocumentTypes(
[Iterable<int>? ids]) async {
final documentTypes = await _api.getDocumentTypes(ids);
final updatedState = {...state.documentTypes}
..addEntries(documentTypes.map((e) => MapEntry(e.id!, e)));
emit(state.copyWith(documentTypes: updatedState));
Future<Iterable<DocumentType>> findAllDocumentTypes() async {
final documentTypes = await _api.getDocumentTypes();
this.documentTypes = {
for (var dt in documentTypes) dt.id!: dt,
};
notifyListeners();
return documentTypes;
}
Future<DocumentType> updateDocumentType(DocumentType documentType) async {
final updated = await _api.updateDocumentType(documentType);
final updatedState = {...state.documentTypes}
..update(updated.id!, (_) => updated);
emit(state.copyWith(documentTypes: updatedState));
documentTypes = {...documentTypes, updated.id!: updated};
notifyListeners();
return updated;
}
Future<StoragePath> createStoragePath(StoragePath storagePath) async {
final created = await _api.saveStoragePath(storagePath);
final updatedState = {...state.storagePaths}
..putIfAbsent(created.id!, () => created);
emit(state.copyWith(storagePaths: updatedState));
storagePaths = {...storagePaths, created.id!: created};
notifyListeners();
return created;
}
Future<int> deleteStoragePath(StoragePath storagePath) async {
await _api.deleteStoragePath(storagePath);
final updatedState = {...state.storagePaths}
..removeWhere((k, v) => k == storagePath.id);
emit(state.copyWith(storagePaths: updatedState));
storagePaths.remove(storagePath.id!);
notifyListeners();
return storagePath.id!;
}
Future<StoragePath?> findStoragePath(int id) async {
final storagePath = await _api.getStoragePath(id);
if (storagePath != null) {
final updatedState = {...state.storagePaths}..[id] = storagePath;
emit(state.copyWith(storagePaths: updatedState));
storagePaths = {...storagePaths, id: storagePath};
notifyListeners();
return storagePath;
}
return null;
}
Future<Iterable<StoragePath>> findAllStoragePaths(
[Iterable<int>? ids]) async {
final storagePaths = await _api.getStoragePaths(ids);
final updatedState = {...state.storagePaths}
..addEntries(storagePaths.map((e) => MapEntry(e.id!, e)));
emit(state.copyWith(storagePaths: updatedState));
Future<Iterable<StoragePath>> findAllStoragePaths() async {
final storagePaths = await _api.getStoragePaths();
this.storagePaths = {
for (var sp in storagePaths) sp.id!: sp,
};
notifyListeners();
return storagePaths;
}
Future<StoragePath> updateStoragePath(StoragePath storagePath) async {
final updated = await _api.updateStoragePath(storagePath);
final updatedState = {...state.storagePaths}
..update(updated.id!, (_) => updated);
emit(state.copyWith(storagePaths: updatedState));
storagePaths = {...storagePaths, updated.id!: updated};
notifyListeners();
return updated;
}

View File

@@ -1,18 +0,0 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paperless_api/paperless_api.dart';
part 'label_repository_state.freezed.dart';
part 'label_repository_state.g.dart';
@freezed
class LabelRepositoryState with _$LabelRepositoryState {
const factory LabelRepositoryState({
@Default({}) Map<int, Correspondent> correspondents,
@Default({}) Map<int, DocumentType> documentTypes,
@Default({}) Map<int, Tag> tags,
@Default({}) Map<int, StoragePath> storagePaths,
}) = _LabelRepositoryState;
factory LabelRepositoryState.fromJson(Map<String, dynamic> json) =>
_$LabelRepositoryStateFromJson(json);
}

View File

@@ -1,95 +1,54 @@
import 'dart:async';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/cupertino.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
part 'saved_view_repository_state.dart';
part 'saved_view_repository.g.dart';
part 'saved_view_repository.freezed.dart';
class SavedViewRepository
extends PersistentRepository<SavedViewRepositoryState> {
class SavedViewRepository extends ChangeNotifier {
final PaperlessSavedViewsApi _api;
final Completer _initialized = Completer();
Map<int, SavedView> savedViews = {};
SavedViewRepository(this._api)
: super(const SavedViewRepositoryState.initial());
SavedViewRepository(this._api);
Future<void> initialize() async {
try {
await findAll();
_initialized.complete();
} catch (e) {
_initialized.completeError(e);
emit(const SavedViewRepositoryState.error());
}
await findAll();
}
Future<SavedView> create(SavedView object) async {
await _initialized.future;
final created = await _api.save(object);
final updatedState = {...state.savedViews}
..putIfAbsent(created.id!, () => created);
emit(SavedViewRepositoryState.loaded(savedViews: updatedState));
savedViews = {...savedViews, created.id!: created};
notifyListeners();
return created;
}
Future<SavedView> update(SavedView object) async {
await _initialized.future;
final updated = await _api.update(object);
final updatedState = {...state.savedViews}..update(
updated.id!,
(_) => updated,
ifAbsent: () => updated,
);
emit(SavedViewRepositoryState.loaded(savedViews: updatedState));
savedViews = {...savedViews, updated.id!: updated};
notifyListeners();
return updated;
}
Future<int> delete(SavedView view) async {
await _initialized.future;
await _api.delete(view);
final updatedState = {...state.savedViews}..remove(view.id);
emit(SavedViewRepositoryState.loaded(savedViews: updatedState));
savedViews.remove(view.id!);
notifyListeners();
return view.id!;
}
Future<SavedView?> find(int id) async {
await _initialized.future;
final found = await _api.find(id);
if (found != null) {
final updatedState = {...state.savedViews}
..update(id, (_) => found, ifAbsent: () => found);
emit(SavedViewRepositoryState.loaded(savedViews: updatedState));
savedViews = {...savedViews, id: found};
notifyListeners();
}
return found;
}
Future<Iterable<SavedView>> findAll([Iterable<int>? ids]) async {
final found = await _api.findAll(ids);
final updatedState = {
...state.savedViews,
...{for (final view in found) view.id!: view},
savedViews = {
for (final view in found) view.id!: view,
};
emit(SavedViewRepositoryState.loaded(savedViews: updatedState));
notifyListeners();
return found;
}
// @override
// Future<void> clear() async {
// await _initialized.future;
// await super.clear();
// emit(const SavedViewRepositoryState.initial());
// }
// @override
// SavedViewRepositoryState? fromJson(Map<String, dynamic> json) {
// return SavedViewRepositoryState.fromJson(json);
// }
// @override
// Map<String, dynamic>? toJson(SavedViewRepositoryState state) {
// return state.toJson();
// }
}

View File

@@ -1,22 +0,0 @@
part of 'saved_view_repository.dart';
@freezed
class SavedViewRepositoryState with _$SavedViewRepositoryState {
const factory SavedViewRepositoryState.initial({
@Default({}) Map<int, SavedView> savedViews,
}) = _Initial;
const factory SavedViewRepositoryState.loading({
@Default({}) Map<int, SavedView> savedViews,
}) = _Loading;
const factory SavedViewRepositoryState.loaded({
@Default({}) Map<int, SavedView> savedViews,
}) = _Loaded;
const factory SavedViewRepositoryState.error({
@Default({}) Map<int, SavedView> savedViews,
}) = _Error;
factory SavedViewRepositoryState.fromJson(Map<String, dynamic> json) =>
_$SavedViewRepositoryStateFromJson(json);
}

View File

@@ -1,30 +1,45 @@
import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
import 'package:paperless_mobile/features/logging/data/logger.dart';
part 'user_repository_state.dart';
/// Repository for new users (API v3, server version 1.14.2+)
class UserRepository extends PersistentRepository<UserRepositoryState> {
final PaperlessUserApiV3 _userApiV3;
final PaperlessUserApi _userApi;
UserRepository(this._userApiV3) : super(const UserRepositoryState());
UserRepository(this._userApi) : super(const UserRepositoryState());
Future<void> initialize() async {
await findAll();
}
Future<Iterable<UserModel>> findAll() async {
final users = await _userApiV3.findAll();
emit(state.copyWith(users: {for (var e in users) e.id: e}));
return users;
if (_userApi is PaperlessUserApiV3Impl) {
final users = await (_userApi as PaperlessUserApiV3Impl).findAll();
emit(state.copyWith(users: {for (var e in users) e.id: e}));
return users;
}
logger.fw(
"Tried to access API v3 features while using an older API version.",
className: 'UserRepository',
methodName: 'findAll',
);
return [];
}
Future<UserModel?> find(int id) async {
final user = await _userApiV3.find(id);
emit(state.copyWith(users: state.users..[id] = user));
return user;
if (_userApi is PaperlessUserApiV3Impl) {
final user = await (_userApi as PaperlessUserApiV3Impl).find(id);
emit(state.copyWith(users: state.users..[id] = user));
return user;
}
logger.fw(
"Tried to access API v3 features while using an older API version.",
className: 'UserRepository',
methodName: 'findAll',
);
return null;
}
// @override