upload<T> method
Execute an upload request. Progress is emitted on uploadProgressStreamProvider. Returns the ApiResult and also updates state.
Implementation
Future<ApiResult<T>> upload<T>(UploadRequest<T> request) async {
_cancelToken = CancelToken();
state = const AsyncValue.loading();
_progressController.add(const UploadProgress.idle());
try {
// Build FormData
final formData = FormData();
// Add extra string fields
request.fields?.forEach((key, value) {
formData.fields.add(MapEntry(key, value));
});
// Add files
for (final file in request.files) {
final entry = await file.toMultipart();
formData.files.add(entry);
}
final dio = ApiClient.instance(request.version);
final response = await dio.request(
request.endpoint,
data: formData,
options: Options(
method: request.method == UploadMethod.post ? 'POST' : 'PUT',
headers: {'Content-Type': 'multipart/form-data', ...?request.headers},
extra: {'noAuth': request.noAuth},
),
cancelToken: _cancelToken,
onSendProgress: (sent, total) {
_progressController.add(UploadProgress(sent: sent, total: total));
if (total > 0 && sent >= total) {
_progressController.add(UploadProgress.done(total));
}
},
);
final raw = response.data as Map<String, dynamic>?;
final message = raw?['message'] as String? ?? '';
dynamic parsed;
if (request.fromJson != null && raw != null) {
try {
parsed = request.fromJson!(raw);
} catch (e) {
dev.log('[upload] Parse error: $e', name: 'server', level: 900);
parsed = null;
}
}
final result = ApiSuccess<T>(
message: message,
statusCode: response.statusCode ?? 200,
data: parsed,
raw: raw);
state = AsyncValue.data(result);
return result;
} on DioException catch (e) {
if (CancelToken.isCancel(e)) {
final result = ApiError<T>(
message: 'Upload cancelled', error: 'cancelled', statusCode: null);
state = AsyncValue.data(result);
return result;
}
final raw = e.response?.data as Map<String, dynamic>?;
final message = raw?['message'] as String? ?? 'Upload failed';
dev.log('[upload] Error: $message', name: 'server', level: 900);
final result = ApiError<T>(
message: message,
error: e.message ?? 'DioException',
statusCode: e.response?.statusCode,
raw: raw,
);
state = AsyncValue.data(result);
return result;
} catch (e) {
dev.log('[upload] Unexpected: $e', name: 'server', level: 1000);
final result =
ApiError<T>(message: 'Unexpected upload error', error: e.toString());
state = AsyncValue.data(result);
return result;
}
}