Skip to content

Commit 60ca5a4

Browse files
authored
feat: Add upload / download cancel and progress callback for ParseFile (#806)
1 parent 6e7f5dc commit 60ca5a4

10 files changed

+114
-12
lines changed

packages/dart/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [3.1.5](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-3.1.4...dart-3.1.5) (2022-12-16)
2+
3+
### Bug Fixes
4+
5+
* Add upload / download cancel and progress callback for ParseFile ([#807](https://github.com/parse-community/Parse-SDK-Flutter/issues/807))
6+
17
## [3.1.4](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-3.1.3...dart-3.1.4) (2022-12-14)
28

39
### Bug Fixes

packages/dart/lib/src/base/parse_constants.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
part of flutter_parse_sdk;
22

33
// Library
4-
const String keySdkVersion = '3.1.4';
4+
const String keySdkVersion = '3.1.5';
55
const String keyLibraryName = 'Flutter Parse SDK';
66

77
// End Points

packages/dart/lib/src/network/parse_client.dart

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ abstract class ParseClient {
2727
Stream<List<int>>? data,
2828
ParseNetworkOptions? options,
2929
ProgressCallback? onSendProgress,
30+
dynamic cancelToken,
3031
});
3132

3233
Future<ParseNetworkResponse> delete(
@@ -38,6 +39,7 @@ abstract class ParseClient {
3839
String path, {
3940
ParseNetworkOptions? options,
4041
ProgressCallback? onReceiveProgress,
42+
dynamic cancelToken,
4143
});
4244

4345
// Future<ParseNetworkByteResponse> putBytes(

packages/dart/lib/src/network/parse_dio_client.dart

+26-5
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,26 @@ class ParseDioClient extends ParseClient {
4040
String path, {
4141
ParseNetworkOptions? options,
4242
ProgressCallback? onReceiveProgress,
43+
dynamic cancelToken,
4344
}) async {
4445
try {
4546
final dio.Response<List<int>> dioResponse = await _client.get<List<int>>(
4647
path,
48+
cancelToken: cancelToken,
49+
onReceiveProgress: onReceiveProgress,
4750
options: _Options(
4851
headers: options?.headers, responseType: dio.ResponseType.bytes),
4952
);
5053
return ParseNetworkByteResponse(
5154
bytes: dioResponse.data, statusCode: dioResponse.statusCode!);
5255
} on dio.DioError catch (error) {
53-
return ParseNetworkByteResponse(
54-
data: error.response?.data, statusCode: error.response!.statusCode!);
56+
if (error.response != null) {
57+
return ParseNetworkByteResponse(
58+
data: error.response?.data,
59+
statusCode: error.response!.statusCode!);
60+
} else {
61+
return _getOtherCaseErrorForParseNetworkResponse(error.error);
62+
}
5563
}
5664
}
5765

@@ -93,22 +101,35 @@ class ParseDioClient extends ParseClient {
93101
Future<ParseNetworkResponse> postBytes(String path,
94102
{Stream<List<int>>? data,
95103
ParseNetworkOptions? options,
96-
ProgressCallback? onSendProgress}) async {
104+
ProgressCallback? onSendProgress,
105+
dynamic cancelToken}) async {
97106
try {
98107
final dio.Response<String> dioResponse = await _client.post<String>(
99108
path,
100109
data: data,
110+
cancelToken: cancelToken,
101111
options: _Options(headers: options?.headers),
102112
onSendProgress: onSendProgress,
103113
);
104114
return ParseNetworkResponse(
105115
data: dioResponse.data!, statusCode: dioResponse.statusCode!);
106116
} on dio.DioError catch (error) {
107-
return ParseNetworkResponse(
108-
data: error.response?.data, statusCode: error.response!.statusCode!);
117+
if (error.response != null) {
118+
return ParseNetworkResponse(
119+
data: error.response?.data,
120+
statusCode: error.response!.statusCode!);
121+
} else {
122+
return _getOtherCaseErrorForParseNetworkResponse(error.error);
123+
}
109124
}
110125
}
111126

127+
_getOtherCaseErrorForParseNetworkResponse(String error) {
128+
return ParseNetworkResponse(
129+
data: "{\"code\":${ParseError.otherCause},\"error\":\"$error\"}",
130+
statusCode: ParseError.otherCause);
131+
}
132+
112133
@override
113134
Future<ParseNetworkResponse> delete(String path,
114135
{ParseNetworkOptions? options}) async {

packages/dart/lib/src/network/parse_http_client.dart

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class ParseHTTPClient extends ParseClient {
4040
String path, {
4141
ParseNetworkOptions? options,
4242
ProgressCallback? onReceiveProgress,
43+
dynamic cancelToken,
4344
}) async {
4445
final http.Response response = await _client.get(
4546
Uri.parse(path),
@@ -85,6 +86,7 @@ class ParseHTTPClient extends ParseClient {
8586
Stream<List<int>>? data,
8687
ParseNetworkOptions? options,
8788
ProgressCallback? onSendProgress,
89+
dynamic cancelToken,
8890
}) async {
8991
final http.Response response = await _client.post(
9092
Uri.parse(path),

packages/dart/lib/src/objects/parse_file.dart

+28
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class ParseFile extends ParseFileBase {
1919
);
2020

2121
File? file;
22+
CancelToken? _cancelToken;
23+
ProgressCallback? _progressCallback;
2224

2325
Future<ParseFile> loadStorage() async {
2426
final File possibleFile = File('${ParseCoreData().fileDirectory}/$name');
@@ -42,9 +44,15 @@ class ParseFile extends ParseFileBase {
4244

4345
file = File('${ParseCoreData().fileDirectory}/$name');
4446
await file!.create();
47+
48+
progressCallback ??= _progressCallback;
49+
50+
_cancelToken = CancelToken();
51+
4552
final ParseNetworkByteResponse response = await _client.getBytes(
4653
url!,
4754
onReceiveProgress: progressCallback,
55+
cancelToken: _cancelToken,
4856
);
4957
await file!.writeAsBytes(response.bytes!);
5058

@@ -68,28 +76,48 @@ class ParseFile extends ParseFileBase {
6876
parseClassName);
6977
}
7078

79+
progressCallback ??= _progressCallback;
80+
81+
_cancelToken = CancelToken();
82+
7183
final Map<String, String> headers = <String, String>{
7284
HttpHeaders.contentTypeHeader:
7385
mime(file!.path) ?? 'application/octet-stream',
7486
HttpHeaders.contentLengthHeader: '${file!.lengthSync()}',
7587
};
88+
7689
try {
7790
final String uri = ParseCoreData().serverUrl + _path;
7891
final ParseNetworkResponse response = await _client.postBytes(
7992
uri,
8093
options: ParseNetworkOptions(headers: headers),
8194
data: file!.openRead(),
8295
onSendProgress: progressCallback,
96+
cancelToken: _cancelToken,
8397
);
8498
if (response.statusCode == 201) {
8599
final Map<String, dynamic> map = json.decode(response.data);
86100
url = map['url'].toString();
87101
name = map['name'].toString();
88102
}
103+
89104
return handleResponse<ParseFile>(
90105
this, response, ParseApiRQ.upload, _debug, parseClassName);
91106
} on Exception catch (e) {
92107
return handleException(e, ParseApiRQ.upload, _debug, parseClassName);
93108
}
94109
}
110+
111+
/// Cancels the current request (upload or download of file).
112+
@override
113+
void cancel([dynamic reason]) {
114+
_cancelToken?.cancel(reason);
115+
_cancelToken = null;
116+
}
117+
118+
/// Add Progress Callback
119+
@override
120+
void progressCallback(ProgressCallback progressCallback) {
121+
_progressCallback = progressCallback;
122+
}
95123
}

packages/dart/lib/src/objects/parse_file_base.dart

+4
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,8 @@ abstract class ParseFileBase extends ParseObject {
4848
Future<ParseResponse> upload({ProgressCallback? progressCallback});
4949

5050
Future<ParseFileBase> download({ProgressCallback? progressCallback});
51+
52+
void progressCallback(ProgressCallback progressCallback);
53+
54+
void cancel([dynamic reason]);
5155
}

packages/dart/lib/src/objects/parse_file_web.dart

+25
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,23 @@ class ParseWebFile extends ParseFileBase {
1616
);
1717

1818
Uint8List? file;
19+
CancelToken? _cancelToken;
20+
ProgressCallback? _progressCallback;
1921

2022
@override
2123
Future<ParseWebFile> download({ProgressCallback? progressCallback}) async {
2224
if (url == null) {
2325
return this;
2426
}
2527

28+
progressCallback ??= _progressCallback;
29+
30+
_cancelToken = CancelToken();
31+
2632
final ParseNetworkByteResponse response = await _client.getBytes(
2733
url!,
2834
onReceiveProgress: progressCallback,
35+
cancelToken: _cancelToken,
2936
);
3037
file = response.bytes as Uint8List?;
3138

@@ -48,6 +55,10 @@ class ParseWebFile extends ParseFileBase {
4855
parseClassName);
4956
}
5057

58+
progressCallback ??= _progressCallback;
59+
60+
_cancelToken = CancelToken();
61+
5162
final Map<String, String> headers = <String, String>{
5263
HttpHeaders.contentTypeHeader:
5364
mime(url ?? name) ?? 'application/octet-stream',
@@ -59,6 +70,7 @@ class ParseWebFile extends ParseFileBase {
5970
options: ParseNetworkOptions(headers: headers),
6071
data: Stream<List<int>>.fromIterable(<List<int>>[file!]),
6172
onSendProgress: progressCallback,
73+
cancelToken: _cancelToken,
6274
);
6375
if (response.statusCode == 201) {
6476
final Map<String, dynamic> map = json.decode(response.data);
@@ -71,4 +83,17 @@ class ParseWebFile extends ParseFileBase {
7183
return handleException(e, ParseApiRQ.upload, _debug, parseClassName);
7284
}
7385
}
86+
87+
/// Cancels the current request (upload or download of file).
88+
@override
89+
void cancel([dynamic reason]) {
90+
_cancelToken?.cancel(reason);
91+
_cancelToken = null;
92+
}
93+
94+
/// Add Progress Callback
95+
@override
96+
void progressCallback(ProgressCallback progressCallback) {
97+
_progressCallback = progressCallback;
98+
}
7499
}

packages/dart/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: parse_server_sdk
22
description: Dart plugin for Parse Server, (https://parseplatform.org), (https://back4app.com)
3-
version: 3.1.4
3+
version: 3.1.5
44
homepage: https://github.com/parse-community/Parse-SDK-Flutter
55

66
environment:

packages/dart/test/parse_query_test.mocks.dart

+19-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class MockParseClient extends _i1.Mock implements _i2.ParseClient {
2929
@override
3030
_i2.ParseCoreData get data => (super.noSuchMethod(Invocation.getter(#data),
3131
returnValue: _FakeParseCoreData()) as _i2.ParseCoreData);
32+
3233
@override
3334
_i3.Future<_i2.ParseNetworkResponse> get(String? path,
3435
{_i2.ParseNetworkOptions? options,
@@ -39,6 +40,7 @@ class MockParseClient extends _i1.Mock implements _i2.ParseClient {
3940
returnValue: Future<_i2.ParseNetworkResponse>.value(
4041
_FakeParseNetworkResponse()))
4142
as _i3.Future<_i2.ParseNetworkResponse>);
43+
4244
@override
4345
_i3.Future<_i2.ParseNetworkResponse> put(String? path,
4446
{String? data, _i2.ParseNetworkOptions? options}) =>
@@ -47,6 +49,7 @@ class MockParseClient extends _i1.Mock implements _i2.ParseClient {
4749
returnValue: Future<_i2.ParseNetworkResponse>.value(
4850
_FakeParseNetworkResponse()))
4951
as _i3.Future<_i2.ParseNetworkResponse>);
52+
5053
@override
5154
_i3.Future<_i2.ParseNetworkResponse> post(String? path,
5255
{String? data, _i2.ParseNetworkOptions? options}) =>
@@ -55,22 +58,26 @@ class MockParseClient extends _i1.Mock implements _i2.ParseClient {
5558
returnValue: Future<_i2.ParseNetworkResponse>.value(
5659
_FakeParseNetworkResponse())) as _i3
5760
.Future<_i2.ParseNetworkResponse>);
61+
5862
@override
5963
_i3.Future<_i2.ParseNetworkResponse> postBytes(String? path,
6064
{_i3.Stream<List<int>>? data,
6165
_i2.ParseNetworkOptions? options,
62-
_i2.ProgressCallback? onSendProgress}) =>
66+
_i2.ProgressCallback? onSendProgress,
67+
dynamic cancelToken}) =>
6368
(super.noSuchMethod(
6469
Invocation.method(#postBytes, [
6570
path
6671
], {
6772
#data: data,
6873
#options: options,
69-
#onSendProgress: onSendProgress
74+
#onSendProgress: onSendProgress,
75+
#cancelToken: cancelToken
7076
}),
7177
returnValue: Future<_i2.ParseNetworkResponse>.value(
7278
_FakeParseNetworkResponse()))
7379
as _i3.Future<_i2.ParseNetworkResponse>);
80+
7481
@override
7582
_i3.Future<_i2.ParseNetworkResponse> delete(String? path,
7683
{_i2.ParseNetworkOptions? options}) =>
@@ -79,13 +86,20 @@ class MockParseClient extends _i1.Mock implements _i2.ParseClient {
7986
returnValue: Future<_i2.ParseNetworkResponse>.value(
8087
_FakeParseNetworkResponse()))
8188
as _i3.Future<_i2.ParseNetworkResponse>);
89+
8290
@override
8391
_i3.Future<_i2.ParseNetworkByteResponse> getBytes(String? path,
8492
{_i2.ParseNetworkOptions? options,
85-
_i2.ProgressCallback? onReceiveProgress}) =>
93+
_i2.ProgressCallback? onReceiveProgress,
94+
dynamic cancelToken}) =>
8695
(super.noSuchMethod(
87-
Invocation.method(#getBytes, [path],
88-
{#options: options, #onReceiveProgress: onReceiveProgress}),
96+
Invocation.method(#getBytes, [
97+
path
98+
], {
99+
#options: options,
100+
#onReceiveProgress: onReceiveProgress,
101+
#cancelToken: cancelToken
102+
}),
89103
returnValue: Future<_i2.ParseNetworkByteResponse>.value(
90104
_FakeParseNetworkByteResponse()))
91105
as _i3.Future<_i2.ParseNetworkByteResponse>);

0 commit comments

Comments
 (0)