Skip to content

Commit

Permalink
feat: Add ParseXFile for cross-platform XFile support (#990)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbfakourii committed Mar 30, 2024
1 parent 540b127 commit c388545
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 60 deletions.
6 changes: 6 additions & 0 deletions packages/dart/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [6.4.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-6.3.0...dart-6.4.0) (2024-03-30)

### Features

* Add `ParseXFile` for cross-platform `XFile` support ([#990](https://github.com/parse-community/Parse-SDK-Flutter/pull/990))

## [6.3.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-6.2.0...dart-6.3.0) (2023-11-11)

### Features
Expand Down
60 changes: 5 additions & 55 deletions packages/dart/lib/parse_server_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import 'dart:math';
import 'dart:typed_data';

import 'package:collection/collection.dart';
import 'package:cross_file/cross_file.dart';
import 'package:dio/dio.dart';
import 'package:meta/meta.dart';
import 'package:mime_type/mime_type.dart';
import 'package:mime/mime.dart';
import 'package:path/path.dart' as path;
import 'package:sembast/sembast.dart';
import 'package:sembast/sembast_io.dart';
Expand All @@ -27,109 +28,58 @@ export 'src/network/parse_dio_client.dart';
export 'src/network/parse_http_client.dart';

part 'src/base/parse_constants.dart';

part 'src/data/parse_core_data.dart';

part 'src/data/parse_subclass_handler.dart';

part 'src/enums/parse_enum_api_rq.dart';

part 'src/network/options.dart';

part 'src/network/parse_client.dart';

part 'src/network/parse_connectivity.dart';

part 'src/network/parse_live_query.dart';

part 'src/network/parse_query.dart';

part 'src/objects/parse_acl.dart';

part 'src/objects/parse_array.dart';

part 'src/objects/parse_base.dart';

part 'src/objects/parse_cloneable.dart';

part 'src/objects/parse_config.dart';

part 'src/objects/parse_error.dart';

part 'src/objects/parse_exception.dart';
part 'src/objects/parse_file.dart';

part 'src/objects/parse_number.dart';

part 'src/objects/parse_file_base.dart';

part 'src/objects/parse_file_web.dart';

part 'src/objects/parse_function.dart';

part 'src/objects/parse_geo_point.dart';

part 'src/objects/parse_installation.dart';

part 'src/objects/parse_number.dart';
part 'src/objects/parse_object.dart';

part 'src/objects/parse_exception.dart';

part 'src/objects/parse_operation/parse_add_operation.dart';

part 'src/objects/parse_operation/parse_add_relation_operation.dart';

part 'src/objects/parse_operation/parse_add_unique_operation.dart';

part 'src/objects/parse_operation/parse_increment_operation.dart';

part 'src/objects/parse_operation/parse_operation.dart';

part 'src/objects/parse_operation/parse_remove_operation.dart';

part 'src/objects/parse_operation/parse_remove_relation_operation.dart';

part 'src/objects/parse_relation.dart';

part 'src/objects/parse_response.dart';

part 'src/objects/parse_save_state_aware_child.dart';

part 'src/objects/parse_session.dart';

part 'src/objects/parse_user.dart';

part 'src/objects/parse_x_file.dart';
part 'src/objects/response/parse_error_response.dart';

part 'src/objects/response/parse_exception_response.dart';

part 'src/objects/response/parse_response_builder.dart';

part 'src/objects/response/parse_response_utils.dart';

part 'src/objects/response/parse_success_no_results.dart';

part 'src/storage/core_store.dart';

part 'src/storage/core_store_memory.dart';

part 'src/storage/core_store_sem_impl.dart';

part 'src/storage/xxtea_codec.dart';

part 'src/utils/parse_date_format.dart';

part 'src/utils/parse_decoder.dart';

part 'src/utils/parse_encoder.dart';

part 'src/utils/parse_live_list.dart';

part 'src/utils/parse_logger.dart';

part 'src/utils/parse_login_helpers.dart';

part 'src/utils/parse_utils.dart';

part 'src/utils/valuable.dart';

class Parse {
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/lib/src/base/parse_constants.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
part of flutter_parse_sdk;

// Library
const String keySdkVersion = '6.3.0';
const String keySdkVersion = '6.4.0';
const String keyLibraryName = 'Flutter Parse SDK';

// End Points
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/lib/src/objects/parse_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class ParseFile extends ParseFileBase {

final Map<String, String> headers = <String, String>{
HttpHeaders.contentTypeHeader:
mime(file!.path) ?? 'application/octet-stream',
lookupMimeType(file!.path) ?? 'application/octet-stream',
HttpHeaders.contentLengthHeader: '${file!.lengthSync()}',
};

Expand Down
2 changes: 1 addition & 1 deletion packages/dart/lib/src/objects/parse_file_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ParseWebFile extends ParseFileBase {

final Map<String, String> headers = <String, String>{
HttpHeaders.contentTypeHeader:
mime(url ?? name) ?? 'application/octet-stream',
lookupMimeType(url ?? name) ?? 'application/octet-stream',
};
try {
final String uri = ParseCoreData().serverUrl + _path;
Expand Down
158 changes: 158 additions & 0 deletions packages/dart/lib/src/objects/parse_x_file.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
part of flutter_parse_sdk;

class ParseXFile extends ParseFileBase {
/// Creates a new file base XFile
///
/// {https://docs.parseplatform.org/rest/guide/#files/}
ParseXFile(this.file,
{String? name,
String? url,
bool? debug,
ParseClient? client,
bool? autoSendSessionId})
: super(
name: file != null ? path.basename(file.path) : name!,
url: url,
debug: debug,
client: client,
autoSendSessionId: autoSendSessionId,
);

XFile? file;
CancelToken? _cancelToken;
ProgressCallback? _progressCallback;

Future<ParseXFile> loadStorage() async {
// Web not need load storage.
if (parseIsWeb) {
return this;
}

final XFile possibleFile = XFile('${ParseCoreData().fileDirectory}/$name');
// ignore: avoid_slow_async_io
final bool exists = await File(possibleFile.path).exists();

if (exists) {
file = possibleFile;
} else {
file = null;
}

return this;
}

@override
Future<ParseXFile> download({ProgressCallback? progressCallback}) async {
if (url == null) {
return this;
}

progressCallback ??= _progressCallback;

_cancelToken = CancelToken();

if (parseIsWeb) {
final ParseNetworkByteResponse response = await _client.getBytes(
url!,
onReceiveProgress: progressCallback,
cancelToken: _cancelToken,
);

if (response.bytes != null) {
file = XFile.fromData(response.bytes as Uint8List);
}
} else {
file = XFile('${ParseCoreData().fileDirectory}/$name');
await File(file!.path).create();

final ParseNetworkByteResponse response = await _client.getBytes(
url!,
onReceiveProgress: progressCallback,
cancelToken: _cancelToken,
);
await File(file!.path).writeAsBytes(response.bytes!);
}

return this;
}

/// Uploads a file to Parse Server
@override
Future<ParseResponse> upload({ProgressCallback? progressCallback}) async {
if (saved) {
//Creates a Fake Response to return the correct result
final Map<String, String> response = <String, String>{
'url': url!,
'name': name
};
return handleResponse<ParseXFile>(
this,
ParseNetworkResponse(data: json.encode(response), statusCode: 201),
ParseApiRQ.upload,
_debug,
parseClassName);
}

progressCallback ??= _progressCallback;

_cancelToken = CancelToken();
Map<String, String> headers;
if (parseIsWeb) {
headers = <String, String>{
HttpHeaders.contentTypeHeader: file?.mimeType ??
lookupMimeType(url ?? file?.name ?? name,
headerBytes: await file?.readAsBytes()) ??
'application/octet-stream',
};
} else {
headers = <String, String>{
HttpHeaders.contentTypeHeader: file?.mimeType ??
lookupMimeType(file!.path) ??
'application/octet-stream',
HttpHeaders.contentLengthHeader: '${await file!.length()}',
};
}

try {
final String uri = ParseCoreData().serverUrl + _path;

Stream<List<int>>? data;
if (parseIsWeb) {
data = Stream<List<int>>.fromIterable(
<List<int>>[await file!.readAsBytes()]);
} else {
data = file!.openRead();
}

final ParseNetworkResponse response = await _client.postBytes(
uri,
options: ParseNetworkOptions(headers: headers),
data: data,
onSendProgress: progressCallback,
cancelToken: _cancelToken,
);
if (response.statusCode == 201) {
final Map<String, dynamic> map = json.decode(response.data);
url = map['url'].toString();
name = map['name'].toString();
}
return handleResponse<ParseXFile>(
this, response, ParseApiRQ.upload, _debug, parseClassName);
} on Exception catch (e) {
return handleException(e, ParseApiRQ.upload, _debug, parseClassName);
}
}

/// Cancels the current request (upload or download of file).
@override
void cancel([dynamic reason]) {
_cancelToken?.cancel(reason);
_cancelToken = null;
}

/// Add Progress Callback
@override
void progressCallback(ProgressCallback progressCallback) {
_progressCallback = progressCallback;
}
}
5 changes: 3 additions & 2 deletions packages/dart/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: parse_server_sdk
description: The Dart SDK to connect to Parse Server. Build your apps faster with Parse Platform, the complete application stack.
version: 6.3.0
version: 6.4.0
homepage: https://parseplatform.org
repository: https://github.com/parse-community/Parse-SDK-Flutter
issue_tracker: https://github.com/parse-community/Parse-SDK-Flutter/issues
Expand Down Expand Up @@ -34,11 +34,12 @@ dependencies:
uuid: ^3.0.7
meta: ^1.8.0
path: ^1.8.2
mime_type: ^1.0.0
mime: ^1.0.4
timezone: ^0.9.2
universal_io: ^2.2.0
xxtea: ^2.1.0
collection: ^1.16.0
cross_file: ^0.3.3+6

dev_dependencies:
lints: ^2.0.1
Expand Down

0 comments on commit c388545

Please sign in to comment.