From 4b76c61e72188c49c983849494777a7a4baffc83 Mon Sep 17 00:00:00 2001 From: John-Dag Addy Date: Wed, 21 Sep 2022 03:35:04 +0000 Subject: [PATCH 01/23] add public_id field to upload params --- example/pubspec.lock | 26 +++++++++++++------------- lib/src/cloudinary_file.dart | 17 ++++++++++++++--- lib/src/cloudinary_public.dart | 5 +++++ pubspec.lock | 24 ++++++++++++------------ 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index de73835..521e254 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -21,7 +21,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: @@ -35,14 +35,14 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" cloudinary_public: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.11.1" + version: "0.12.0" collection: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -155,21 +155,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" multi_image_picker: dependency: "direct main" description: @@ -183,7 +183,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" plugin_platform_interface: dependency: transitive description: @@ -202,7 +202,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -223,21 +223,21 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" typed_data: dependency: transitive description: diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index e24dc2a..a138d70 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -14,6 +14,9 @@ class CloudinaryFile { /// The path of the [File] to be uploaded final String? filePath; + /// The file public id which will be used to name the file + final String? publicId; + /// The file name/path final String? identifier; @@ -50,6 +53,7 @@ class CloudinaryFile { this.byteData, this.bytesData, this.filePath, + this.publicId, this.identifier, this.url, this.tags, @@ -59,11 +63,13 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from future [ByteData] static Future fromFutureByteData(Future byteData, - {String? identifier, + {String? publicId, + String? identifier, CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, List? tags}) async => CloudinaryFile.fromByteData( await byteData, + publicId: publicId, identifier: identifier, resourceType: resourceType, tags: tags, @@ -72,6 +78,7 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from [ByteData] factory CloudinaryFile.fromByteData( ByteData byteData, { + String? publicId, String? identifier, CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, List? tags, @@ -80,6 +87,7 @@ class CloudinaryFile { }) { return CloudinaryFile._( byteData: byteData, + publicId: publicId, identifier: identifier, resourceType: resourceType, tags: tags, @@ -91,6 +99,7 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from [ByteData] factory CloudinaryFile.fromBytesData( List bytesData, { + String? publicId, String? identifier, CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, List? tags, @@ -99,6 +108,7 @@ class CloudinaryFile { }) { return CloudinaryFile._( bytesData: bytesData, + publicId: publicId, identifier: identifier, resourceType: resourceType, tags: tags, @@ -110,6 +120,7 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from [File] path factory CloudinaryFile.fromFile( String path, { + String? publicId, String? identifier, CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, List? tags, @@ -118,6 +129,7 @@ class CloudinaryFile { }) { return CloudinaryFile._( filePath: path, + publicId: publicId, identifier: identifier ??= path.split('/').last, resourceType: resourceType, tags: tags, @@ -144,8 +156,7 @@ class CloudinaryFile { } /// Convert [CloudinaryFile] to [MultipartFile] - Future toMultipartFile( - [String fieldName = 'file']) async { + Future toMultipartFile([String fieldName = 'file']) async { assert( !fromExternalUrl, 'toMultipartFile() not available when uploading from external urls', diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index 044d43c..cb32c21 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -100,6 +100,10 @@ class CloudinaryPublic { ); } + if (file.publicId != null) { + data['public_id'] = file.publicId!; + } + if (file.folder != null) { data['folder'] = file.folder!; } @@ -132,6 +136,7 @@ class CloudinaryPublic { request: { 'url': file.url, 'path': file.filePath, + 'public_id': file.identifier, 'identifier': file.identifier, }, ); diff --git a/pubspec.lock b/pubspec.lock index dca851f..464b3cf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -21,7 +21,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: @@ -35,7 +35,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: @@ -49,7 +49,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -80,28 +80,28 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" sky_engine: dependency: transitive description: flutter @@ -113,7 +113,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -134,21 +134,21 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" typed_data: dependency: transitive description: From bb1c280bb39f680596fc513a8a02c6e9bdb67350 Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Wed, 21 Sep 2022 07:29:49 +0100 Subject: [PATCH 02/23] Bump version --- CHANGELOG.md | 3 +++ README.md | 2 +- example/lib/src/image_picker_example.dart | 12 +++++++----- example/pubspec.yaml | 2 +- lib/src/cloudinary_file.dart | 1 - lib/src/cloudinary_public.dart | 1 - pubspec.yaml | 2 +- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca4e659..8d88ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.13.0 +- add public_id option + ## 0.12.0 - Update dependencies diff --git a/README.md b/README.md index 5f978ae..359f7e4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ secretKey. ## Getting started -Add the dependency `cloudinary_public: ^0.11.0` to your project: +Add the dependency `cloudinary_public: ^0.13.0` to your project: ```dart import 'package:cloudinary_public/cloudinary_public.dart'; diff --git a/example/lib/src/image_picker_example.dart b/example/lib/src/image_picker_example.dart index bc96183..608a45d 100644 --- a/example/lib/src/image_picker_example.dart +++ b/example/lib/src/image_picker_example.dart @@ -15,12 +15,12 @@ class ImagePickerExample extends StatefulWidget { class _ImagePickerExampleState extends State { final picker = ImagePicker(); - PickedFile _pickedFile; + XFile? _pickedFile; bool _uploading = false; double _uploadingPercentage = 0.0; Future getImage() async { - final image = await picker.getImage(source: ImageSource.gallery); + final image = await picker.pickImage(source: ImageSource.gallery); setState(() { if (image != null) { @@ -64,6 +64,8 @@ class _ImagePickerExampleState extends State { } Future _upload() async { + if(_pickedFile == null) return; + setState(() { _uploading = true; }); @@ -71,7 +73,7 @@ class _ImagePickerExampleState extends State { try { final res = await cloudinary.uploadFile( CloudinaryFile.fromFile( - _pickedFile.path, + _pickedFile!.path, folder: 'hello-folder', context: { 'alt': 'Hello', @@ -98,8 +100,8 @@ class _ImagePickerExampleState extends State { Widget _buildImage() { if (kIsWeb) { - return Image.network(_pickedFile.path); + return Image.network(_pickedFile!.path); } - return Image.file(File(_pickedFile.path)); + return Image.file(File(_pickedFile!.path)); } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 16297b3..563d9ba 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index a138d70..ff8bde8 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -1,6 +1,5 @@ import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; /// The recognised file class to be used for this package diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index cb32c21..4875a90 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -6,7 +6,6 @@ import 'package:cloudinary_public/src/progress_callback.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; -import '../cloudinary_public.dart'; import 'multipart_request.dart'; /// The base class for this package diff --git a/pubspec.yaml b/pubspec.yaml index 4ba6243..91aa5e4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: cloudinary_public description: This package allows you to upload media files directly to cloudinary, without exposing your apiKey or secretKey. -version: 0.12.0 +version: 0.13.0 homepage: https://github.com/djade007/cloudinary_public environment: From 3eda390a1e91ba07e239a46f920d798a68f057d2 Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Sun, 23 Oct 2022 21:03:46 +0530 Subject: [PATCH 03/23] - Added function to add file in chunks - Replace https plugin with dio --- example/pubspec.lock | 9 +- lib/src/cloudinary_public.dart | 210 ++++++++++++++++++++++----------- pubspec.lock | 14 +-- pubspec.yaml | 2 +- 4 files changed, 160 insertions(+), 75 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 521e254..4022e07 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "0.12.0" + version: "0.13.0" collection: dependency: transitive description: @@ -64,6 +64,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" + dio: + dependency: transitive + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.6" fake_async: dependency: transitive description: diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index 4875a90..b87390b 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -1,12 +1,12 @@ import 'dart:async'; -import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; import 'package:cloudinary_public/cloudinary_public.dart'; -import 'package:cloudinary_public/src/progress_callback.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:http/http.dart' as http; +import 'package:path/path.dart' as path; -import 'multipart_request.dart'; /// The base class for this package class CloudinaryPublic { @@ -19,6 +19,8 @@ class CloudinaryPublic { /// To cache all the uploaded files in the current class instance Map _uploadedFiles = {}; + static Dio _dio = Dio(); + /// Cloud name from Cloudinary final String _cloudName; @@ -28,17 +30,26 @@ class CloudinaryPublic { /// Defaults to false final bool cache; - /// The http client to be used to upload files - http.Client? client; - CloudinaryPublic( this._cloudName, this._uploadPreset, { this.cache = false, - this.client, }) { - /// set default http client - client ??= http.Client(); + _dio = Dio( + BaseOptions( + baseUrl: _baseUrl, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'multipart/form-data' + }, + ), + ); + } + + String _createUrl(CloudinaryResourceType type) { + return '$_cloudName/' + '${describeEnum(type).toLowerCase()}' + '/upload'; } CloudinaryImage getImage(String publicId) { @@ -62,7 +73,7 @@ class CloudinaryPublic { Future uploadFile( CloudinaryFile file, { String? uploadPreset, - ProgressCallback? onProgress, + Function(int, int)? onProgress, }) async { if (cache) { assert(file.identifier != null, 'identifier is required for caching'); @@ -71,67 +82,29 @@ class CloudinaryPublic { return _uploadedFiles[file.identifier]!.enableCache(); } - final url = '$_baseUrl/$_cloudName/' - '${describeEnum(file.resourceType).toLowerCase()}' - '/upload'; - - final request = MultipartRequest( - 'POST', - Uri.parse(url), - onProgress: (count, total) { - onProgress?.call(count, total); - }, - ); - - request.headers.addAll({ - 'Accept': 'application/json', - }); - - final data = { - 'upload_preset': uploadPreset ?? _uploadPreset, - }; + Map data = generateFormData(file, uploadPreset: uploadPreset); if (file.fromExternalUrl) { data[_fieldName] = file.url!; } else { - request.files.add( - await file.toMultipartFile(_fieldName), - ); - } - - if (file.publicId != null) { - data['public_id'] = file.publicId!; - } - - if (file.folder != null) { - data['folder'] = file.folder!; - } - - if (file.tags != null && file.tags!.isNotEmpty) { - data['tags'] = file.tags!.join(','); - } - - if (file.context != null && file.context!.isNotEmpty) { - String context = ''; - - file.context!.forEach((key, value) { - context += '|$key=$value'; - }); - - // remove the extra `|` at the beginning - data['context'] = context.replaceFirst('|', ''); + data[_fieldName] = await file.toMultipartFile(_fieldName); } - request.fields.addAll(data); - - final sendRequest = await client!.send(request); - - final res = await http.Response.fromStream(sendRequest); + var response = await _dio.post( + _createUrl(file.resourceType), + data: FormData.fromMap(data), + onSendProgress: (int sent, int total) { + print("sent: $sent, total: $total"); + if (onProgress != null) { + onProgress(sent, total); + } + }, + ); - if (res.statusCode != 200) { + if (response.statusCode != 200) { throw CloudinaryException( - res.body, - res.statusCode, + response.data, + response.statusCode ?? 0, request: { 'url': file.url, 'path': file.filePath, @@ -142,7 +115,7 @@ class CloudinaryPublic { } final cloudinaryResponse = CloudinaryResponse.fromMap( - json.decode(res.body), + response.data, ); if (cache) { @@ -156,7 +129,7 @@ class CloudinaryPublic { Future uploadFutureFile( Future file, { String? uploadPreset, - ProgressCallback? onProgress, + Function(int, int)? onProgress, }) async { return uploadFile( await file, @@ -176,4 +149,109 @@ class CloudinaryPublic { ), ); } + + /// Upload file in chunks + /// default chunk size is 10 MB + Future uploadFileInChunks( + CloudinaryFile file, { + String? uploadPreset, + Function(int, int)? onProgress, + int chunkSize = 10000000, // 10MB + }) async { + CloudinaryResponse? cloudinaryResponse; + if (file.filePath == null) return null; + final tempFile = File(file.filePath!); + final fileName = path.basename(file.filePath!); + + Response? finalResponse; + + int _fileSize = tempFile.lengthSync(); // 100MB + + int _maxChunkSize = min(_fileSize, chunkSize); + + int _chunksCount = (_fileSize / _maxChunkSize).ceil(); + + Map data = generateFormData(file, uploadPreset: uploadPreset); + + try { + for (int i = 0; i < _chunksCount; i++) { + print('uploadVideoInChunks chunk $i of $_chunksCount'); + final start = i * _maxChunkSize; + final end = min((i + 1) * _maxChunkSize, _fileSize); + final chunkStream = tempFile.openRead(start, end); + + final formData = FormData.fromMap({ + "file": MultipartFile(chunkStream, end - start, filename: fileName), + ...data + }); + + finalResponse = await _dio.post( + _createUrl(file.resourceType), + data: formData, + options: Options( + headers: { + 'Accept': 'application/json', + 'Content-Type': 'multipart/form-data', + "X-Unique-Upload-Id": file.filePath, + 'Content-Range': 'bytes $start-${end - 1}/$_fileSize', + }, + ), + onSendProgress: (int sent, int total) { + print("sent: $sent, total: $total"); + }, + ); + } + if (finalResponse?.statusCode != 200 || finalResponse == null) { + throw CloudinaryException( + finalResponse?.data, + finalResponse?.statusCode ?? 0, + request: { + 'url': file.url, + 'path': file.filePath, + 'public_id': file.identifier, + 'identifier': file.identifier, + }, + ); + } + + cloudinaryResponse = CloudinaryResponse.fromMap( + finalResponse.data, + ); + } catch (e) { + print("CloudinaryService uploadVideo error: $e"); + throw e; + } + return cloudinaryResponse; + } + + + + /// common function to generate form data + /// Override the default upload preset (when [CloudinaryPublic] is instantiated) with this one (if specified). + Map generateFormData( + CloudinaryFile file, { + String? uploadPreset, + }) { + final Map data = { + 'upload_preset': uploadPreset ?? _uploadPreset, + if (file.publicId != null) 'public_id': file.publicId, + if (file.folder != null) 'folder': file.folder, + if (file.tags != null && file.tags!.isNotEmpty) + 'tags': file.tags!.join(','), + }; + + if (file.context != null && file.context!.isNotEmpty) { + String context = ''; + + file.context!.forEach((key, value) { + context += '|$key=$value'; + }); + + // remove the extra `|` at the beginning + data['context'] = context.replaceFirst('|', ''); + } + + return data; + } + } diff --git a/pubspec.lock b/pubspec.lock index 464b3cf..346aa31 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -43,6 +43,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.6" fake_async: dependency: transitive description: @@ -60,13 +67,6 @@ packages: description: flutter source: sdk version: "0.0.0" - http: - dependency: "direct main" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.5" http_parser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 91aa5e4..0c9c994 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - http: ^0.13.5 + dio: ^4.0.6 dev_dependencies: flutter_test: From d0e95d8779a8dbdc4042cf152188dd2db348812d Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Sun, 23 Oct 2022 21:29:46 +0530 Subject: [PATCH 04/23] - Added ti multipart chunk function --- lib/src/cloudinary_file.dart | 53 +++++++++++++++++++++++++++------- lib/src/cloudinary_public.dart | 4 +-- pubspec.lock | 7 +++++ pubspec.yaml | 1 + 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index ff8bde8..b621a6d 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:cloudinary_public/cloudinary_public.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; @@ -98,7 +101,7 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from [ByteData] factory CloudinaryFile.fromBytesData( List bytesData, { - String? publicId, + String? publicId, String? identifier, CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, List? tags, @@ -155,23 +158,21 @@ class CloudinaryFile { } /// Convert [CloudinaryFile] to [MultipartFile] - Future toMultipartFile([String fieldName = 'file']) async { + Future toMultipartFile([String fieldName = 'file']) async { assert( !fromExternalUrl, 'toMultipartFile() not available when uploading from external urls', ); if (byteData != null) { - return http.MultipartFile.fromBytes( - fieldName, + return MultipartFile.fromBytes( byteData!.buffer.asUint8List(), filename: identifier, ); } if (bytesData != null) { - return http.MultipartFile.fromBytes( - fieldName, + return MultipartFile.fromBytes( bytesData!, filename: identifier, ); @@ -179,17 +180,47 @@ class CloudinaryFile { if (kIsWeb) { final bytes = await http.readBytes(Uri.parse(filePath!)); - return http.MultipartFile.fromBytes( - fieldName, - bytes, + return MultipartFile.fromBytes( + bytes.buffer.asUint8List(), filename: identifier, ); } - return http.MultipartFile.fromPath( - fieldName, + return MultipartFile.fromFile( filePath!, filename: identifier, ); } + + /// Convert to multipart with chunked upload + MultipartFile toMultipartFileChunked( + int start, + int end, + ) { + assert( + !fromExternalUrl, + 'toMultipartFileChunked() not available when uploading from external urls', + ); + Stream> chunkStream; + if (byteData != null) { + chunkStream = Stream.fromIterable( + byteData!.buffer.asInt8List(start, end - start).map((e) => [e]), + ); + } else if (bytesData != null) { + chunkStream = Stream.fromIterable( + bytesData!.map((e) => [e]), + ); + } if(kIsWeb){ + chunkStream = http.readBytes(Uri.parse(filePath!)).asStream(); + + } else { + chunkStream = File(filePath!).openRead(start, end); + } + + return MultipartFile( + chunkStream, + end - start, + filename: identifier, + ); + } } diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index b87390b..91f2b78 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -161,7 +161,6 @@ class CloudinaryPublic { CloudinaryResponse? cloudinaryResponse; if (file.filePath == null) return null; final tempFile = File(file.filePath!); - final fileName = path.basename(file.filePath!); Response? finalResponse; @@ -178,10 +177,9 @@ class CloudinaryPublic { print('uploadVideoInChunks chunk $i of $_chunksCount'); final start = i * _maxChunkSize; final end = min((i + 1) * _maxChunkSize, _fileSize); - final chunkStream = tempFile.openRead(start, end); final formData = FormData.fromMap({ - "file": MultipartFile(chunkStream, end - start, filename: fileName), + "file": file.toMultipartFileChunked(start, end), ...data }); diff --git a/pubspec.lock b/pubspec.lock index 346aa31..a1a2be8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -67,6 +67,13 @@ packages: description: flutter source: sdk version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.5" http_parser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0c9c994..78d5c47 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ dependencies: flutter: sdk: flutter dio: ^4.0.6 + http: ^0.13.5 dev_dependencies: flutter_test: From 90b7fc2ebf89518c09e10b68810a828201f0cdb3 Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Sun, 23 Oct 2022 21:52:20 +0530 Subject: [PATCH 05/23] Fix Issues --- lib/src/cloudinary_file.dart | 1 + lib/src/cloudinary_public.dart | 37 ++++++++++++++------------------ test/cloudinary_public_test.dart | 7 ------ 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index b621a6d..a599b8c 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:typed_data'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:dio/dio.dart'; diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index 91f2b78..b4dff0e 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -1,12 +1,11 @@ import 'dart:async'; import 'dart:io'; import 'dart:math'; +import 'package:path/path.dart' as path; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:path/path.dart' as path; - /// The base class for this package class CloudinaryPublic { @@ -47,7 +46,7 @@ class CloudinaryPublic { } String _createUrl(CloudinaryResourceType type) { - return '$_cloudName/' + return '$_baseUrl/$_cloudName/' '${describeEnum(type).toLowerCase()}' '/upload'; } @@ -82,7 +81,8 @@ class CloudinaryPublic { return _uploadedFiles[file.identifier]!.enableCache(); } - Map data = generateFormData(file, uploadPreset: uploadPreset); + Map data = + generateFormData(file, uploadPreset: uploadPreset); if (file.fromExternalUrl) { data[_fieldName] = file.url!; @@ -93,12 +93,7 @@ class CloudinaryPublic { var response = await _dio.post( _createUrl(file.resourceType), data: FormData.fromMap(data), - onSendProgress: (int sent, int total) { - print("sent: $sent, total: $total"); - if (onProgress != null) { - onProgress(sent, total); - } - }, + onSendProgress: onProgress, ); if (response.statusCode != 200) { @@ -150,7 +145,7 @@ class CloudinaryPublic { ); } - /// Upload file in chunks + /// Upload file in chunks /// default chunk size is 10 MB Future uploadFileInChunks( CloudinaryFile file, { @@ -161,26 +156,29 @@ class CloudinaryPublic { CloudinaryResponse? cloudinaryResponse; if (file.filePath == null) return null; final tempFile = File(file.filePath!); + final fileName = path.basename(file.filePath!); Response? finalResponse; int _fileSize = tempFile.lengthSync(); // 100MB - + int _maxChunkSize = min(_fileSize, chunkSize); int _chunksCount = (_fileSize / _maxChunkSize).ceil(); - Map data = generateFormData(file, uploadPreset: uploadPreset); + Map data = + generateFormData(file, uploadPreset: uploadPreset); try { for (int i = 0; i < _chunksCount; i++) { print('uploadVideoInChunks chunk $i of $_chunksCount'); final start = i * _maxChunkSize; final end = min((i + 1) * _maxChunkSize, _fileSize); + final chunkStream = tempFile.openRead(start, end); final formData = FormData.fromMap({ - "file": file.toMultipartFileChunked(start, end), - ...data + "file": MultipartFile(chunkStream, end - start, filename: fileName), + ...data, }); finalResponse = await _dio.post( @@ -194,11 +192,11 @@ class CloudinaryPublic { 'Content-Range': 'bytes $start-${end - 1}/$_fileSize', }, ), - onSendProgress: (int sent, int total) { - print("sent: $sent, total: $total"); - }, + onSendProgress: onProgress, ); + print('uploadVideoInChunks finalResponse $i $finalResponse'); } + if (finalResponse?.statusCode != 200 || finalResponse == null) { throw CloudinaryException( finalResponse?.data, @@ -222,8 +220,6 @@ class CloudinaryPublic { return cloudinaryResponse; } - - /// common function to generate form data /// Override the default upload preset (when [CloudinaryPublic] is instantiated) with this one (if specified). Map generateFormData( @@ -251,5 +247,4 @@ class CloudinaryPublic { return data; } - } diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index ede742f..4b8310d 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -33,7 +33,6 @@ void main() { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, - client: client, cache: true, ); @@ -60,7 +59,6 @@ void main() { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, - client: client, cache: true, ); @@ -88,7 +86,6 @@ void main() { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, - client: client, cache: true, ); @@ -113,7 +110,6 @@ void main() { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, - client: client, cache: true, ); @@ -137,7 +133,6 @@ void main() { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, - client: client, cache: true, ); @@ -161,7 +156,6 @@ void main() { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, - client: client, cache: true, ); @@ -202,7 +196,6 @@ void main() { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, - client: client, cache: true, ); From f1cbf3a73730c93cb0f20f5a4fc9d9a2f7c5c55d Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Mon, 24 Oct 2022 12:24:01 +0530 Subject: [PATCH 06/23] Update test cases --- lib/src/cloudinary_file.dart | 32 ++++++++++++++++++++++++--- lib/src/cloudinary_public.dart | 38 +++++--------------------------- lib/src/cloudinary_response.dart | 2 ++ test/cloudinary_public_test.dart | 11 +++++---- 4 files changed, 44 insertions(+), 39 deletions(-) diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index a599b8c..6491480 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -167,7 +167,7 @@ class CloudinaryFile { if (byteData != null) { return MultipartFile.fromBytes( - byteData!.buffer.asUint8List(), + byteData?.buffer.asUint8List()?? [], filename: identifier, ); } @@ -211,9 +211,9 @@ class CloudinaryFile { chunkStream = Stream.fromIterable( bytesData!.map((e) => [e]), ); - } if(kIsWeb){ + } + if (kIsWeb) { chunkStream = http.readBytes(Uri.parse(filePath!)).asStream(); - } else { chunkStream = File(filePath!).openRead(start, end); } @@ -224,4 +224,30 @@ class CloudinaryFile { filename: identifier, ); } + + /// common function to generate form data + /// Override the default upload preset (when [CloudinaryPublic] is instantiated) with this one (if specified). + Map toFormData({ + required String uploadPreset, + }) { + final Map data = { + 'upload_preset': uploadPreset, + if (publicId != null) 'public_id': publicId, + if (folder != null) 'folder': folder, + if (tags != null && tags!.isNotEmpty) 'tags': tags!.join(','), + }; + + if (context != null && context!.isNotEmpty) { + String context = ''; + + this.context!.forEach((key, value) { + context += '|$key=$value'; + }); + + // remove the extra `|` at the beginning + data['context'] = context.replaceFirst('|', ''); + } + + return data; + } } diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index b4dff0e..8119088 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -46,9 +46,11 @@ class CloudinaryPublic { } String _createUrl(CloudinaryResourceType type) { - return '$_baseUrl/$_cloudName/' + var url = '$_baseUrl/$_cloudName/' '${describeEnum(type).toLowerCase()}' '/upload'; + print(url); + return url; } CloudinaryImage getImage(String publicId) { @@ -82,7 +84,7 @@ class CloudinaryPublic { } Map data = - generateFormData(file, uploadPreset: uploadPreset); + file.toFormData(uploadPreset: uploadPreset ?? _uploadPreset); if (file.fromExternalUrl) { data[_fieldName] = file.url!; @@ -167,7 +169,7 @@ class CloudinaryPublic { int _chunksCount = (_fileSize / _maxChunkSize).ceil(); Map data = - generateFormData(file, uploadPreset: uploadPreset); + file.toFormData(uploadPreset: uploadPreset ?? _uploadPreset); try { for (int i = 0; i < _chunksCount; i++) { @@ -214,37 +216,9 @@ class CloudinaryPublic { finalResponse.data, ); } catch (e) { - print("CloudinaryService uploadVideo error: $e"); + print("CloudinaryService uploadFileInChunks error: $e"); throw e; } return cloudinaryResponse; } - - /// common function to generate form data - /// Override the default upload preset (when [CloudinaryPublic] is instantiated) with this one (if specified). - Map generateFormData( - CloudinaryFile file, { - String? uploadPreset, - }) { - final Map data = { - 'upload_preset': uploadPreset ?? _uploadPreset, - if (file.publicId != null) 'public_id': file.publicId, - if (file.folder != null) 'folder': file.folder, - if (file.tags != null && file.tags!.isNotEmpty) - 'tags': file.tags!.join(','), - }; - - if (file.context != null && file.context!.isNotEmpty) { - String context = ''; - - file.context!.forEach((key, value) { - context += '|$key=$value'; - }); - - // remove the extra `|` at the beginning - data['context'] = context.replaceFirst('|', ''); - } - - return data; - } } diff --git a/lib/src/cloudinary_response.dart b/lib/src/cloudinary_response.dart index 7031b27..8fedb1f 100644 --- a/lib/src/cloudinary_response.dart +++ b/lib/src/cloudinary_response.dart @@ -74,6 +74,8 @@ class CloudinaryResponse { }; } + + @override String toString() { return toMap().toString(); diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index 4b8310d..21d9770 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -137,8 +137,11 @@ void main() { ); final files = >[]; - final file = CloudinaryFile.fromFutureByteData(Future.value(ByteData(8)), - resourceType: CloudinaryResourceType.Image, identifier: 'image.jpg'); + final file = CloudinaryFile.fromFutureByteData( + Future.value(ByteData(8)), + resourceType: CloudinaryResourceType.Image, + identifier: 'image.jpg', + ); files.add(file); files.add(file); @@ -194,8 +197,8 @@ void main() { test('thumbnail shortcut', () { final cloudinary = CloudinaryPublic( - cloudName, - uploadPreset, + "demo", + "present", cache: true, ); From 05f61d37dbf884a0e50a244f8b4e4bbcd551cc0e Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Thu, 27 Oct 2022 10:06:45 +0530 Subject: [PATCH 07/23] remove keys from test cases --- test/cloudinary_public_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index 21d9770..e234261 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -17,7 +17,7 @@ File getFile() { return file; } -const cloudName = 'demo'; +const cloudName = 'name'; const uploadPreset = 'preset'; void main() { From e2a4e86888f8f001c1a2fcbf8df99c44229a28fe Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Thu, 27 Oct 2022 14:14:11 +0530 Subject: [PATCH 08/23] - Upload file in byte data fix errors - create function to get file size in cloudinary file - Fix test cases - Remove unncessory use of https - Write test case for Cloudinary file size --- .gitignore | 2 +- lib/src/cloudinary_file.dart | 33 ++++++++++++++---------- lib/src/cloudinary_public.dart | 25 +++++++++--------- lib/src/multipart_request.dart | 36 -------------------------- pubspec.lock | 7 ----- pubspec.yaml | 5 +--- test/cloudinary_file_test.dart | 44 ++++++++++++++++++++++++++++++++ test/cloudinary_public_test.dart | 20 ++++++--------- 8 files changed, 86 insertions(+), 86 deletions(-) delete mode 100644 lib/src/multipart_request.dart create mode 100644 test/cloudinary_file_test.dart diff --git a/.gitignore b/.gitignore index f98def8..3146226 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. -#.vscode/ +.vscode/ # Flutter/Dart/Pub related **/doc/api/ diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index 6491480..b546693 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -1,10 +1,10 @@ import 'dart:io'; +// ignore: unnecessary_import import 'dart:typed_data'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:http/http.dart' as http; /// The recognised file class to be used for this package class CloudinaryFile { @@ -50,6 +50,18 @@ class CloudinaryFile { /// Determine if initialized from [CloudinaryFile.fromUrl] bool get fromExternalUrl => url != null; + int get fileSize { + if (byteData != null) { + return byteData!.lengthInBytes; + } else if (bytesData != null) { + return bytesData!.length; + } else if (filePath != null) { + return File(filePath!).lengthSync(); + } else { + return 0; + } + } + /// [CloudinaryFile] instance const CloudinaryFile._({ this.resourceType: CloudinaryResourceType.Auto, @@ -167,7 +179,7 @@ class CloudinaryFile { if (byteData != null) { return MultipartFile.fromBytes( - byteData?.buffer.asUint8List()?? [], + byteData?.buffer.asUint8List() ?? [], filename: identifier, ); } @@ -179,14 +191,6 @@ class CloudinaryFile { ); } - if (kIsWeb) { - final bytes = await http.readBytes(Uri.parse(filePath!)); - return MultipartFile.fromBytes( - bytes.buffer.asUint8List(), - filename: identifier, - ); - } - return MultipartFile.fromFile( filePath!, filename: identifier, @@ -203,18 +207,19 @@ class CloudinaryFile { 'toMultipartFileChunked() not available when uploading from external urls', ); Stream> chunkStream; + if (byteData != null) { + print('toMultipartFileChunked byteData'); chunkStream = Stream.fromIterable( - byteData!.buffer.asInt8List(start, end - start).map((e) => [e]), + [byteData!.buffer.asUint8List(start, end - start)], ); } else if (bytesData != null) { + print('toMultipartFileChunked bytesData'); chunkStream = Stream.fromIterable( bytesData!.map((e) => [e]), ); - } - if (kIsWeb) { - chunkStream = http.readBytes(Uri.parse(filePath!)).asStream(); } else { + print('toMultipartFileChunked filePath'); chunkStream = File(filePath!).openRead(start, end); } diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index 8119088..acac6d7 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'dart:io'; import 'dart:math'; -import 'package:path/path.dart' as path; +// ignore: unused_import +import 'dart:typed_data'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:dio/dio.dart'; @@ -46,10 +46,10 @@ class CloudinaryPublic { } String _createUrl(CloudinaryResourceType type) { - var url = '$_baseUrl/$_cloudName/' + var url = '$_baseUrl/$_cloudName/' '${describeEnum(type).toLowerCase()}' '/upload'; - print(url); + print(url); return url; } @@ -156,13 +156,12 @@ class CloudinaryPublic { int chunkSize = 10000000, // 10MB }) async { CloudinaryResponse? cloudinaryResponse; - if (file.filePath == null) return null; - final tempFile = File(file.filePath!); - final fileName = path.basename(file.filePath!); + + print("uploadFileInChunks: fileSize ${file.fileSize}"); Response? finalResponse; - int _fileSize = tempFile.lengthSync(); // 100MB + int _fileSize = file.fileSize; // 100MB int _maxChunkSize = min(_fileSize, chunkSize); @@ -170,16 +169,14 @@ class CloudinaryPublic { Map data = file.toFormData(uploadPreset: uploadPreset ?? _uploadPreset); - try { for (int i = 0; i < _chunksCount; i++) { print('uploadVideoInChunks chunk $i of $_chunksCount'); final start = i * _maxChunkSize; final end = min((i + 1) * _maxChunkSize, _fileSize); - final chunkStream = tempFile.openRead(start, end); final formData = FormData.fromMap({ - "file": MultipartFile(chunkStream, end - start, filename: fileName), + "file": file.toMultipartFileChunked(start, end), ...data, }); @@ -194,7 +191,11 @@ class CloudinaryPublic { 'Content-Range': 'bytes $start-${end - 1}/$_fileSize', }, ), - onSendProgress: onProgress, + onSendProgress: (sent, total) { + // total progress + final s = sent + i * _maxChunkSize; + onProgress?.call(s, _fileSize); + }, ); print('uploadVideoInChunks finalResponse $i $finalResponse'); } diff --git a/lib/src/multipart_request.dart b/lib/src/multipart_request.dart deleted file mode 100644 index 25ae105..0000000 --- a/lib/src/multipart_request.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:async'; - -import 'package:http/http.dart' as http; - -class MultipartRequest extends http.MultipartRequest { - /// Creates a new [MultipartRequest]. - MultipartRequest( - String method, - Uri url, { - this.onProgress, - }) : super(method, url); - - final void Function(int bytes, int totalBytes)? onProgress; - - /// Freezes all mutable fields and returns a - /// single-subscription [http.ByteStream] - /// that will emit the request body. - @override - http.ByteStream finalize() { - final byteStream = super.finalize(); - if (onProgress == null) return byteStream; - - final total = contentLength; - var bytes = 0; - - final t = StreamTransformer.fromHandlers( - handleData: (List data, EventSink> sink) { - bytes += data.length; - onProgress?.call(bytes, total); - sink.add(data); - }, - ); - final stream = byteStream.transform(t); - return http.ByteStream(stream); - } -} diff --git a/pubspec.lock b/pubspec.lock index a1a2be8..346aa31 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -67,13 +67,6 @@ packages: description: flutter source: sdk version: "0.0.0" - http: - dependency: "direct main" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.5" http_parser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 78d5c47..b4bc404 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,26 +4,23 @@ version: 0.13.0 homepage: https://github.com/djade007/cloudinary_public environment: - sdk: '>=2.12.0 <3.0.0' + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: sdk: flutter dio: ^4.0.6 - http: ^0.13.5 dev_dependencies: flutter_test: sdk: flutter matcher: any - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # To add assets to your package, add an assets section, like this: # assets: # - icon.png diff --git a/test/cloudinary_file_test.dart b/test/cloudinary_file_test.dart new file mode 100644 index 0000000..989dc26 --- /dev/null +++ b/test/cloudinary_file_test.dart @@ -0,0 +1,44 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:cloudinary_public/cloudinary_public.dart'; +import 'package:flutter_test/flutter_test.dart'; + +File getFile() { + File file = File('../test/icon.png'); + try { + file.lengthSync(); + } catch (exception) { + file = File('test/icon.png'); + } + return file; +} + +Future getFutureByteData() async { + final tempFile = getFile(); + Uint8List uIntBytes = tempFile.readAsBytesSync(); + ByteData bytes = (ByteData.view(uIntBytes.buffer)); + return Future.value(bytes); +} + +void main() { + final tempFile = getFile(); + group("Cloudinary file size test", () { + test('uploads an image file', () async { + final file = CloudinaryFile.fromFile(tempFile.path); + expect(file.fileSize, tempFile.lengthSync()); + }); + + test('uploads an image from byte data', () async { + final bytes = await getFutureByteData(); + final file = CloudinaryFile.fromByteData(bytes); + expect(file.fileSize, tempFile.lengthSync()); + }); + + test('uploads an image from bytes data', () async { + final bytes = await getFutureByteData(); + final file = CloudinaryFile.fromBytesData(bytes.buffer.asUint8List()); + expect(file.fileSize, tempFile.lengthSync()); + }); + }); +} diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index e234261..96ad0e4 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -1,11 +1,8 @@ -import 'dart:convert'; import 'dart:io'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:http/http.dart' as http; -import 'package:http/testing.dart'; File getFile() { File file = File('../test/icon.png'); @@ -17,18 +14,17 @@ File getFile() { return file; } +Future getFutureByteData() async { + final tempFile = getFile(); + Uint8List uIntBytes = tempFile.readAsBytesSync(); + ByteData bytes = (ByteData.view(uIntBytes.buffer)); + return Future.value(bytes); +} + const cloudName = 'name'; const uploadPreset = 'preset'; void main() { - // mock http client - final client = MockClient( - (request) async => http.Response( - jsonEncode(_sampleResponse), - 200, - ), - ); - test('uploads an image from external url', () async { final cloudinary = CloudinaryPublic( cloudName, @@ -138,7 +134,7 @@ void main() { final files = >[]; final file = CloudinaryFile.fromFutureByteData( - Future.value(ByteData(8)), + getFutureByteData(), resourceType: CloudinaryResourceType.Image, identifier: 'image.jpg', ); From 97f05145e1cd58fa332a535de342bd2fa87ff24d Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Fri, 28 Oct 2022 16:22:11 +0530 Subject: [PATCH 09/23] - Make identifier required and non null field - create saperate function to get chunk list - Add test cases for upload file in chunks --- lib/src/cloudinary_file.dart | 40 +++++++++++---- lib/src/cloudinary_public.dart | 19 ++++--- test/cloudinary_file_test.dart | 74 ++++++++++++++++++++++++++- test/cloudinary_public_test.dart | 87 ++++++++++++++------------------ 4 files changed, 148 insertions(+), 72 deletions(-) diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index b546693..510ef48 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:math'; // ignore: unnecessary_import import 'dart:typed_data'; @@ -21,7 +22,7 @@ class CloudinaryFile { final String? publicId; /// The file name/path - final String? identifier; + final String identifier; /// An optional folder name where the uploaded asset will be stored. /// The public ID will contain the full path of the uploaded asset, @@ -69,7 +70,7 @@ class CloudinaryFile { this.bytesData, this.filePath, this.publicId, - this.identifier, + required this.identifier, this.url, this.tags, this.folder, @@ -77,11 +78,13 @@ class CloudinaryFile { }); /// Instantiate [CloudinaryFile] from future [ByteData] - static Future fromFutureByteData(Future byteData, - {String? publicId, - String? identifier, - CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, - List? tags}) async => + static Future fromFutureByteData( + Future byteData, { + required String identifier, + String? publicId, + CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, + List? tags, + }) async => CloudinaryFile.fromByteData( await byteData, publicId: publicId, @@ -93,8 +96,8 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from [ByteData] factory CloudinaryFile.fromByteData( ByteData byteData, { + required String identifier, String? publicId, - String? identifier, CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, List? tags, String? folder, @@ -114,8 +117,8 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from [ByteData] factory CloudinaryFile.fromBytesData( List bytesData, { + required String identifier, String? publicId, - String? identifier, CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, List? tags, String? folder, @@ -216,7 +219,7 @@ class CloudinaryFile { } else if (bytesData != null) { print('toMultipartFileChunked bytesData'); chunkStream = Stream.fromIterable( - bytesData!.map((e) => [e]), + [bytesData!.sublist(start, end)], ); } else { print('toMultipartFileChunked filePath'); @@ -255,4 +258,21 @@ class CloudinaryFile { return data; } + + List createChunks( + int _chunksCount, + int _maxChunkSize, + ) { + List _chunks = []; + + for (int i = 0; i < _chunksCount; i++) { + int _start = i * _maxChunkSize; + int _end = min(fileSize, _start + _maxChunkSize); + _chunks.add(toMultipartFileChunked( + _start, + _end, + )); + } + return _chunks; + } } diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index acac6d7..ececa89 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -77,8 +77,6 @@ class CloudinaryPublic { Function(int, int)? onProgress, }) async { if (cache) { - assert(file.identifier != null, 'identifier is required for caching'); - if (_uploadedFiles.containsKey(file.identifier)) return _uploadedFiles[file.identifier]!.enableCache(); } @@ -161,11 +159,12 @@ class CloudinaryPublic { Response? finalResponse; - int _fileSize = file.fileSize; // 100MB + int _maxChunkSize = min(file.fileSize, chunkSize); - int _maxChunkSize = min(_fileSize, chunkSize); + int _chunksCount = (file.fileSize / _maxChunkSize).ceil(); - int _chunksCount = (_fileSize / _maxChunkSize).ceil(); + List? _chunks = + file.createChunks(_chunksCount, _maxChunkSize); Map data = file.toFormData(uploadPreset: uploadPreset ?? _uploadPreset); @@ -173,10 +172,10 @@ class CloudinaryPublic { for (int i = 0; i < _chunksCount; i++) { print('uploadVideoInChunks chunk $i of $_chunksCount'); final start = i * _maxChunkSize; - final end = min((i + 1) * _maxChunkSize, _fileSize); + final end = min((i + 1) * _maxChunkSize, file.fileSize); final formData = FormData.fromMap({ - "file": file.toMultipartFileChunked(start, end), + "file": _chunks[i], ...data, }); @@ -187,14 +186,14 @@ class CloudinaryPublic { headers: { 'Accept': 'application/json', 'Content-Type': 'multipart/form-data', - "X-Unique-Upload-Id": file.filePath, - 'Content-Range': 'bytes $start-${end - 1}/$_fileSize', + "X-Unique-Upload-Id": file.identifier, + 'Content-Range': 'bytes $start-${end - 1}/${file.fileSize}', }, ), onSendProgress: (sent, total) { // total progress final s = sent + i * _maxChunkSize; - onProgress?.call(s, _fileSize); + onProgress?.call(s, file.fileSize); }, ); print('uploadVideoInChunks finalResponse $i $finalResponse'); diff --git a/test/cloudinary_file_test.dart b/test/cloudinary_file_test.dart index 989dc26..0d8f0a3 100644 --- a/test/cloudinary_file_test.dart +++ b/test/cloudinary_file_test.dart @@ -1,9 +1,12 @@ import 'dart:io'; +import 'dart:math'; import 'dart:typed_data'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:flutter_test/flutter_test.dart'; +const chunkSize = 1024 * 1024 * 10; // 10MB + File getFile() { File file = File('../test/icon.png'); try { @@ -21,6 +24,24 @@ Future getFutureByteData() async { return Future.value(bytes); } +// To test video add sample video to test folder +File getVideoFile() { + File file = File('../test/video.mp4'); + try { + file.lengthSync(); + } catch (exception) { + file = File('test/video.mp4'); + } + return file; +} + +Future getFutureVideoByteData() { + final tempFile = getVideoFile(); + Uint8List uIntBytes = tempFile.readAsBytesSync(); + ByteData bytes = (ByteData.view(uIntBytes.buffer)); + return Future.value(bytes); +} + void main() { final tempFile = getFile(); group("Cloudinary file size test", () { @@ -31,14 +52,63 @@ void main() { test('uploads an image from byte data', () async { final bytes = await getFutureByteData(); - final file = CloudinaryFile.fromByteData(bytes); + final file = CloudinaryFile.fromByteData(bytes, identifier: "test"); expect(file.fileSize, tempFile.lengthSync()); }); test('uploads an image from bytes data', () async { final bytes = await getFutureByteData(); - final file = CloudinaryFile.fromBytesData(bytes.buffer.asUint8List()); + final file = CloudinaryFile.fromBytesData( + bytes.buffer.asUint8List(), + identifier: "test", + ); expect(file.fileSize, tempFile.lengthSync()); }); }); + + group("cloudinary chunks test", () { + test("chunks count and size", () async { + // Getting file + File file = getVideoFile(); + CloudinaryFile videoFile = CloudinaryFile.fromFile(file.path); + ByteData byteData = await getFutureVideoByteData(); + CloudinaryFile videoFileFromByteData = CloudinaryFile.fromByteData( + byteData, + identifier: "video.mp4", + ); + + // Values from file + int _maxChunkSize = min(videoFile.fileSize, chunkSize); + int _chunksCount = (videoFile.fileSize / _maxChunkSize).ceil(); + + var chunks = videoFile.createChunks(_chunksCount, _maxChunkSize); + + // count chunk size + int _chunkSize = 0; + chunks.forEach((element) { + _chunkSize += element.length; + }); + + // values from byte data + int _maxChunkSizeFromByteData = + min(videoFileFromByteData.fileSize, chunkSize); + int _chunksCountFromByteData = + (videoFileFromByteData.fileSize / _maxChunkSizeFromByteData).ceil(); + + var chunksFromByteData = videoFileFromByteData.createChunks( + _chunksCountFromByteData, _maxChunkSize); + + int _chunkSizeFromByteData = 0; + chunksFromByteData.forEach((element) { + _chunkSizeFromByteData += element.length; + }); + + // Tests + expect(_chunkSize, videoFile.fileSize); + expect(chunks.length, _chunksCount); + expect(chunks.length, chunksFromByteData.length); + expect(_chunkSize, _chunkSizeFromByteData); + expect(_chunkSizeFromByteData, videoFile.fileSize); + }); + }); } diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index 96ad0e4..808c821 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -1,28 +1,10 @@ -import 'dart:io'; - import 'package:cloudinary_public/cloudinary_public.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -File getFile() { - File file = File('../test/icon.png'); - try { - file.lengthSync(); - } catch (exception) { - file = File('test/icon.png'); - } - return file; -} +import 'cloudinary_file_test.dart'; -Future getFutureByteData() async { - final tempFile = getFile(); - Uint8List uIntBytes = tempFile.readAsBytesSync(); - ByteData bytes = (ByteData.view(uIntBytes.buffer)); - return Future.value(bytes); -} - -const cloudName = 'name'; -const uploadPreset = 'preset'; +const cloudName = 'test'; +const uploadPreset = 'test'; void main() { test('uploads an image from external url', () async { @@ -204,33 +186,38 @@ void main() { 'https://res.cloudinary.com/demo/image/upload/c_thumb,g_face,' 'h_200,w_200/cloudinary_icon'); }); -} -const _sampleResponse = { - 'asset_id': '82345c4e10d4c019658b3334cde497ed9', - 'public_id': 'psryios0nkgpf1h4a3h', - 'version': '1590212116', - 'version_id': 'd5c175f90d3daf799cda96ead698368ea', - 'signature': '08a8183b499d1cd3aa46ea54ab278c14b8cfbba', - 'width': '1668', - 'height': '2500', - 'format': 'jpg', - 'resource_type': 'image', - 'created_at': '2020-05-23T05:35:16Z', - 'tags': [], - 'bytes': '3331383', - 'type': 'upload', - 'etag': '787996e313bcdd299d090b20389tta8d', - 'placeholder': 'false', - 'url': - 'http://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg', - 'secure_url': - 'https://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg', - 'original_filename': '001', - 'context': { - 'custom': { - 'alt': 'image', - 'caption': 'Example image', - } - } -}; + test("Upload file in Chunks", () async { + final cloudinary = CloudinaryPublic( + cloudName, + uploadPreset, + cache: true, + ); + final videoFile = getVideoFile(); + + final file = CloudinaryFile.fromFile( + videoFile.path, + resourceType: CloudinaryResourceType.Video, + tags: ['trip'], + ); + final res = await cloudinary.uploadFileInChunks(file); + expect(res, TypeMatcher()); + }); + + test("Upload file bytes in chunks", () async { + final cloudinary = CloudinaryPublic( + cloudName, + uploadPreset, + cache: true, + ); + final videoBytes = getFutureVideoByteData(); + + final file = await CloudinaryFile.fromFutureByteData( + videoBytes, + resourceType: CloudinaryResourceType.Video, + identifier: 'video.mp4', + ); + final res = await cloudinary.uploadFileInChunks(file); + expect(res, TypeMatcher()); + }); +} From 81829b4dd245a291c83c0a291ad23bab86f4fef7 Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Sat, 29 Oct 2022 09:47:13 +0530 Subject: [PATCH 10/23] Fix chunk size --- lib/src/cloudinary_public.dart | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index ececa89..f6ecde2 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -146,13 +146,26 @@ class CloudinaryPublic { } /// Upload file in chunks - /// default chunk size is 10 MB + /// default chunk size is 20 MB + /// chunk size must be less than 20 MB and greater than 5 MB Future uploadFileInChunks( CloudinaryFile file, { String? uploadPreset, Function(int, int)? onProgress, - int chunkSize = 10000000, // 10MB + int chunkSize = 20000000, // 20MB }) async { + if (chunkSize > 20000000 || chunkSize < 5000000) { + throw CloudinaryException( + 'Chunk size must be less than 20 MB and greater than 5 MB', + 0, + request: { + 'url': file.url, + 'path': file.filePath, + 'public_id': file.identifier, + 'identifier': file.identifier, + }, + ); + } CloudinaryResponse? cloudinaryResponse; print("uploadFileInChunks: fileSize ${file.fileSize}"); From 829b371d316de07a9600c2414ea730d64fe258df Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Sat, 29 Oct 2022 09:56:36 +0530 Subject: [PATCH 11/23] Added current upload index --- .../lib/src/multi_image_picker_example.dart | 2 +- lib/src/cloudinary_public.dart | 19 +++++++++++++++---- lib/src/cloudinary_response.dart | 7 +++++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/example/lib/src/multi_image_picker_example.dart b/example/lib/src/multi_image_picker_example.dart index 31062ac..6235830 100644 --- a/example/lib/src/multi_image_picker_example.dart +++ b/example/lib/src/multi_image_picker_example.dart @@ -104,7 +104,7 @@ class _MultiImagePickerExampleState extends State { .map( (image) => CloudinaryFile.fromFutureByteData( image.getByteData(), - identifier: image.identifier, + identifier: image.identifier ?? "test", ), ) .toList(), diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index f6ecde2..bc878b0 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -74,7 +74,7 @@ class CloudinaryPublic { Future uploadFile( CloudinaryFile file, { String? uploadPreset, - Function(int, int)? onProgress, + ProgressCallback? onProgress, }) async { if (cache) { if (_uploadedFiles.containsKey(file.identifier)) @@ -124,7 +124,7 @@ class CloudinaryPublic { Future uploadFutureFile( Future file, { String? uploadPreset, - Function(int, int)? onProgress, + ProgressCallback? onProgress, }) async { return uploadFile( await file, @@ -137,10 +137,21 @@ class CloudinaryPublic { Future> multiUpload( List> files, { String? uploadPreset, + ProgressCallback? onProgress, + void Function(int index)? currentUploadIndex, }) async { return Future.wait( files.map( - (file) => uploadFutureFile(file, uploadPreset: uploadPreset), + (file) { + if (currentUploadIndex != null) { + currentUploadIndex(files.indexOf(file)); + } + return uploadFutureFile( + file, + uploadPreset: uploadPreset, + onProgress: onProgress, + ); + }, ), ); } @@ -151,7 +162,7 @@ class CloudinaryPublic { Future uploadFileInChunks( CloudinaryFile file, { String? uploadPreset, - Function(int, int)? onProgress, + ProgressCallback? onProgress, int chunkSize = 20000000, // 20MB }) async { if (chunkSize > 20000000 || chunkSize < 5000000) { diff --git a/lib/src/cloudinary_response.dart b/lib/src/cloudinary_response.dart index 8fedb1f..7e181dd 100644 --- a/lib/src/cloudinary_response.dart +++ b/lib/src/cloudinary_response.dart @@ -9,6 +9,7 @@ class CloudinaryResponse { final List tags; final Map context; final bool fromCache; + final Map data; /// Extract and return the image context Map get customContext { @@ -24,6 +25,7 @@ class CloudinaryResponse { required this.url, required this.secureUrl, required this.originalFilename, + required this.data, this.tags: const [], this.context: const {}, this.fromCache: false, @@ -42,6 +44,7 @@ class CloudinaryResponse { ? (data['tags'] as List).map((tag) => tag as String).toList() : [], context: data['context'] is Map ? data['context'] : {}, + data: data, ); } @@ -57,6 +60,7 @@ class CloudinaryResponse { tags: tags, context: context, fromCache: true, + data: data, ); } @@ -71,11 +75,10 @@ class CloudinaryResponse { 'original_filename': originalFilename, 'tags': tags, 'context': context, + 'data': data, }; } - - @override String toString() { return toMap().toString(); From fe378e339e4dafa6417279149e3a3c34ca17993d Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Sat, 29 Oct 2022 10:12:32 +0530 Subject: [PATCH 12/23] Upload Readme and version --- README.md | 28 +++++++++++++++++++++++++++- example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 359f7e4..222890b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ secretKey. ## Getting started -Add the dependency `cloudinary_public: ^0.13.0` to your project: +Add the dependency `cloudinary_public: ^0.20.0` to your project: ```dart import 'package:cloudinary_public/cloudinary_public.dart'; @@ -109,4 +109,30 @@ final res = await cloudinary.uploadFile( }); }, ); +``` + +## Upload In Chunks +Use chunked upload when file size is more then 100 Megabytes. + +By default, the chunk size is set to 20 Megabytes but can be set to as low as 5 Megabytes by using the chunk_size parameter. + +Source: https://cloudinary.com/documentation/upload_images#chunked_asset_upload + +```dart +final res = await cloudinary.uploadFileInChunks( + CloudinaryFile.fromFile( + _pickedFile.path, + folder: 'hello-folder', + context: { + 'alt': 'Hello', + 'caption': 'An example upload in chunks', + }, + ), + chunkSize: 10000000 + onProgress: (count, total) { + setState(() { + _uploadingPercentage = (count / total) * 100; + }); + }, +); ``` \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 4022e07..ffda613 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "0.13.0" + version: "0.20.0" collection: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b4bc404..0e4d0ac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: cloudinary_public description: This package allows you to upload media files directly to cloudinary, without exposing your apiKey or secretKey. -version: 0.13.0 +version: 0.20.0 homepage: https://github.com/djade007/cloudinary_public environment: From 4f4503d4954435e242def0ddd67db8fec49d46eb Mon Sep 17 00:00:00 2001 From: rajan metaliya Date: Wed, 16 Nov 2022 10:43:51 +0530 Subject: [PATCH 13/23] Remove print --- lib/src/cloudinary_file.dart | 3 --- lib/src/cloudinary_public.dart | 6 ------ 2 files changed, 9 deletions(-) diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index 510ef48..49f08de 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -212,17 +212,14 @@ class CloudinaryFile { Stream> chunkStream; if (byteData != null) { - print('toMultipartFileChunked byteData'); chunkStream = Stream.fromIterable( [byteData!.buffer.asUint8List(start, end - start)], ); } else if (bytesData != null) { - print('toMultipartFileChunked bytesData'); chunkStream = Stream.fromIterable( [bytesData!.sublist(start, end)], ); } else { - print('toMultipartFileChunked filePath'); chunkStream = File(filePath!).openRead(start, end); } diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index bc878b0..fe5a5a8 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -49,7 +49,6 @@ class CloudinaryPublic { var url = '$_baseUrl/$_cloudName/' '${describeEnum(type).toLowerCase()}' '/upload'; - print(url); return url; } @@ -179,8 +178,6 @@ class CloudinaryPublic { } CloudinaryResponse? cloudinaryResponse; - print("uploadFileInChunks: fileSize ${file.fileSize}"); - Response? finalResponse; int _maxChunkSize = min(file.fileSize, chunkSize); @@ -194,7 +191,6 @@ class CloudinaryPublic { file.toFormData(uploadPreset: uploadPreset ?? _uploadPreset); try { for (int i = 0; i < _chunksCount; i++) { - print('uploadVideoInChunks chunk $i of $_chunksCount'); final start = i * _maxChunkSize; final end = min((i + 1) * _maxChunkSize, file.fileSize); @@ -220,7 +216,6 @@ class CloudinaryPublic { onProgress?.call(s, file.fileSize); }, ); - print('uploadVideoInChunks finalResponse $i $finalResponse'); } if (finalResponse?.statusCode != 200 || finalResponse == null) { @@ -240,7 +235,6 @@ class CloudinaryPublic { finalResponse.data, ); } catch (e) { - print("CloudinaryService uploadFileInChunks error: $e"); throw e; } return cloudinaryResponse; From ecb29b2948c405231b1a79350a501a43e475c046 Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Wed, 16 Nov 2022 10:30:41 +0000 Subject: [PATCH 14/23] Add dart analysis --- analysis_options.yaml | 32 ++++++++++ example/lib/example.dart | 18 +++--- example/lib/src/image_picker_example.dart | 10 +-- .../lib/src/multi_image_picker_example.dart | 16 ++--- lib/src/cloudinary_file.dart | 38 +++++------ lib/src/cloudinary_public.dart | 26 ++++---- lib/src/cloudinary_resource_type.dart | 2 + lib/src/cloudinary_response.dart | 6 +- lib/src/exceptions/cloudinary_exception.dart | 5 +- lib/src/transformation/cloudinary_image.dart | 6 +- lib/src/transformation/transformation.dart | 12 ++-- pubspec.lock | 16 ++++- pubspec.yaml | 1 + test/cloudinary_file_test.dart | 56 ++++++++-------- test/cloudinary_public_test.dart | 64 ++++++++++--------- 15 files changed, 185 insertions(+), 123 deletions(-) create mode 100644 analysis_options.yaml diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..a014562 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,32 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the modules of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + - avoid_print + - prefer_single_quotes + - always_declare_return_types + - require_trailing_commas + - avoid_dynamic_calls + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/lib/example.dart b/example/lib/example.dart index a16559b..7d5d4dd 100644 --- a/example/lib/example.dart +++ b/example/lib/example.dart @@ -1,9 +1,9 @@ import 'dart:io'; import 'package:cloudinary_public/cloudinary_public.dart'; -import 'package:flutter/services.dart'; +import 'package:flutter/foundation.dart'; -main() async { +void main() async { // set cache as true if you don't want to make an upload call with files of the same filename // in such case if the filepath/identifier has already been uploaded before, you simply get the previously cached response. var cloudinary = @@ -13,14 +13,16 @@ main() async { File file = File(''); try { CloudinaryResponse response = await cloudinary.uploadFile( - CloudinaryFile.fromFile(file.path, - resourceType: CloudinaryResourceType.Image), + CloudinaryFile.fromFile( + file.path, + resourceType: CloudinaryResourceType.Image, + ), ); - print(response.secureUrl); + debugPrint(response.secureUrl); } on CloudinaryException catch (e) { - print(e.message); - print(e.request); + debugPrint(e.message); + debugPrint(e.request.toString()); } // Using Byte Data. For example gotten from: https://pub.dev/packages/multi_image_picker @@ -38,7 +40,7 @@ main() async { .toList(), ); - print(uploadedImages[0].secureUrl); + debugPrint(uploadedImages[0].secureUrl); } class Asset { diff --git a/example/lib/src/image_picker_example.dart b/example/lib/src/image_picker_example.dart index 608a45d..bd44ab5 100644 --- a/example/lib/src/image_picker_example.dart +++ b/example/lib/src/image_picker_example.dart @@ -26,7 +26,7 @@ class _ImagePickerExampleState extends State { if (image != null) { _pickedFile = image; } else { - print('No image selected.'); + debugPrint('No image selected.'); } }); } @@ -64,7 +64,7 @@ class _ImagePickerExampleState extends State { } Future _upload() async { - if(_pickedFile == null) return; + if (_pickedFile == null) return; setState(() { _uploading = true; @@ -86,10 +86,10 @@ class _ImagePickerExampleState extends State { }); }, ); - print(res); + debugPrint(res.toString()); } on CloudinaryException catch (e) { - print(e.message); - print(e.request); + debugPrint(e.message); + debugPrint(e.request.toString()); } setState(() { diff --git a/example/lib/src/multi_image_picker_example.dart b/example/lib/src/multi_image_picker_example.dart index 6235830..212ec5f 100644 --- a/example/lib/src/multi_image_picker_example.dart +++ b/example/lib/src/multi_image_picker_example.dart @@ -39,13 +39,13 @@ class _MultiImagePickerExampleState extends State { maxImages: 300, enableCamera: true, selectedAssets: images, - cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"), + cupertinoOptions: CupertinoOptions(takePhotoIcon: 'chat'), materialOptions: MaterialOptions( - actionBarColor: "#abcdef", - actionBarTitle: "Example App", - allViewTitle: "All Photos", + actionBarColor: '#abcdef', + actionBarTitle: 'Example App', + allViewTitle: 'All Photos', useDetailsView: false, - selectCircleStrokeColor: "#000000", + selectCircleStrokeColor: '#000000', ), ); } on Exception catch (e) { @@ -74,7 +74,7 @@ class _MultiImagePickerExampleState extends State { children: [ Center(child: Text('Error: $_error')), ElevatedButton( - child: Text("Pick images"), + child: Text('Pick images'), onPressed: loadAssets, ), Expanded( @@ -104,7 +104,7 @@ class _MultiImagePickerExampleState extends State { .map( (image) => CloudinaryFile.fromFutureByteData( image.getByteData(), - identifier: image.identifier ?? "test", + identifier: image.identifier ?? 'test', ), ) .toList(), @@ -114,6 +114,6 @@ class _MultiImagePickerExampleState extends State { _uploading = false; }); - print(uploadedImages[0].secureUrl); + debugPrint(uploadedImages[0].secureUrl); } } diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index 49f08de..a172a11 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -65,7 +65,7 @@ class CloudinaryFile { /// [CloudinaryFile] instance const CloudinaryFile._({ - this.resourceType: CloudinaryResourceType.Auto, + this.resourceType = CloudinaryResourceType.Auto, this.byteData, this.bytesData, this.filePath, @@ -82,7 +82,7 @@ class CloudinaryFile { Future byteData, { required String identifier, String? publicId, - CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, + CloudinaryResourceType resourceType = CloudinaryResourceType.Auto, List? tags, }) async => CloudinaryFile.fromByteData( @@ -98,7 +98,7 @@ class CloudinaryFile { ByteData byteData, { required String identifier, String? publicId, - CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, + CloudinaryResourceType resourceType = CloudinaryResourceType.Auto, List? tags, String? folder, Map? context, @@ -119,7 +119,7 @@ class CloudinaryFile { List bytesData, { required String identifier, String? publicId, - CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, + CloudinaryResourceType resourceType = CloudinaryResourceType.Auto, List? tags, String? folder, Map? context, @@ -140,7 +140,7 @@ class CloudinaryFile { String path, { String? publicId, String? identifier, - CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, + CloudinaryResourceType resourceType = CloudinaryResourceType.Auto, List? tags, String? folder, Map? context, @@ -159,7 +159,7 @@ class CloudinaryFile { /// Instantiate [CloudinaryFile] from an external url factory CloudinaryFile.fromUrl( String url, { - CloudinaryResourceType resourceType: CloudinaryResourceType.Auto, + CloudinaryResourceType resourceType = CloudinaryResourceType.Auto, List? tags, String? folder, Map? context, @@ -257,19 +257,21 @@ class CloudinaryFile { } List createChunks( - int _chunksCount, - int _maxChunkSize, + int chunksCount, + int maxChunkSize, ) { - List _chunks = []; - - for (int i = 0; i < _chunksCount; i++) { - int _start = i * _maxChunkSize; - int _end = min(fileSize, _start + _maxChunkSize); - _chunks.add(toMultipartFileChunked( - _start, - _end, - )); + List chunks = []; + + for (int i = 0; i < chunksCount; i++) { + int start = i * maxChunkSize; + int end = min(fileSize, start + maxChunkSize); + chunks.add( + toMultipartFileChunked( + start, + end, + ), + ); } - return _chunks; + return chunks; } } diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index fe5a5a8..d6a4c49 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -16,7 +16,7 @@ class CloudinaryPublic { static const _fieldName = 'file'; /// To cache all the uploaded files in the current class instance - Map _uploadedFiles = {}; + final Map _uploadedFiles = {}; static Dio _dio = Dio(); @@ -76,8 +76,9 @@ class CloudinaryPublic { ProgressCallback? onProgress, }) async { if (cache) { - if (_uploadedFiles.containsKey(file.identifier)) + if (_uploadedFiles.containsKey(file.identifier)) { return _uploadedFiles[file.identifier]!.enableCache(); + } } Map data = @@ -180,22 +181,21 @@ class CloudinaryPublic { Response? finalResponse; - int _maxChunkSize = min(file.fileSize, chunkSize); + int maxChunkSize = min(file.fileSize, chunkSize); - int _chunksCount = (file.fileSize / _maxChunkSize).ceil(); + int chunksCount = (file.fileSize / maxChunkSize).ceil(); - List? _chunks = - file.createChunks(_chunksCount, _maxChunkSize); + List? chunks = file.createChunks(chunksCount, maxChunkSize); Map data = file.toFormData(uploadPreset: uploadPreset ?? _uploadPreset); try { - for (int i = 0; i < _chunksCount; i++) { - final start = i * _maxChunkSize; - final end = min((i + 1) * _maxChunkSize, file.fileSize); + for (int i = 0; i < chunksCount; i++) { + final start = i * maxChunkSize; + final end = min((i + 1) * maxChunkSize, file.fileSize); final formData = FormData.fromMap({ - "file": _chunks[i], + 'file': chunks[i], ...data, }); @@ -206,13 +206,13 @@ class CloudinaryPublic { headers: { 'Accept': 'application/json', 'Content-Type': 'multipart/form-data', - "X-Unique-Upload-Id": file.identifier, + 'X-Unique-Upload-Id': file.identifier, 'Content-Range': 'bytes $start-${end - 1}/${file.fileSize}', }, ), onSendProgress: (sent, total) { // total progress - final s = sent + i * _maxChunkSize; + final s = sent + i * maxChunkSize; onProgress?.call(s, file.fileSize); }, ); @@ -235,7 +235,7 @@ class CloudinaryPublic { finalResponse.data, ); } catch (e) { - throw e; + rethrow; } return cloudinaryResponse; } diff --git a/lib/src/cloudinary_resource_type.dart b/lib/src/cloudinary_resource_type.dart index 4c140e4..2609f29 100644 --- a/lib/src/cloudinary_resource_type.dart +++ b/lib/src/cloudinary_resource_type.dart @@ -1,4 +1,6 @@ /// The various types of cloudinary resource types +// ignore_for_file: constant_identifier_names + enum CloudinaryResourceType { Image, Raw, diff --git a/lib/src/cloudinary_response.dart b/lib/src/cloudinary_response.dart index 7e181dd..e26a6a5 100644 --- a/lib/src/cloudinary_response.dart +++ b/lib/src/cloudinary_response.dart @@ -26,9 +26,9 @@ class CloudinaryResponse { required this.secureUrl, required this.originalFilename, required this.data, - this.tags: const [], - this.context: const {}, - this.fromCache: false, + this.tags = const [], + this.context = const {}, + this.fromCache = false, }); /// Instantiate this class from a map data diff --git a/lib/src/exceptions/cloudinary_exception.dart b/lib/src/exceptions/cloudinary_exception.dart index 63ff94d..22e0e32 100644 --- a/lib/src/exceptions/cloudinary_exception.dart +++ b/lib/src/exceptions/cloudinary_exception.dart @@ -16,7 +16,9 @@ class CloudinaryException implements Exception { /// Extract the error message from cloudinary String? get message { try { - return jsonDecode(responseString)['error']['message']; + final Map json = jsonDecode(responseString); + final Map error = json['error']; + return error['message']; } catch (e) { // unable to extract error message return null; @@ -27,6 +29,7 @@ class CloudinaryException implements Exception { CloudinaryException(this.responseString, this.statusCode, {this.request}); /// `CloudinaryException` summary + @override String toString() { return '($statusCode) ${message ?? responseString}'; } diff --git a/lib/src/transformation/cloudinary_image.dart b/lib/src/transformation/cloudinary_image.dart index bcb3285..462b10d 100644 --- a/lib/src/transformation/cloudinary_image.dart +++ b/lib/src/transformation/cloudinary_image.dart @@ -14,11 +14,11 @@ class CloudinaryImage { CloudinaryImage(String url) { // remove version - _originalUrl = url.replaceFirst(RegExp(r"v\d+/"), ''); + _originalUrl = url.replaceFirst(RegExp(r'v\d+/'), ''); final resource = url.split('/upload/'); assert(resource.length == 2, 'Invalid cloudinary url'); - _path = resource[0] + '/upload/'; + _path = '${resource[0]}/upload/'; _publicId = resource[1]; } @@ -32,7 +32,7 @@ class CloudinaryImage { return Transformation(_path, _publicId); } - Transformation thumbnail({int width: 200, int height: 200}) { + Transformation thumbnail({int width = 200, int height = 200}) { return transform() .width(width) .height(height) diff --git a/lib/src/transformation/transformation.dart b/lib/src/transformation/transformation.dart index 99bd1c1..adc33d9 100644 --- a/lib/src/transformation/transformation.dart +++ b/lib/src/transformation/transformation.dart @@ -3,8 +3,8 @@ import '../../cloudinary_public.dart'; class Transformation { final String _path; final String _publicId; - Map _params = {}; - List> _chains = []; + final Map _params = {}; + final List> _chains = []; Transformation(this._path, this._publicId); @@ -67,10 +67,10 @@ class Transformation { String url = _path; - _chains.forEach((element) { + for (var element in _chains) { url += _values(element); url += '/'; - }); + } url += _publicId; @@ -90,9 +90,9 @@ class Transformation { List values = []; - keys.forEach((key) { + for (var key in keys) { values.add('${key}_${items[key]}'); - }); + } return values.join(','); } diff --git a/pubspec.lock b/pubspec.lock index 346aa31..3d7f7f6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -62,6 +62,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -74,6 +81,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" matcher: dependency: "direct dev" description: @@ -164,4 +178,4 @@ packages: source: hosted version: "2.1.2" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0e4d0ac..b9bde81 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,7 @@ dev_dependencies: flutter_test: sdk: flutter matcher: any + flutter_lints: ^2.0.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/cloudinary_file_test.dart b/test/cloudinary_file_test.dart index 0d8f0a3..5177486 100644 --- a/test/cloudinary_file_test.dart +++ b/test/cloudinary_file_test.dart @@ -5,7 +5,7 @@ import 'dart:typed_data'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:flutter_test/flutter_test.dart'; -const chunkSize = 1024 * 1024 * 10; // 10MB +const chunkSize10 = 1024 * 1024 * 10; // 10MB File getFile() { File file = File('../test/icon.png'); @@ -44,7 +44,7 @@ Future getFutureVideoByteData() { void main() { final tempFile = getFile(); - group("Cloudinary file size test", () { + group('Cloudinary file size test', () { test('uploads an image file', () async { final file = CloudinaryFile.fromFile(tempFile.path); expect(file.fileSize, tempFile.lengthSync()); @@ -52,7 +52,7 @@ void main() { test('uploads an image from byte data', () async { final bytes = await getFutureByteData(); - final file = CloudinaryFile.fromByteData(bytes, identifier: "test"); + final file = CloudinaryFile.fromByteData(bytes, identifier: 'test'); expect(file.fileSize, tempFile.lengthSync()); }); @@ -60,55 +60,57 @@ void main() { final bytes = await getFutureByteData(); final file = CloudinaryFile.fromBytesData( bytes.buffer.asUint8List(), - identifier: "test", + identifier: 'test', ); expect(file.fileSize, tempFile.lengthSync()); }); }); - group("cloudinary chunks test", () { - test("chunks count and size", () async { + group('cloudinary chunks test', () { + test('chunks count and size', () async { // Getting file File file = getVideoFile(); CloudinaryFile videoFile = CloudinaryFile.fromFile(file.path); ByteData byteData = await getFutureVideoByteData(); CloudinaryFile videoFileFromByteData = CloudinaryFile.fromByteData( byteData, - identifier: "video.mp4", + identifier: 'video.mp4', ); // Values from file - int _maxChunkSize = min(videoFile.fileSize, chunkSize); - int _chunksCount = (videoFile.fileSize / _maxChunkSize).ceil(); + int maxChunkSize = min(videoFile.fileSize, chunkSize10); + int chunksCount = (videoFile.fileSize / maxChunkSize).ceil(); - var chunks = videoFile.createChunks(_chunksCount, _maxChunkSize); + var chunks = videoFile.createChunks(chunksCount, maxChunkSize); // count chunk size - int _chunkSize = 0; - chunks.forEach((element) { - _chunkSize += element.length; - }); + int chunkSize = 0; + for (var element in chunks) { + chunkSize += element.length; + } // values from byte data - int _maxChunkSizeFromByteData = - min(videoFileFromByteData.fileSize, chunkSize); - int _chunksCountFromByteData = - (videoFileFromByteData.fileSize / _maxChunkSizeFromByteData).ceil(); + int maxChunkSizeFromByteData = + min(videoFileFromByteData.fileSize, chunkSize10); + int chunksCountFromByteData = + (videoFileFromByteData.fileSize / maxChunkSizeFromByteData).ceil(); var chunksFromByteData = videoFileFromByteData.createChunks( - _chunksCountFromByteData, _maxChunkSize); + chunksCountFromByteData, + maxChunkSize, + ); - int _chunkSizeFromByteData = 0; - chunksFromByteData.forEach((element) { - _chunkSizeFromByteData += element.length; - }); + int chunkSizeFromByteData = 0; + for (var element in chunksFromByteData) { + chunkSizeFromByteData += element.length; + } // Tests - expect(_chunkSize, videoFile.fileSize); - expect(chunks.length, _chunksCount); + expect(chunkSize, videoFile.fileSize); + expect(chunks.length, chunksCount); expect(chunks.length, chunksFromByteData.length); - expect(_chunkSize, _chunkSizeFromByteData); - expect(_chunkSizeFromByteData, videoFile.fileSize); + expect(chunkSize, chunkSizeFromByteData); + expect(chunkSizeFromByteData, videoFile.fileSize); }); }); } diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index 808c821..ae74a8a 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -20,14 +20,14 @@ void main() { ); final res = await cloudinary.uploadFile(file); - expect(res, TypeMatcher()); + expect(res, const TypeMatcher()); // test toString expect(res.toString(), res.toMap().toString()); // test cache final secondUpload = await cloudinary.uploadFile(file); - expect(secondUpload, TypeMatcher()); + expect(secondUpload, const TypeMatcher()); expect(secondUpload.fromCache, true); }); @@ -40,23 +40,23 @@ void main() { cache: true, ); - final file = CloudinaryFile.fromFile(tempFile.path, - resourceType: CloudinaryResourceType.Image, - tags: [ - 'trip' - ], - context: { - 'alt': 'Image', - }); + final file = CloudinaryFile.fromFile( + tempFile.path, + resourceType: CloudinaryResourceType.Image, + tags: ['trip'], + context: { + 'alt': 'Image', + }, + ); final res = await cloudinary.uploadFile(file); - expect(res, TypeMatcher()); + expect(res, const TypeMatcher()); // test toString expect(res.toString(), res.toMap().toString()); // test cache final secondUpload = await cloudinary.uploadFile(file); - expect(secondUpload, TypeMatcher()); + expect(secondUpload, const TypeMatcher()); expect(secondUpload.fromCache, true); }); @@ -67,10 +67,13 @@ void main() { cache: true, ); - final file = CloudinaryFile.fromFile(tempFile.path, - resourceType: CloudinaryResourceType.Image, tags: ['trip']); + final file = CloudinaryFile.fromFile( + tempFile.path, + resourceType: CloudinaryResourceType.Image, + tags: ['trip'], + ); final res = await cloudinary.uploadFile(file); - expect(res, TypeMatcher()); + expect(res, const TypeMatcher()); // test toString expect(res.toString(), res.toMap().toString()); @@ -80,7 +83,7 @@ void main() { file, uploadPreset: 'another_preset', ); - expect(secondUpload, TypeMatcher()); + expect(secondUpload, const TypeMatcher()); expect(secondUpload.fromCache, true); }); @@ -102,9 +105,9 @@ void main() { expect(uploadedFiles.length, 2); - expect(uploadedFiles[0], TypeMatcher()); + expect(uploadedFiles[0], const TypeMatcher()); - expect(uploadedFiles[1], TypeMatcher()); + expect(uploadedFiles[1], const TypeMatcher()); }); test('upload multiple image byteData', () async { @@ -128,9 +131,9 @@ void main() { expect(uploadedFiles.length, 2); - expect(uploadedFiles[0], TypeMatcher()); + expect(uploadedFiles[0], const TypeMatcher()); - expect(uploadedFiles[1], TypeMatcher()); + expect(uploadedFiles[1], const TypeMatcher()); }); test('Test transformation', () { @@ -167,16 +170,17 @@ void main() { .generate(); expect( - 'https://res.cloudinary.com/demo/image/upload/c_thumb,g_face,h_150,' - 'w_150/r_20/e_sepia/e_brightness:200,g_south_east,l_cloudinary_icon,' - 'o_60,w_50,x_5,y_5/a_10/front_face.png', - url); + 'https://res.cloudinary.com/demo/image/upload/c_thumb,g_face,h_150,' + 'w_150/r_20/e_sepia/e_brightness:200,g_south_east,l_cloudinary_icon,' + 'o_60,w_50,x_5,y_5/a_10/front_face.png', + url, + ); }); test('thumbnail shortcut', () { final cloudinary = CloudinaryPublic( - "demo", - "present", + 'demo', + 'present', cache: true, ); @@ -187,7 +191,7 @@ void main() { 'h_200,w_200/cloudinary_icon'); }); - test("Upload file in Chunks", () async { + test('Upload file in Chunks', () async { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, @@ -201,10 +205,10 @@ void main() { tags: ['trip'], ); final res = await cloudinary.uploadFileInChunks(file); - expect(res, TypeMatcher()); + expect(res, const TypeMatcher()); }); - test("Upload file bytes in chunks", () async { + test('Upload file bytes in chunks', () async { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, @@ -218,6 +222,6 @@ void main() { identifier: 'video.mp4', ); final res = await cloudinary.uploadFileInChunks(file); - expect(res, TypeMatcher()); + expect(res, const TypeMatcher()); }); } From e88e5747275a1fa50e77ba4c829417c867f12b51 Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Wed, 16 Nov 2022 19:06:51 +0000 Subject: [PATCH 15/23] Fix failing tests --- lib/src/cloudinary_file.dart | 2 +- lib/src/cloudinary_public.dart | 31 ++--- pubspec.lock | 226 ++++++++++++++++++++++++++++++- pubspec.yaml | 3 +- test/cloudinary_file_test.dart | 49 ++----- test/cloudinary_public_test.dart | 73 +++++++++- test/file_manager.dart | 46 +++++++ 7 files changed, 374 insertions(+), 56 deletions(-) create mode 100644 test/file_manager.dart diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index a172a11..a87fda4 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -174,7 +174,7 @@ class CloudinaryFile { } /// Convert [CloudinaryFile] to [MultipartFile] - Future toMultipartFile([String fieldName = 'file']) async { + Future toMultipartFile() async { assert( !fromExternalUrl, 'toMultipartFile() not available when uploading from external urls', diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index d6a4c49..4dc4d61 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -18,7 +18,11 @@ class CloudinaryPublic { /// To cache all the uploaded files in the current class instance final Map _uploadedFiles = {}; - static Dio _dio = Dio(); + /// The provided Dio client to be used to upload files + final Dio? dioClient; + + /// The Dio client to be used to upload files + final Dio _dioClient; /// Cloud name from Cloudinary final String _cloudName; @@ -33,17 +37,8 @@ class CloudinaryPublic { this._cloudName, this._uploadPreset, { this.cache = false, - }) { - _dio = Dio( - BaseOptions( - baseUrl: _baseUrl, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'multipart/form-data' - }, - ), - ); - } + this.dioClient, + }) : _dioClient = dioClient ?? Dio(); String _createUrl(CloudinaryResourceType type) { var url = '$_baseUrl/$_cloudName/' @@ -87,10 +82,10 @@ class CloudinaryPublic { if (file.fromExternalUrl) { data[_fieldName] = file.url!; } else { - data[_fieldName] = await file.toMultipartFile(_fieldName); + data[_fieldName] = await file.toMultipartFile(); } - var response = await _dio.post( + var response = await _dioClient.post( _createUrl(file.resourceType), data: FormData.fromMap(data), onSendProgress: onProgress, @@ -187,8 +182,10 @@ class CloudinaryPublic { List? chunks = file.createChunks(chunksCount, maxChunkSize); - Map data = - file.toFormData(uploadPreset: uploadPreset ?? _uploadPreset); + Map data = file.toFormData( + uploadPreset: uploadPreset ?? _uploadPreset, + ); + try { for (int i = 0; i < chunksCount; i++) { final start = i * maxChunkSize; @@ -199,7 +196,7 @@ class CloudinaryPublic { ...data, }); - finalResponse = await _dio.post( + finalResponse = await _dioClient.post( _createUrl(file.resourceType), data: formData, options: Options( diff --git a/pubspec.lock b/pubspec.lock index 3d7f7f6..10082ae 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,27 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "47.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "4.7.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" async: dependency: transitive description: @@ -43,6 +64,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.dartlang.org" + source: hosted + version: "1.6.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" dio: dependency: "direct main" description: @@ -57,6 +99,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -74,6 +123,27 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.1" http_parser: dependency: transitive description: @@ -81,6 +151,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.5" lints: dependency: transitive description: @@ -88,6 +172,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" matcher: dependency: "direct dev" description: @@ -109,6 +200,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + mocktail: + dependency: "direct dev" + description: + name: mocktail + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -116,11 +235,67 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.11" source_span: dependency: transitive description: @@ -156,6 +331,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.1" + test: + dependency: transitive + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.21.4" test_api: dependency: transitive description: @@ -163,6 +345,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.12" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.16" typed_data: dependency: transitive description: @@ -177,5 +366,40 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "9.4.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.18.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b9bde81..06892f3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,8 @@ dev_dependencies: flutter_test: sdk: flutter matcher: any - flutter_lints: ^2.0.1 + flutter_lints: any + mocktail: any # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/cloudinary_file_test.dart b/test/cloudinary_file_test.dart index 5177486..603a304 100644 --- a/test/cloudinary_file_test.dart +++ b/test/cloudinary_file_test.dart @@ -5,45 +5,24 @@ import 'dart:typed_data'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:flutter_test/flutter_test.dart'; -const chunkSize10 = 1024 * 1024 * 10; // 10MB +import 'file_manager.dart'; -File getFile() { - File file = File('../test/icon.png'); - try { - file.lengthSync(); - } catch (exception) { - file = File('test/icon.png'); - } - return file; -} +const chunkSize10 = 1024 * 1024 * 10; // 10MB -Future getFutureByteData() async { - final tempFile = getFile(); - Uint8List uIntBytes = tempFile.readAsBytesSync(); - ByteData bytes = (ByteData.view(uIntBytes.buffer)); - return Future.value(bytes); -} +void main() { + late File tempFile; + late File tempVideoFile; -// To test video add sample video to test folder -File getVideoFile() { - File file = File('../test/video.mp4'); - try { - file.lengthSync(); - } catch (exception) { - file = File('test/video.mp4'); - } - return file; -} + setUpAll(() { + tempFile = getFile(); + tempVideoFile = getVideoFile(); + }); -Future getFutureVideoByteData() { - final tempFile = getVideoFile(); - Uint8List uIntBytes = tempFile.readAsBytesSync(); - ByteData bytes = (ByteData.view(uIntBytes.buffer)); - return Future.value(bytes); -} + tearDownAll(() { + // delete generated video file + deleteGeneratedVideoFile(); + }); -void main() { - final tempFile = getFile(); group('Cloudinary file size test', () { test('uploads an image file', () async { final file = CloudinaryFile.fromFile(tempFile.path); @@ -69,7 +48,7 @@ void main() { group('cloudinary chunks test', () { test('chunks count and size', () async { // Getting file - File file = getVideoFile(); + final file = tempVideoFile; CloudinaryFile videoFile = CloudinaryFile.fromFile(file.path); ByteData byteData = await getFutureVideoByteData(); CloudinaryFile videoFileFromByteData = CloudinaryFile.fromByteData( diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index ae74a8a..781cbea 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -1,17 +1,58 @@ import 'package:cloudinary_public/cloudinary_public.dart'; +import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; -import 'cloudinary_file_test.dart'; +import 'file_manager.dart'; const cloudName = 'test'; const uploadPreset = 'test'; +class MockClient extends Mock implements Dio {} + void main() { + late MockClient client; + + setUp(() { + client = MockClient(); + when( + () => client.post( + 'https://api.cloudinary.com/v1_1/$cloudName/image/upload', + data: any(named: 'data'), + onSendProgress: any(named: 'onSendProgress'), + ), + ).thenAnswer( + (_) async => Response( + data: _sampleResponse, + statusCode: 200, + requestOptions: RequestOptions(path: ''), + ), + ); + + when( + () => client.post( + 'https://api.cloudinary.com/v1_1/$cloudName/video/upload', + data: any(named: 'data'), + onSendProgress: any(named: 'onSendProgress'), + options: any(named: 'options'), + ), + ).thenAnswer( + (_) async => Response( + data: _sampleResponse, + statusCode: 200, + requestOptions: RequestOptions(path: ''), + ), + ); + }); + + tearDownAll(() => deleteGeneratedVideoFile()); + test('uploads an image from external url', () async { final cloudinary = CloudinaryPublic( cloudName, uploadPreset, cache: true, + dioClient: client, ); final file = CloudinaryFile.fromUrl( @@ -38,6 +79,7 @@ void main() { cloudName, uploadPreset, cache: true, + dioClient: client, ); final file = CloudinaryFile.fromFile( @@ -65,6 +107,7 @@ void main() { cloudName, uploadPreset, cache: true, + dioClient: client, ); final file = CloudinaryFile.fromFile( @@ -92,6 +135,7 @@ void main() { cloudName, uploadPreset, cache: true, + dioClient: client, ); final files = []; @@ -115,6 +159,7 @@ void main() { cloudName, uploadPreset, cache: true, + dioClient: client, ); final files = >[]; @@ -141,6 +186,7 @@ void main() { cloudName, uploadPreset, cache: true, + dioClient: client, ); final image = CloudinaryImage( @@ -196,6 +242,7 @@ void main() { cloudName, uploadPreset, cache: true, + dioClient: client, ); final videoFile = getVideoFile(); @@ -213,6 +260,7 @@ void main() { cloudName, uploadPreset, cache: true, + dioClient: client, ); final videoBytes = getFutureVideoByteData(); @@ -225,3 +273,26 @@ void main() { expect(res, const TypeMatcher()); }); } + +const _sampleResponse = { + 'asset_id': '82345c4e10d4c019658b3334cde497ed9', + 'public_id': 'psryios0nkgpf1h4a3h', + 'version': '1590212116', + 'version_id': 'd5c175f90d3daf799cda96ead698368ea', + 'signature': '08a8183b499d1cd3aa46ea54ab278c14b8cfbba', + 'width': '1668', + 'height': '2500', + 'format': 'jpg', + 'resource_type': 'image', + 'created_at': '2020-05-23T05:35:16Z', + 'tags': [], + 'bytes': '3331383', + 'type': 'upload', + 'etag': '787996e313bcdd299d090b20389tta8d', + 'placeholder': 'false', + 'url': + 'http://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg', + 'secure_url': + 'https://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg', + 'original_filename': '001' +}; diff --git a/test/file_manager.dart b/test/file_manager.dart new file mode 100644 index 0000000..a89536a --- /dev/null +++ b/test/file_manager.dart @@ -0,0 +1,46 @@ +import 'dart:io'; +import 'dart:typed_data'; + +const videoSize = 1024 * 1024 * 50; // 50MB + +File getFile() { + File file = File('../test/icon.png'); + try { + file.lengthSync(); + } catch (exception) { + file = File('test/icon.png'); + } + return file; +} + +Future getFutureByteData() async { + final tempFile = getFile(); + Uint8List uIntBytes = tempFile.readAsBytesSync(); + ByteData bytes = (ByteData.view(uIntBytes.buffer)); + return Future.value(bytes); +} + +// To test video add sample video to test folder +File getVideoFile() { + final file = File('test/video.mp4'); + if (file.existsSync()) { + return file; + } + + file.writeAsBytesSync(List.filled(videoSize, 0)); + return file; +} + +Future getFutureVideoByteData() { + final tempFile = getVideoFile(); + Uint8List uIntBytes = tempFile.readAsBytesSync(); + ByteData bytes = (ByteData.view(uIntBytes.buffer)); + return Future.value(bytes); +} + +Future deleteGeneratedVideoFile() async { + final file = getVideoFile(); + if (file.existsSync()) { + await file.delete(); + } +} From 49b7e5c9828c57f64aa3cba4264ffeae5186d532 Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Wed, 16 Nov 2022 19:17:19 +0000 Subject: [PATCH 16/23] add github workflow --- .github/workflows/all.yaml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/all.yaml diff --git a/.github/workflows/all.yaml b/.github/workflows/all.yaml new file mode 100644 index 0000000..94febb9 --- /dev/null +++ b/.github/workflows/all.yaml @@ -0,0 +1,27 @@ +name: Test Cloudinary Library + +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: subosito/flutter-action@v2 + with: + channel: 'stable' + - name: Install dependencies + run: flutter pub get + - name: Analyze + run: flutter analyze + - name: Tests + run: flutter test From fe795cef253f868d5246538a14228f20ca2066a5 Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Wed, 16 Nov 2022 19:23:14 +0000 Subject: [PATCH 17/23] Setup env file in github workflow --- .github/workflows/all.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/all.yaml b/.github/workflows/all.yaml index 94febb9..91283fe 100644 --- a/.github/workflows/all.yaml +++ b/.github/workflows/all.yaml @@ -21,6 +21,8 @@ jobs: channel: 'stable' - name: Install dependencies run: flutter pub get + - name: Copy env file + run: cp example/lib/src/.init.example.dart example/lib/src/.init.dart - name: Analyze run: flutter analyze - name: Tests From 5d6f907d44091459f137cf1cbdbd47a33064ec47 Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Wed, 16 Nov 2022 19:25:37 +0000 Subject: [PATCH 18/23] fix file name --- .github/workflows/all.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/all.yaml b/.github/workflows/all.yaml index 91283fe..6b986ea 100644 --- a/.github/workflows/all.yaml +++ b/.github/workflows/all.yaml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: flutter pub get - name: Copy env file - run: cp example/lib/src/.init.example.dart example/lib/src/.init.dart + run: cp example/lib/src/.init.example.dart example/lib/src/init.dart - name: Analyze run: flutter analyze - name: Tests From a9adb64c2c1c4e0fe3b3757b4061accb6ad60a7d Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Wed, 16 Nov 2022 20:10:16 +0000 Subject: [PATCH 19/23] fix upload on web --- CHANGELOG.md | 4 ++++ lib/src/cloudinary_file.dart | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d88ee2..825dbb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.20.0 +- Upload large files in chunks support +- Switch from http package to Dio to support chunk upload + ## 0.13.0 - add public_id option diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index a87fda4..83b53c0 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -194,6 +194,17 @@ class CloudinaryFile { ); } + if (kIsWeb) { + final res = await Dio().get>( + filePath!, + options: Options(responseType: ResponseType.bytes), + ); + return MultipartFile.fromBytes( + res.data!, + filename: identifier, + ); + } + return MultipartFile.fromFile( filePath!, filename: identifier, From 014c8d71d1f95652d014c721cc8df05da7b79491 Mon Sep 17 00:00:00 2001 From: Olajide Afeez Date: Mon, 1 May 2023 11:57:25 +0100 Subject: [PATCH 20/23] Upgrade dio dependency --- CHANGELOG.md | 3 + example/pubspec.lock | 129 ++++++++++++++++++----------- pubspec.lock | 193 +++++++++++++++++++++++++++---------------- pubspec.yaml | 4 +- 4 files changed, 210 insertions(+), 119 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 825dbb6..c74ab43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.21.0 +- Upgrade dio dependency + ## 0.20.0 - Upload large files in chunks support - Switch from http package to Dio to support chunk upload diff --git a/example/pubspec.lock b/example/pubspec.lock index ffda613..87ed924 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,35 +5,40 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" source: hosted version: "1.3.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" cloudinary_public: @@ -42,40 +47,45 @@ packages: path: ".." relative: true source: path - version: "0.20.0" + version: "0.21.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.dartlang.org" + sha256: "7632a2bcddc8cef4afde3c6f80e69b29a7060e176f01119c229fe4eb3a2a3d4f" + url: "https://pub.dev" source: hosted version: "0.3.3+1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" dio: dependency: transitive description: name: dio - url: "https://pub.dartlang.org" + sha256: "0894a098594263fe1caaba3520e3016d8a855caeb010a882273189cca10f11e9" + url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "5.1.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" flutter: @@ -87,7 +97,8 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "6ffe524cd6a7d49d99b2bf979a4f6ad82304c639cea4c8d3d0f8cf1aff24e74a" + url: "https://pub.dev" source: hosted version: "2.0.6" flutter_test: @@ -104,98 +115,112 @@ packages: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 + url: "https://pub.dev" source: hosted version: "4.0.0" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + sha256: f3712cd190227fb92e0960cb0ce22928ba042c7183b16864ade83b259adf8ea6 + url: "https://pub.dev" source: hosted version: "0.8.5+3" image_picker_android: dependency: transitive description: name: image_picker_android - url: "https://pub.dartlang.org" + sha256: "524c04b800320c92c079294a8a2024912b5cff6854d8e5da4d966338b243a276" + url: "https://pub.dev" source: hosted version: "0.8.4+13" image_picker_for_web: dependency: "direct main" description: name: image_picker_for_web - url: "https://pub.dartlang.org" + sha256: "60f306ffbdcada4bc8b2691acc420258a1b758e102c87c4f94fb568d640f0e0e" + url: "https://pub.dev" source: hosted version: "2.1.8" image_picker_ios: dependency: transitive description: name: image_picker_ios - url: "https://pub.dartlang.org" + sha256: c1af1bd2223362771e161a72c5361c762a7719f822583762b3ddd1971bcea081 + url: "https://pub.dev" source: hosted version: "0.8.5+5" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + sha256: b5cfa6b0364979411dfbd3a68bd874452eff22344f184f92af79bddc4acf4742 + url: "https://pub.dev" source: hosted version: "2.5.0" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" multi_image_picker: dependency: "direct main" description: name: multi_image_picker - url: "https://pub.dartlang.org" + sha256: "3071bef51d4165f152bde7e22b6f6769745acd5939d70b9fc3d0c9137dbd0a15" + url: "https://pub.dev" source: hosted version: "4.8.01" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "075f927ebbab4262ace8d0b283929ac5410c0ac4e7fc123c76429564facfb757" + url: "https://pub.dev" source: hosted version: "2.1.2" sky_engine: @@ -207,58 +232,66 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" source: hosted version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.18.0 <3.0.0" flutter: ">=2.8.0" diff --git a/pubspec.lock b/pubspec.lock index 10082ae..aa8948c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,105 +5,120 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8" + url: "https://pub.dev" source: hosted version: "47.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80" + url: "https://pub.dev" source: hosted version: "4.7.0" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + url: "https://pub.dev" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" source: hosted version: "1.3.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" source: hosted version: "3.1.1" coverage: dependency: transitive description: name: coverage - url: "https://pub.dartlang.org" + sha256: d2494157c32b303f47dedee955b1479f2979c4ff66934eb7c0def44fd9e0267a + url: "https://pub.dev" source: hosted version: "1.6.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" dio: dependency: "direct main" description: name: dio - url: "https://pub.dartlang.org" + sha256: "0894a098594263fe1caaba3520e3016d8a855caeb010a882273189cca10f11e9" + url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "5.1.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted version: "6.1.4" flutter: @@ -115,7 +130,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_test: @@ -127,154 +143,176 @@ packages: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "4f4a162323c86ffc1245765cfe138872b8f069deb42f7dbb36115fa27f31469b" + url: "https://pub.dev" source: hosted version: "2.1.3" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + url: "https://pub.dev" source: hosted version: "2.1.1" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 + url: "https://pub.dev" source: hosted version: "4.0.0" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" + url: "https://pub.dev" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted version: "0.6.5" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + url: "https://pub.dev" source: hosted version: "1.1.0" matcher: dependency: "direct dev" description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: dab22e92b41aa1255ea90ddc4bc2feaf35544fd0728e209638cad041a6e3928a + url: "https://pub.dev" source: hosted version: "1.0.2" mocktail: dependency: "direct dev" description: name: mocktail - url: "https://pub.dartlang.org" + sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53" + url: "https://pub.dev" source: hosted version: "0.3.0" node_preamble: dependency: transitive description: name: node_preamble - url: "https://pub.dartlang.org" + sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + url: "https://pub.dev" source: hosted version: "2.0.1" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + url: "https://pub.dev" source: hosted version: "2.1.3" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + url: "https://pub.dev" source: hosted version: "1.4.0" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler - url: "https://pub.dartlang.org" + sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 + url: "https://pub.dev" source: hosted version: "3.0.1" shelf_static: dependency: transitive description: name: shelf_static - url: "https://pub.dartlang.org" + sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c + url: "https://pub.dev" source: hosted version: "1.1.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + url: "https://pub.dev" source: hosted version: "1.0.3" sky_engine: @@ -286,119 +324,136 @@ packages: dependency: transitive description: name: source_map_stack_trace - url: "https://pub.dartlang.org" + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" source: hosted version: "2.1.1" source_maps: dependency: transitive description: name: source_maps - url: "https://pub.dartlang.org" + sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" + url: "https://pub.dev" source: hosted version: "0.10.11" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test: dependency: transitive description: name: test - url: "https://pub.dartlang.org" + sha256: a5fcd2d25eeadbb6589e80198a47d6a464ba3e2049da473943b8af9797900c2d + url: "https://pub.dev" source: hosted - version: "1.21.4" + version: "1.22.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" test_core: dependency: transitive description: name: test_core - url: "https://pub.dartlang.org" + sha256: "0ef9755ec6d746951ba0aabe62f874b707690b5ede0fecc818b138fcc9b14888" + url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.4.20" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" source: hosted version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + url: "https://pub.dev" source: hosted version: "9.4.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" source: hosted version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + url: "https://pub.dev" source: hosted version: "2.2.0" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol - url: "https://pub.dartlang.org" + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" source: hosted version: "1.2.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted version: "3.1.1" sdks: diff --git a/pubspec.yaml b/pubspec.yaml index 06892f3..a3c6589 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: cloudinary_public description: This package allows you to upload media files directly to cloudinary, without exposing your apiKey or secretKey. -version: 0.20.0 +version: 0.21.0 homepage: https://github.com/djade007/cloudinary_public environment: @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - dio: ^4.0.6 + dio: ^5.1.1 dev_dependencies: flutter_test: From 66dba3db179f2159e8bef8ef8e6ba0840f783f96 Mon Sep 17 00:00:00 2001 From: Afeez Olajide Date: Tue, 28 Nov 2023 14:25:29 +0100 Subject: [PATCH 21/23] chore: update dio version --- README.md | 2 +- example/pubspec.lock | 52 +++++++++++++++------------ lib/src/cloudinary_file.dart | 5 +-- pubspec.lock | 62 ++++++++++++++++++-------------- pubspec.yaml | 4 +-- test/cloudinary_public_test.dart | 2 +- 6 files changed, 72 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 222890b..92d03aa 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ secretKey. ## Getting started -Add the dependency `cloudinary_public: ^0.20.0` to your project: +Add the dependency `cloudinary_public: ^0.23.0` to your project: ```dart import 'package:cloudinary_public/cloudinary_public.dart'; diff --git a/example/pubspec.lock b/example/pubspec.lock index 87ed924..0a0d8b3 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" charcode: dependency: transitive description: @@ -47,15 +47,15 @@ packages: path: ".." relative: true source: path - version: "0.21.0" + version: "0.22.0" collection: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.2" cross_file: dependency: transitive description: @@ -76,10 +76,10 @@ packages: dependency: transitive description: name: dio - sha256: "0894a098594263fe1caaba3520e3016d8a855caeb010a882273189cca10f11e9" + sha256: "01870acd87986f768e0c09cc4d7a19a59d814af7b34cbeb0b437d2c33bdfea4c" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.3.4" fake_async: dependency: transitive description: @@ -179,26 +179,26 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" multi_image_picker: dependency: "direct main" description: @@ -211,10 +211,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" plugin_platform_interface: dependency: transitive description: @@ -232,10 +232,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -272,10 +272,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.6.0" typed_data: dependency: transitive description: @@ -292,6 +292,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=2.8.0" diff --git a/lib/src/cloudinary_file.dart b/lib/src/cloudinary_file.dart index 83b53c0..387ac08 100644 --- a/lib/src/cloudinary_file.dart +++ b/lib/src/cloudinary_file.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'dart:math'; + // ignore: unnecessary_import import 'dart:typed_data'; @@ -234,8 +235,8 @@ class CloudinaryFile { chunkStream = File(filePath!).openRead(start, end); } - return MultipartFile( - chunkStream, + return MultipartFile.fromStream( + () => chunkStream, end - start, filename: identifier, ); diff --git a/pubspec.lock b/pubspec.lock index aa8948c..ff62bbf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" charcode: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.2" convert: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "0894a098594263fe1caaba3520e3016d8a855caeb010a882273189cca10f11e9" + sha256: "01870acd87986f768e0c09cc4d7a19a59d814af7b34cbeb0b437d2c33bdfea4c" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.3.4" fake_async: dependency: transitive description: @@ -143,10 +143,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "4f4a162323c86ffc1245765cfe138872b8f069deb42f7dbb36115fa27f31469b" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "3.2.0" glob: dependency: transitive description: @@ -207,26 +207,26 @@ packages: dependency: "direct dev" description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" mime: dependency: transitive description: @@ -263,10 +263,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" pool: dependency: transitive description: @@ -340,10 +340,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -380,26 +380,26 @@ packages: dependency: transitive description: name: test - sha256: a5fcd2d25eeadbb6589e80198a47d6a464ba3e2049da473943b8af9797900c2d + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" url: "https://pub.dev" source: hosted - version: "1.22.0" + version: "1.24.3" test_api: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.6.0" test_core: dependency: transitive description: name: test_core - sha256: "0ef9755ec6d746951ba0aabe62f874b707690b5ede0fecc818b138fcc9b14888" + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" url: "https://pub.dev" source: hosted - version: "0.4.20" + version: "0.5.3" typed_data: dependency: transitive description: @@ -432,6 +432,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -457,4 +465,4 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index a3c6589..cfb1cbc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: cloudinary_public description: This package allows you to upload media files directly to cloudinary, without exposing your apiKey or secretKey. -version: 0.21.0 +version: 0.23.0 homepage: https://github.com/djade007/cloudinary_public environment: @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - dio: ^5.1.1 + dio: ^5.3.4 dev_dependencies: flutter_test: diff --git a/test/cloudinary_public_test.dart b/test/cloudinary_public_test.dart index 781cbea..68c5c50 100644 --- a/test/cloudinary_public_test.dart +++ b/test/cloudinary_public_test.dart @@ -294,5 +294,5 @@ const _sampleResponse = { 'http://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg', 'secure_url': 'https://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg', - 'original_filename': '001' + 'original_filename': '001', }; From d9388455e5d483c6bbd4604ec8630a3e764e07e5 Mon Sep 17 00:00:00 2001 From: Afeez Olajide Date: Tue, 28 Nov 2023 14:31:18 +0100 Subject: [PATCH 22/23] chore: Update sdk constraint --- CHANGELOG.md | 2 +- example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c74ab43..efa1eae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.21.0 +## 0.23.0 - Upgrade dio dependency ## 0.20.0 diff --git a/example/pubspec.lock b/example/pubspec.lock index 0a0d8b3..deaf217 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -47,7 +47,7 @@ packages: path: ".." relative: true source: path - version: "0.22.0" + version: "0.23.0" collection: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cfb1cbc..86d205c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.23.0 homepage: https://github.com/djade007/cloudinary_public environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.12.0 <4.0.0" dependencies: flutter: From 1132b55d415008062ea54c5900afd80c1fcd2011 Mon Sep 17 00:00:00 2001 From: Afeez Olajide Date: Tue, 28 Nov 2023 14:45:26 +0100 Subject: [PATCH 23/23] chore: fix deprecated method --- CHANGELOG.md | 4 ++-- README.md | 2 +- example/pubspec.lock | 26 ++++++++++----------- lib/src/cloudinary_public.dart | 3 +-- pubspec.lock | 42 +++++++++++++++++----------------- pubspec.yaml | 4 ++-- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efa1eae..f467944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -## 0.23.0 -- Upgrade dio dependency +## 0.23.1 +- Update dio dependency and sdk constraints ## 0.20.0 - Upload large files in chunks support diff --git a/README.md b/README.md index 92d03aa..df0d676 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ secretKey. ## Getting started -Add the dependency `cloudinary_public: ^0.23.0` to your project: +Add the dependency `cloudinary_public: ^0.23.1` to your project: ```dart import 'package:cloudinary_public/cloudinary_public.dart'; diff --git a/example/pubspec.lock b/example/pubspec.lock index deaf217..daa0180 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -52,10 +52,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" cross_file: dependency: transitive description: @@ -195,10 +195,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" multi_image_picker: dependency: "direct main" description: @@ -240,18 +240,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -272,10 +272,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" typed_data: dependency: transitive description: @@ -296,10 +296,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=2.8.0" diff --git a/lib/src/cloudinary_public.dart b/lib/src/cloudinary_public.dart index 4dc4d61..c9b47e5 100644 --- a/lib/src/cloudinary_public.dart +++ b/lib/src/cloudinary_public.dart @@ -5,7 +5,6 @@ import 'dart:typed_data'; import 'package:cloudinary_public/cloudinary_public.dart'; import 'package:dio/dio.dart'; -import 'package:flutter/foundation.dart'; /// The base class for this package class CloudinaryPublic { @@ -42,7 +41,7 @@ class CloudinaryPublic { String _createUrl(CloudinaryResourceType type) { var url = '$_baseUrl/$_cloudName/' - '${describeEnum(type).toLowerCase()}' + '${type.name.toLowerCase()}' '/upload'; return url; } diff --git a/pubspec.lock b/pubspec.lock index ff62bbf..3319176 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8" + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "64.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80" + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "6.2.0" args: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" convert: dependency: transitive description: @@ -223,10 +223,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" mime: dependency: transitive description: @@ -348,18 +348,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -380,26 +380,26 @@ packages: dependency: transitive description: name: test - sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" + sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f url: "https://pub.dev" source: hosted - version: "1.24.3" + version: "1.24.9" test_api: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" test_core: dependency: transitive description: name: test_core - sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" + sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a url: "https://pub.dev" source: hosted - version: "0.5.3" + version: "0.5.9" typed_data: dependency: transitive description: @@ -436,10 +436,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -465,4 +465,4 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 86d205c..678ea4d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ name: cloudinary_public description: This package allows you to upload media files directly to cloudinary, without exposing your apiKey or secretKey. -version: 0.23.0 +version: 0.23.1 homepage: https://github.com/djade007/cloudinary_public environment: - sdk: ">=2.12.0 <4.0.0" + sdk: ">=2.15.0 <4.0.0" dependencies: flutter: