mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-11 10:08:02 -06:00
WIP - Add system notifications for document upload progress/status
This commit is contained in:
@@ -22,3 +22,5 @@ export 'paperless_server_information_model.dart';
|
||||
export 'paperless_server_statistics_model.dart';
|
||||
export 'saved_view_model.dart';
|
||||
export 'similar_document_model.dart';
|
||||
export 'task/task.dart';
|
||||
export 'task/task_status.dart';
|
||||
|
||||
52
packages/paperless_api/lib/src/models/task/task.dart
Normal file
52
packages/paperless_api/lib/src/models/task/task.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/src/request_utils.dart';
|
||||
import 'task_status.dart';
|
||||
|
||||
part 'task.g.dart';
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class Task extends Equatable {
|
||||
final int id;
|
||||
final String? taskId;
|
||||
final String? taskFileName;
|
||||
final DateTime dateCreated;
|
||||
final DateTime? dateDone;
|
||||
final String? type;
|
||||
final TaskStatus? status;
|
||||
final String? result;
|
||||
final bool acknowledged;
|
||||
@JsonKey(fromJson: tryParseNullable)
|
||||
final int? relatedDocumentId;
|
||||
|
||||
const Task({
|
||||
required this.id,
|
||||
this.taskId,
|
||||
this.taskFileName,
|
||||
required this.dateCreated,
|
||||
this.dateDone,
|
||||
this.type,
|
||||
this.status,
|
||||
this.acknowledged = false,
|
||||
this.relatedDocumentId,
|
||||
this.result,
|
||||
});
|
||||
|
||||
factory Task.fromJson(Map<String, dynamic> json) => _$TaskFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$TaskToJson(this);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
taskId,
|
||||
taskFileName,
|
||||
dateCreated,
|
||||
dateDone,
|
||||
type,
|
||||
status,
|
||||
result,
|
||||
acknowledged,
|
||||
relatedDocumentId,
|
||||
];
|
||||
}
|
||||
43
packages/paperless_api/lib/src/models/task/task.g.dart
Normal file
43
packages/paperless_api/lib/src/models/task/task.g.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'task.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Task _$TaskFromJson(Map<String, dynamic> json) => Task(
|
||||
id: json['id'] as int,
|
||||
taskId: json['task_id'] as String?,
|
||||
taskFileName: json['task_file_name'] as String?,
|
||||
dateCreated: DateTime.parse(json['date_created'] as String),
|
||||
dateDone: json['date_done'] == null
|
||||
? null
|
||||
: DateTime.parse(json['date_done'] as String),
|
||||
type: json['type'] as String?,
|
||||
status: $enumDecodeNullable(_$TaskStatusEnumMap, json['status']),
|
||||
acknowledged: json['acknowledged'] as bool? ?? false,
|
||||
relatedDocumentId:
|
||||
tryParseNullable(json['related_document_id'] as String?),
|
||||
result: json['result'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$TaskToJson(Task instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'task_id': instance.taskId,
|
||||
'task_file_name': instance.taskFileName,
|
||||
'date_created': instance.dateCreated.toIso8601String(),
|
||||
'date_done': instance.dateDone?.toIso8601String(),
|
||||
'type': instance.type,
|
||||
'status': _$TaskStatusEnumMap[instance.status],
|
||||
'result': instance.result,
|
||||
'acknowledged': instance.acknowledged,
|
||||
'related_document_id': instance.relatedDocumentId,
|
||||
};
|
||||
|
||||
const _$TaskStatusEnumMap = {
|
||||
TaskStatus.started: 'STARTED',
|
||||
TaskStatus.pending: 'PENDING',
|
||||
TaskStatus.failure: 'FAILURE',
|
||||
TaskStatus.success: 'SUCCESS',
|
||||
};
|
||||
13
packages/paperless_api/lib/src/models/task/task_status.dart
Normal file
13
packages/paperless_api/lib/src/models/task/task_status.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
@JsonEnum(valueField: 'value')
|
||||
enum TaskStatus {
|
||||
started("STARTED"),
|
||||
pending("PENDING"),
|
||||
failure("FAILURE"),
|
||||
success("SUCCESS");
|
||||
|
||||
final String value;
|
||||
|
||||
const TaskStatus(this.value);
|
||||
}
|
||||
@@ -8,7 +8,9 @@ import 'package:paperless_api/src/models/paged_search_result.dart';
|
||||
import 'package:paperless_api/src/models/similar_document_model.dart';
|
||||
|
||||
abstract class PaperlessDocumentsApi {
|
||||
Future<void> create(
|
||||
/// Uploads a document using a form data request and from server version 1.11.3
|
||||
/// returns the celery task id which can be used to track the status of the document.
|
||||
Future<String?> create(
|
||||
Uint8List documentBytes, {
|
||||
required String filename,
|
||||
required String title,
|
||||
@@ -27,7 +29,9 @@ abstract class PaperlessDocumentsApi {
|
||||
Future<Uint8List> getPreview(int docId);
|
||||
String getThumbnailUrl(int docId);
|
||||
Future<DocumentModel> waitForConsumptionFinished(
|
||||
String filename, String title);
|
||||
String filename,
|
||||
String title,
|
||||
);
|
||||
Future<Uint8List> download(DocumentModel document);
|
||||
|
||||
Future<List<String>> autocomplete(String query, [int limit = 10]);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -6,6 +7,7 @@ import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_api/src/constants.dart';
|
||||
import 'package:paperless_api/src/converters/document_model_json_converter.dart';
|
||||
import 'package:paperless_api/src/converters/similar_document_model_json_converter.dart';
|
||||
import 'package:paperless_api/src/request_utils.dart';
|
||||
|
||||
class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
||||
final Dio client;
|
||||
@@ -13,7 +15,7 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
||||
PaperlessDocumentsApiImpl(this.client);
|
||||
|
||||
@override
|
||||
Future<void> create(
|
||||
Future<String?> create(
|
||||
Uint8List documentBytes, {
|
||||
required String filename,
|
||||
required String title,
|
||||
@@ -46,8 +48,12 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
||||
try {
|
||||
final response =
|
||||
await client.post('/api/documents/post_document/', data: formData);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode == 200) {
|
||||
if (response.data is String && response.data != "OK") {
|
||||
return response.data;
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
throw PaperlessServerException(
|
||||
ErrorCode.documentUploadFailed,
|
||||
httpStatusCode: response.statusCode,
|
||||
|
||||
@@ -9,3 +9,5 @@ export 'saved_views_api/paperless_saved_views_api.dart';
|
||||
export 'saved_views_api/paperless_saved_views_api_impl.dart';
|
||||
export 'server_stats_api/paperless_server_stats_api.dart';
|
||||
export 'server_stats_api/paperless_server_stats_api_impl.dart';
|
||||
export 'tasks_api/paperless_tasks_api.dart';
|
||||
export 'tasks_api/paperless_tasks_api_impl.dart';
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import 'package:paperless_api/src/models/task/task.dart';
|
||||
|
||||
abstract class PaperlessTasksApi {
|
||||
Future<Task?> find({int? id, String? taskId});
|
||||
Future<Iterable<Task>> findAll([Iterable<int>? ids]);
|
||||
Stream<Task> listenForTaskChanges(String taskId);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:paperless_api/src/models/task/task.dart';
|
||||
import 'package:paperless_api/src/models/task/task_status.dart';
|
||||
|
||||
import 'paperless_tasks_api.dart';
|
||||
|
||||
class PaperlessTasksApiImpl implements PaperlessTasksApi {
|
||||
final Dio client;
|
||||
|
||||
const PaperlessTasksApiImpl(this.client);
|
||||
|
||||
@override
|
||||
Future<Task?> find({int? id, String? taskId}) async {
|
||||
assert(id != null || taskId != null);
|
||||
String url = "/api/tasks/";
|
||||
if (taskId != null) {
|
||||
url += "?task_id=$taskId";
|
||||
} else {
|
||||
url += "$id/";
|
||||
}
|
||||
|
||||
final response = await client.get(url);
|
||||
if (response.statusCode == 200) {
|
||||
return Task.fromJson(response.data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<Task>> findAll([Iterable<int>? ids]) async {
|
||||
final response = await client.get("/api/tasks/");
|
||||
if (response.statusCode == 200) {
|
||||
return (response.data as List).map((e) => Task.fromJson(e));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<Task> listenForTaskChanges(String taskId) async* {
|
||||
bool isSuccess = false;
|
||||
while (!isSuccess) {
|
||||
final task = await find(taskId: taskId);
|
||||
if (task == null) {
|
||||
throw Exception("Task with taskId $taskId does not exist.");
|
||||
}
|
||||
yield task;
|
||||
if (task.status == TaskStatus.success) {
|
||||
isSuccess = true;
|
||||
}
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,3 +81,14 @@ class _CollectionFromJsonSerializationParams<T> {
|
||||
|
||||
_CollectionFromJsonSerializationParams(this.fromJson, this.list);
|
||||
}
|
||||
|
||||
int getExtendedVersionNumber(String version) {
|
||||
List versionCells = version.split('.');
|
||||
versionCells = versionCells.map((i) => int.parse(i)).toList();
|
||||
return versionCells[0] * 100000 + versionCells[1] * 1000 + versionCells[2];
|
||||
}
|
||||
|
||||
int? tryParseNullable(String? source, {int? radix}) {
|
||||
if (source == null) return null;
|
||||
return int.tryParse(source, radix: radix);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user