added support for simultan downloads in files and talk, support for background downloads, enhanced loading in files with retry

This commit is contained in:
2026-07-06 15:43:17 +02:00
parent 614ab159af
commit 124b1a5177
34 changed files with 1866 additions and 409 deletions
+41
View File
@@ -3,11 +3,14 @@ import 'dart:io';
import 'package:dio/dio.dart';
import 'package:http/http.dart' as http;
import 'package:nextcloud/nextcloud.dart';
import '../api_error.dart';
import '../marianumcloud/talk/talk_error.dart';
import 'app_exception.dart';
import 'auth_exception.dart';
import 'network_exception.dart';
import 'not_found_exception.dart';
import 'parse_exception.dart';
import 'server_exception.dart';
import 'talk_exception.dart';
@@ -51,6 +54,33 @@ AppException? _dioToAppException(DioException error) {
}
}
/// The nextcloud/dynamite clients throw [DynamiteApiException] on non-2xx.
/// Its toString() dumps every response header, so the details keep only the
/// status plus a trimmed body preview (same format as the Talk API errors).
AppException _dynamiteToAppException(DynamiteApiException error) {
final status = error.statusCode;
final body = error.body.replaceAll(RegExp(r'\s+'), ' ').trim();
final preview = body.length > 500 ? '${body.substring(0, 500)}' : body;
final detail = body.isEmpty ? 'HTTP $status' : 'HTTP $status body=$preview';
switch (status) {
case 401:
return AuthException.unauthorized(technicalDetails: detail);
case 403:
return AuthException.forbidden(technicalDetails: detail);
case 404:
return NotFoundException(technicalDetails: detail);
case 429:
return ServerException(
statusCode: status,
userMessage:
'Zu viele Anfragen. Bitte warte einen Moment, bevor du es erneut versuchst.',
technicalDetails: detail,
);
default:
return ServerException(statusCode: status, technicalDetails: detail);
}
}
String errorToUserMessage(Object? error, {String fallback = _defaultFallback}) {
if (error == null) return fallback;
if (error is AppException) return error.userMessage;
@@ -62,6 +92,10 @@ String errorToUserMessage(Object? error, {String fallback = _defaultFallback}) {
if (mapped != null) return mapped.userMessage;
}
if (error is DynamiteApiException) {
return _dynamiteToAppException(error).userMessage;
}
if (error is SocketException) {
return const NetworkException().userMessage;
}
@@ -92,6 +126,10 @@ String? errorToTechnicalDetails(Object? error) {
final mapped = _dioToAppException(error);
if (mapped != null) return mapped.technicalDetails ?? mapped.toString();
}
if (error is DynamiteApiException) {
final mapped = _dynamiteToAppException(error);
return mapped.technicalDetails ?? mapped.toString();
}
return error.toString();
}
@@ -102,6 +140,9 @@ bool errorAllowsRetry(Object? error) {
final mapped = _dioToAppException(error);
if (mapped != null) return mapped.allowRetry;
}
if (error is DynamiteApiException) {
return _dynamiteToAppException(error).allowRetry;
}
return true;
}