diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f090059fb..a0fbf4c7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,6 @@ on: push: branches: - "master" - - "development" paths-ignore: - "**/README.md" pull_request: @@ -16,23 +15,26 @@ jobs: matrix: include: # Dart framework may contain breaking changes in minor version releases, not following semver. - - name: Dart 3.0, Ubuntu + # The latest Dart framework (below) is tested on all architectures (Ubuntu, macOS, Windows). + - name: Dart 3.3, Ubuntu os: ubuntu-latest - sdk: 3.0.0 - - name: Dart 3.0, macOS + sdk: 3.3.3 + - name: Dart 3.3, macOS os: macos-latest - sdk: 3.0.0 - - name: Dart 3.0, Windows + sdk: 3.3.3 + - name: Dart 3.3, Windows os: windows-latest - sdk: 3.0.0 - # Only the latest Dart framework version (above) is tested with all architectures. Previous - # Dart framework versions (below) are only tested with Ubuntu to reduce CI resource usage. - - name: Dart 2.19 + sdk: 3.3.3 + # Older Dart framework versions (below) are only tested with Ubuntu to reduce CI resource usage. + - name: Dart 3.2 os: ubuntu-latest - sdk: 2.19.6 - - name: Dart 2.18 + sdk: 3.2.6 + - name: Dart 3.1 os: ubuntu-latest - sdk: 2.18.7 + sdk: 3.1.5 + - name: Dart 3.0 + os: ubuntu-latest + sdk: 3.0.7 - name: Dart beta os: ubuntu-latest sdk: beta @@ -40,7 +42,7 @@ jobs: name: Test ${{ matrix.name }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup dart uses: dart-lang/setup-dart@v1.5.0 with: @@ -65,35 +67,39 @@ jobs: dart pub global activate coverage dart pub global run coverage:format_coverage -i coverage/test -o coverage/lcov.info --lcov --packages=.dart_tool/package_config.json --report-on=lib - name: Upload code coverage - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v4 # Needs to be adapted to collect the coverage at all platforms if platform specific code is added. if: ${{ always() && matrix.os == 'ubuntu-latest' }} with: files: packages/dart/coverage/lcov.info fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} check-flutter: runs-on: ${{ matrix.os }} strategy: matrix: include: # Flutter framework may contain breaking changes in minor version releases, not following semver. - - name: Flutter 3.13, Ubuntu + # The latest Flutter framework (below) is tested on all architectures (Ubuntu, macOS, Windows). + - name: Flutter 3.19, Ubuntu os: ubuntu-latest - sdk: 3.13.6 - - name: Flutter 3.13, macOS + sdk: 3.19.5 + - name: Flutter 3.19, macOS os: macos-latest - sdk: 3.13.6 - - name: Flutter 3.13, Windows + sdk: 3.19.5 + - name: Flutter 3.19, Windows os: windows-latest - sdk: 3.13.6 - # Only the latest Flutter framework version (above) is tested with all architectures. Previous - # Flutter framework versions (below) are only tested with Ubuntu to reduce CI resource usage. + sdk: 3.19.5 + # Older Flutter framework versions (below) are only tested with Ubuntu to reduce CI resource usage. + - name: Flutter 3.16 + os: ubuntu-latest + sdk: 3.16.9 + - name: Flutter 3.13 + os: ubuntu-latest + sdk: 3.13.9 - name: Flutter 3.10 os: ubuntu-latest sdk: 3.10.6 - - name: Flutter 3.7 - os: ubuntu-latest - sdk: 3.7.12 - name: Flutter beta os: ubuntu-latest sdk: beta @@ -136,12 +142,13 @@ jobs: escapedPath="$(echo `pwd` | sed 's/\//\\\//g')" sed "s/^SF:lib/SF:$escapedPath\/lib/g" coverage/lcov.info > coverage/lcov-full.info - name: Upload code coverage - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v4 # Needs to be adapted to collect the coverage at all platforms if platform specific code is added. if: ${{ always() && matrix.os == 'ubuntu-latest' }} with: files: packages/flutter/coverage/lcov-full.info fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true diff --git a/.github/workflows/release-automated.yml b/.github/workflows/release-automated.yml index 27fe46a8b..a06b95afc 100644 --- a/.github/workflows/release-automated.yml +++ b/.github/workflows/release-automated.yml @@ -26,7 +26,7 @@ jobs: - name: Setup dart uses: dart-lang/setup-dart@v1 with: - sdk: '3.0.0' # Set to 3.0.0 due to Parse Dart SDK compatibility, can be removed later on + sdk: '3.0' - name: Setup flutter if: env.package == 'flutter' uses: subosito/flutter-action@v2 diff --git a/packages/dart/CHANGELOG.md b/packages/dart/CHANGELOG.md index af36e8417..cdee9b8f6 100644 --- a/packages/dart/CHANGELOG.md +++ b/packages/dart/CHANGELOG.md @@ -1,3 +1,47 @@ +## [7.0.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-6.4.0...dart-7.0.0) (2024-04-12) + +### BREAKING CHANGES + +* This release removes support for Dart 2.19 ([#993](https://github.com/parse-community/Parse-SDK-Flutter/pull/993)) + +### Features + +* Add support for Dart 3.1, 3.2, 3.3; remove support for Dart 2.19 ([#993](https://github.com/parse-community/Parse-SDK-Flutter/pull/993)) + +## [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 + +* Add `installationId` in LiveQuery `connect` ([#976](https://github.com/parse-community/Parse-SDK-Flutter/pull/976)) + +## [6.2.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-6.1.0...dart-6.2.0) (2023-10-18) + +### Features + +* Added `saveEventually` and `deleteEventually` in `ParseObject` ([#911](https://github.com/parse-community/Parse-SDK-Flutter/pull/911)) + +## [6.1.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-6.0.0...dart-6.1.0) (2023-10-17) + +### Features + +* Add `context` in `ParseObject` ([#970](https://github.com/parse-community/Parse-SDK-Flutter/pull/970)) + +## [6.0.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-5.1.3...dart-6.0.0) (2023-10-16) + +### BREAKING CHANGES + +* This release removes support for Dart 2.18 ([#969](https://github.com/parse-community/Parse-SDK-Flutter/pull/969)) + +### Features + +* Add support for Dart 3.1, remove support for Dart 2.18 ([#969](https://github.com/parse-community/Parse-SDK-Flutter/pull/969)) + ## [5.1.3](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-5.1.2...dart-5.1.3) (2023-07-18) ### Bug Fixes diff --git a/packages/dart/README.md b/packages/dart/README.md index 95c1a6211..7eb6995a7 100644 --- a/packages/dart/README.md +++ b/packages/dart/README.md @@ -28,14 +28,14 @@ This library gives you access to the powerful Parse Server backend from your Dar ## Compatibility -The Parse Dart SDK is continuously tested with the most recent release of the Dart framework to ensure compatibility. To give developers time to upgrade their app to the newest Dart framework, previous Dart framework releases are supported for at least 1 year after their [release date](https://dart.dev/get-dart/archive). +The Parse Dart SDK is continuously tested with the most recent release of the Dart framework to ensure compatibility. To give developers time to upgrade their app to a newer Dart framework, previous Dart framework releases are supported for at least 1 year after the [release date](https://dart.dev/get-dart/archive) of the next higher significant version. -| Version | Latest Version | End of Support | Compatible | -|-----------|----------------|----------------|----------------------------------------------| -| Dart 3.0 | 3.0.0 | May 2024 | ✅ Yes | -| Dart 2.19 | 2.19.6 | Mar 2024 | ✅ Yes | -| Dart 2.18 | 2.18.7 | Jan 2024 | ✅ Yes | -| Dart 2.17 | 2.17.7 | Aug 2023 | ❌ No (Parse Dart SDK requires Dart >=2.18.0) | +| Version | Latest Version | End of Support | Compatible | +|-----------|----------------|----------------|------------| +| Dart 3.3 | 3.3.3 | Mar 2025 | ✅ Yes | +| Dart 3.2 | 3.2.6 | Jan 2025 | ✅ Yes | +| Dart 3.1 | 3.1.5 | Oct 2024 | ✅ Yes | +| Dart 3.0 | 3.0.7 | May 2024 | ✅ Yes | ## Getting Started @@ -51,3 +51,4 @@ We want to make contributing to this project as easy and transparent as possible [guide]: https://docs.parseplatform.org/dart/guide/ [open-collective-link]: https://opencollective.com/parse-server + diff --git a/packages/dart/example/pubspec.yaml b/packages/dart/example/pubspec.yaml index 331856eb3..0a2e92fa6 100644 --- a/packages/dart/example/pubspec.yaml +++ b/packages/dart/example/pubspec.yaml @@ -5,7 +5,7 @@ publish_to: 'none' version: 1.0.0 environment: - sdk: ">=2.18.0 <4.0.0" + sdk: ">=2.19.6 <4.0.0" dependencies: parse_server_sdk: diff --git a/packages/dart/lib/parse_server_sdk.dart b/packages/dart/lib/parse_server_sdk.dart index 93ada12ac..555393ded 100644 --- a/packages/dart/lib/parse_server_sdk.dart +++ b/packages/dart/lib/parse_server_sdk.dart @@ -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'; @@ -41,15 +42,15 @@ 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'; @@ -62,6 +63,7 @@ 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'; @@ -83,6 +85,8 @@ part 'src/utils/valuable.dart'; class Parse { bool _hasBeenInitialized = false; + static bool objectsExistForEventually = false; + /// To initialize Parse Server in your application /// /// This should be initialized in MyApp() creation @@ -148,6 +152,12 @@ class Parse { _hasBeenInitialized = true; + objectsExistForEventually = await checkObjectsExistForEventually(); + + if (objectsExistForEventually) { + ParseObject.submitEventually(); + } + return this; } diff --git a/packages/dart/lib/src/base/parse_constants.dart b/packages/dart/lib/src/base/parse_constants.dart index 18ebe01ac..bd96e48fd 100644 --- a/packages/dart/lib/src/base/parse_constants.dart +++ b/packages/dart/lib/src/base/parse_constants.dart @@ -1,7 +1,7 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; // Library -const String keySdkVersion = '5.1.3'; +const String keySdkVersion = '7.0.0'; const String keyLibraryName = 'Flutter Parse SDK'; // End Points @@ -44,6 +44,7 @@ const String keyFileClassname = 'ParseFile'; // Headers const String keyHeaderSessionToken = 'X-Parse-Session-Token'; const String keyHeaderRevocableSession = 'X-Parse-Revocable-Session'; +const String keyHeaderCloudContext = 'X-Parse-Cloud-Context'; const String keyHeaderUserAgent = 'user-agent'; const String keyHeaderApplicationId = 'X-Parse-Application-Id'; const String keyHeaderContentType = 'content-type'; @@ -58,6 +59,8 @@ const String keyParamSessionToken = 'sessionToken'; // Storage const String keyParseStoreBase = 'flutter_parse_sdk_'; const String keyParseStoreUser = '${keyParseStoreBase}user'; +const String keyParseStoreObjects = '${keyParseStoreBase}objects'; +const String keyParseStoreDeletes = '${keyParseStoreBase}deletes'; const String keyParseStoreInstallation = '${keyParseStoreBase}installation'; // Installation @@ -81,5 +84,6 @@ const String keyVarInstallationId = 'installationId'; // Error const String keyError = 'error'; const String keyCode = 'code'; +const String keyNetworkError = 'NetworkError'; const bool parseIsWeb = identical(0, 0.0); diff --git a/packages/dart/lib/src/data/parse_core_data.dart b/packages/dart/lib/src/data/parse_core_data.dart index aea6adf36..cc50cc819 100644 --- a/packages/dart/lib/src/data/parse_core_data.dart +++ b/packages/dart/lib/src/data/parse_core_data.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// Singleton class that defines all user keys and data class ParseCoreData { diff --git a/packages/dart/lib/src/data/parse_subclass_handler.dart b/packages/dart/lib/src/data/parse_subclass_handler.dart index f7ed18cf9..73b2de3af 100644 --- a/packages/dart/lib/src/data/parse_subclass_handler.dart +++ b/packages/dart/lib/src/data/parse_subclass_handler.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; typedef ParseObjectConstructor = ParseObject Function(); typedef ParseUserConstructor = ParseUser Function( diff --git a/packages/dart/lib/src/enums/parse_enum_api_rq.dart b/packages/dart/lib/src/enums/parse_enum_api_rq.dart index 56bb33ef8..fb54de722 100644 --- a/packages/dart/lib/src/enums/parse_enum_api_rq.dart +++ b/packages/dart/lib/src/enums/parse_enum_api_rq.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// Used to define the API calls made in ParseObject logs enum ParseApiRQ { diff --git a/packages/dart/lib/src/network/options.dart b/packages/dart/lib/src/network/options.dart index 7f33a5c6c..5b07d7303 100644 --- a/packages/dart/lib/src/network/options.dart +++ b/packages/dart/lib/src/network/options.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseNetworkOptions { ParseNetworkOptions({this.headers}); diff --git a/packages/dart/lib/src/network/parse_client.dart b/packages/dart/lib/src/network/parse_client.dart index ad16235d0..bf29694e6 100644 --- a/packages/dart/lib/src/network/parse_client.dart +++ b/packages/dart/lib/src/network/parse_client.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; typedef ParseClientCreator = ParseClient Function( {required bool sendSessionId, SecurityContext? securityContext}); @@ -93,12 +93,9 @@ class ParseNetworkResponse { class ParseNetworkByteResponse extends ParseNetworkResponse { ParseNetworkByteResponse({ this.bytes, - final String data = 'byte response', - final int statusCode = -1, - }) : super( - data: data, - statusCode: statusCode, - ); + super.data = 'byte response', + super.statusCode, + }); final List? bytes; } diff --git a/packages/dart/lib/src/network/parse_connectivity.dart b/packages/dart/lib/src/network/parse_connectivity.dart index 731ad1a4b..a6ea3dd81 100644 --- a/packages/dart/lib/src/network/parse_connectivity.dart +++ b/packages/dart/lib/src/network/parse_connectivity.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// Connection status check result. enum ParseConnectivityResult { diff --git a/packages/dart/lib/src/network/parse_dio_client.dart b/packages/dart/lib/src/network/parse_dio_client.dart index c262fe254..04842de90 100644 --- a/packages/dart/lib/src/network/parse_dio_client.dart +++ b/packages/dart/lib/src/network/parse_dio_client.dart @@ -229,6 +229,8 @@ class _ParseDioClient with dio.DioMixin implements dio.Dio { _logCUrl(options, data, path); } + checkForSubmitEventually(); + return super.request( path, data: data, @@ -270,33 +272,11 @@ class _ParseDioClient with dio.DioMixin implements dio.Dio { class _Options extends dio.Options { _Options({ - String? method, - Duration? sendTimeout, - Duration? receiveTimeout, - Map? extra, - Map? headers, - dio.ResponseType? responseType, + super.headers, + super.responseType, String? contentType, - dio.ValidateStatus? validateStatus, - bool? receiveDataWhenStatusError, - bool? followRedirects, - int? maxRedirects, - dio.RequestEncoder? requestEncoder, - dio.ResponseDecoder? responseDecoder, }) : super( - method: method, - sendTimeout: sendTimeout, - receiveTimeout: receiveTimeout, - extra: extra, - headers: headers, - responseType: responseType, contentType: contentType ?? (headers ?? {})[dio.Headers.contentTypeHeader], - validateStatus: validateStatus, - receiveDataWhenStatusError: receiveDataWhenStatusError, - followRedirects: followRedirects, - maxRedirects: maxRedirects, - requestEncoder: requestEncoder, - responseDecoder: responseDecoder, ); } diff --git a/packages/dart/lib/src/network/parse_http_client.dart b/packages/dart/lib/src/network/parse_http_client.dart index 86210be50..cf21724b7 100644 --- a/packages/dart/lib/src/network/parse_http_client.dart +++ b/packages/dart/lib/src/network/parse_http_client.dart @@ -158,6 +158,8 @@ class _ParseHTTPClient extends http.BaseClient { _logCUrl(request); } + checkForSubmitEventually(); + return _client.send(request); } diff --git a/packages/dart/lib/src/network/parse_live_query.dart b/packages/dart/lib/src/network/parse_live_query.dart index 0f94861f3..8778c0e07 100644 --- a/packages/dart/lib/src/network/parse_live_query.dart +++ b/packages/dart/lib/src/network/parse_live_query.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; enum LiveQueryEvent { create, enter, update, leave, delete, error } @@ -22,6 +22,7 @@ class Subscription { 'error' ]; Map eventCallbacks = {}; + void on(LiveQueryEvent op, Function callback) { eventCallbacks[_liveQueryEvent[op.index]] = callback; } @@ -140,8 +141,10 @@ class LiveQueryClient { reconnectingController = LiveQueryReconnectingController( () => reconnect(userInitialized: false), getClientEventStream, _debug); } + static LiveQueryClient get instance => _getInstance(); static LiveQueryClient? _instance; + static LiveQueryClient _getInstance({bool? debug, bool? autoSendSessionId}) { String? liveQueryURL = ParseCoreData().liveQueryURL; if (liveQueryURL == null) { @@ -174,13 +177,14 @@ class LiveQueryClient { bool _connecting = false; late StreamController _clientEventStreamController; late Stream _clientEventStream; + StreamController? chanelStream; late LiveQueryReconnectingController reconnectingController; final Map _requestSubscription = {}; Future reconnect({bool userInitialized = false}) async { await _connect(userInitialized: userInitialized); - _connectLiveQuery(); + await _connectLiveQuery(); } int readyState() { @@ -286,6 +290,8 @@ class LiveQueryClient { _channel = channel; channel.stream.listen((dynamic message) { _handleMessage(message); + + chanelStream?.sink.add(message); }, onDone: () { _clientEventStreamController.sink .add(LiveQueryClientEvent.disconnected); @@ -315,7 +321,7 @@ class LiveQueryClient { } } - void _connectLiveQuery() { + Future _connectLiveQuery() async { WebSocketChannel? channel = _channel; if (channel == null) { return; @@ -333,10 +339,22 @@ class LiveQueryClient { connectMessage['sessionToken'] = sessionId; } } + String? clientKey = ParseCoreData().clientKey; + if (clientKey != null) { + connectMessage['clientKey'] = clientKey; + } + String? masterKey = ParseCoreData().masterKey; - if (clientKey != null) connectMessage['clientKey'] = clientKey; - if (masterKey != null) connectMessage['masterKey'] = masterKey; + if (masterKey != null) { + connectMessage['masterKey'] = masterKey; + } + + String? parseInstallation = + (await ParseInstallation.currentInstallation()).installationId; + if (parseInstallation != null) { + connectMessage['installationId'] = parseInstallation; + } if (_debug) { print('$_printConstLiveQuery: ConnectMessage: $connectMessage'); diff --git a/packages/dart/lib/src/network/parse_query.dart b/packages/dart/lib/src/network/parse_query.dart index f9f659c5c..420b6fd8d 100644 --- a/packages/dart/lib/src/network/parse_query.dart +++ b/packages/dart/lib/src/network/parse_query.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// Class to create complex queries class QueryBuilder { diff --git a/packages/dart/lib/src/network/parse_websocket_html.dart b/packages/dart/lib/src/network/parse_websocket_html.dart index 35593e9a8..37555327f 100644 --- a/packages/dart/lib/src/network/parse_websocket_html.dart +++ b/packages/dart/lib/src/network/parse_websocket_html.dart @@ -1,4 +1,5 @@ /// If you change this file, you should apply the same changes to the 'parse_websocket_io.dart' file +library; import 'dart:html' as html; diff --git a/packages/dart/lib/src/network/parse_websocket_io.dart b/packages/dart/lib/src/network/parse_websocket_io.dart index b2cd15503..2f93d76fb 100644 --- a/packages/dart/lib/src/network/parse_websocket_io.dart +++ b/packages/dart/lib/src/network/parse_websocket_io.dart @@ -1,4 +1,5 @@ /// If you change this file, you should apply the same changes to the 'parse_websocket_html.dart' file +library; import 'dart:io' as io; diff --git a/packages/dart/lib/src/objects/parse_acl.dart b/packages/dart/lib/src/objects/parse_acl.dart index 618b86c5f..bf498e17e 100644 --- a/packages/dart/lib/src/objects/parse_acl.dart +++ b/packages/dart/lib/src/objects/parse_acl.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// [ParseACL] is used to control which users can access or modify a particular object /// [ParseObject] can have its own [ParseACL] diff --git a/packages/dart/lib/src/objects/parse_array.dart b/packages/dart/lib/src/objects/parse_array.dart index 1bf36e273..f4ebf602b 100644 --- a/packages/dart/lib/src/objects/parse_array.dart +++ b/packages/dart/lib/src/objects/parse_array.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class _ParseArray implements _Valuable, _ParseSaveStateAwareChild { _ParseArray({this.setMode = false}); diff --git a/packages/dart/lib/src/objects/parse_base.dart b/packages/dart/lib/src/objects/parse_base.dart index 97eced61e..00134fe4d 100644 --- a/packages/dart/lib/src/objects/parse_base.dart +++ b/packages/dart/lib/src/objects/parse_base.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; abstract class ParseBase { /// refers to the Table Name in your Parse Server diff --git a/packages/dart/lib/src/objects/parse_cloneable.dart b/packages/dart/lib/src/objects/parse_cloneable.dart index 589b60149..bf5d383c7 100644 --- a/packages/dart/lib/src/objects/parse_cloneable.dart +++ b/packages/dart/lib/src/objects/parse_cloneable.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// Creates method which can be used to deep clone objects abstract class ParseCloneable { diff --git a/packages/dart/lib/src/objects/parse_config.dart b/packages/dart/lib/src/objects/parse_config.dart index 8df935d63..6031ca147 100644 --- a/packages/dart/lib/src/objects/parse_config.dart +++ b/packages/dart/lib/src/objects/parse_config.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseConfig extends ParseObject { /// Creates an instance of ParseConfig so that you can grab all configs from the server diff --git a/packages/dart/lib/src/objects/parse_error.dart b/packages/dart/lib/src/objects/parse_error.dart index 323905c77..38e392486 100644 --- a/packages/dart/lib/src/objects/parse_error.dart +++ b/packages/dart/lib/src/objects/parse_error.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// ParseException is used in [ParseResult] to inform the user of the exception class ParseError { diff --git a/packages/dart/lib/src/objects/parse_exception.dart b/packages/dart/lib/src/objects/parse_exception.dart index 27cdaf70a..a760b4f82 100644 --- a/packages/dart/lib/src/objects/parse_exception.dart +++ b/packages/dart/lib/src/objects/parse_exception.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; abstract class ParseException implements Exception {} diff --git a/packages/dart/lib/src/objects/parse_file.dart b/packages/dart/lib/src/objects/parse_file.dart index faa666d34..6a1b6e383 100644 --- a/packages/dart/lib/src/objects/parse_file.dart +++ b/packages/dart/lib/src/objects/parse_file.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseFile extends ParseFileBase { /// Creates a new file @@ -6,16 +6,12 @@ class ParseFile extends ParseFileBase { /// {https://docs.parseplatform.org/rest/guide/#files/} ParseFile(this.file, {String? name, - String? url, - bool? debug, - ParseClient? client, - bool? autoSendSessionId}) + super.url, + super.debug, + super.client, + super.autoSendSessionId}) : super( name: file != null ? path.basename(file.path) : name!, - url: url, - debug: debug, - client: client, - autoSendSessionId: autoSendSessionId, ); File? file; @@ -82,7 +78,7 @@ class ParseFile extends ParseFileBase { final Map headers = { HttpHeaders.contentTypeHeader: - mime(file!.path) ?? 'application/octet-stream', + lookupMimeType(file!.path) ?? 'application/octet-stream', HttpHeaders.contentLengthHeader: '${file!.lengthSync()}', }; diff --git a/packages/dart/lib/src/objects/parse_file_base.dart b/packages/dart/lib/src/objects/parse_file_base.dart index 08cabff6e..3c16ed277 100644 --- a/packages/dart/lib/src/objects/parse_file_base.dart +++ b/packages/dart/lib/src/objects/parse_file_base.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; abstract class ParseFileBase extends ParseObject { /// Creates a new file @@ -40,7 +40,7 @@ abstract class ParseFileBase extends ParseObject { /// Uploads a file to Parse Server @override - Future save() async { + Future save({dynamic context}) async { return upload(); } diff --git a/packages/dart/lib/src/objects/parse_file_web.dart b/packages/dart/lib/src/objects/parse_file_web.dart index c45f5a9c0..cbaba5414 100644 --- a/packages/dart/lib/src/objects/parse_file_web.dart +++ b/packages/dart/lib/src/objects/parse_file_web.dart @@ -1,19 +1,12 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseWebFile extends ParseFileBase { ParseWebFile(this.file, - {required String name, - String? url, - bool? debug, - ParseClient? client, - bool? autoSendSessionId}) - : super( - name: name, - url: url, - debug: debug, - client: client, - autoSendSessionId: autoSendSessionId, - ); + {required super.name, + super.url, + super.debug, + super.client, + super.autoSendSessionId}); Uint8List? file; CancelToken? _cancelToken; @@ -61,7 +54,7 @@ class ParseWebFile extends ParseFileBase { final Map headers = { HttpHeaders.contentTypeHeader: - mime(url ?? name) ?? 'application/octet-stream', + lookupMimeType(url ?? name) ?? 'application/octet-stream', }; try { final String uri = ParseCoreData().serverUrl + _path; diff --git a/packages/dart/lib/src/objects/parse_function.dart b/packages/dart/lib/src/objects/parse_function.dart index 68331baca..5e307303e 100644 --- a/packages/dart/lib/src/objects/parse_function.dart +++ b/packages/dart/lib/src/objects/parse_function.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseCloudFunction extends ParseObject { /// Creates a new cloud function object diff --git a/packages/dart/lib/src/objects/parse_geo_point.dart b/packages/dart/lib/src/objects/parse_geo_point.dart index f7f60a2e8..f1a89193b 100644 --- a/packages/dart/lib/src/objects/parse_geo_point.dart +++ b/packages/dart/lib/src/objects/parse_geo_point.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; const String keyLatitude = 'latitude'; const String keyLongitude = 'longitude'; diff --git a/packages/dart/lib/src/objects/parse_installation.dart b/packages/dart/lib/src/objects/parse_installation.dart index 12c891849..5f4c01c33 100644 --- a/packages/dart/lib/src/objects/parse_installation.dart +++ b/packages/dart/lib/src/objects/parse_installation.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseInstallation extends ParseObject { /// Creates an instance of ParseInstallation @@ -113,7 +113,8 @@ class ParseInstallation extends ParseObject { } @override - Future create({bool allowCustomObjectId = false}) async { + Future create( + {bool allowCustomObjectId = false, dynamic context}) async { final bool isCurrent = await ParseInstallation.isCurrent(this); if (isCurrent) { await _updateInstallation(); @@ -130,7 +131,7 @@ class ParseInstallation extends ParseObject { /// Saves the current installation @override - Future save() async { + Future save({dynamic context}) async { final bool isCurrent = await ParseInstallation.isCurrent(this); if (isCurrent) { await _updateInstallation(); diff --git a/packages/dart/lib/src/objects/parse_number.dart b/packages/dart/lib/src/objects/parse_number.dart index 2b6c1be25..02b8b66f9 100644 --- a/packages/dart/lib/src/objects/parse_number.dart +++ b/packages/dart/lib/src/objects/parse_number.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class _ParseNumber implements _Valuable, _ParseSaveStateAwareChild { num estimateNumber; diff --git a/packages/dart/lib/src/objects/parse_object.dart b/packages/dart/lib/src/objects/parse_object.dart index dc60239a8..3af65c45e 100644 --- a/packages/dart/lib/src/objects/parse_object.dart +++ b/packages/dart/lib/src/objects/parse_object.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// [ParseObject] is a local representation of data that can be saved and /// retrieved from the Parse cloud. @@ -86,7 +86,8 @@ class ParseObject extends ParseBase implements ParseCloneable { /// Creates a new object and saves it online /// /// Prefer using [save] over [create] - Future create({bool allowCustomObjectId = false}) async { + Future create( + {bool allowCustomObjectId = false, dynamic context}) async { try { final Uri url = getSanitisedUri(_client, _path); final String body = json.encode(toJson( @@ -96,8 +97,17 @@ class ParseObject extends ParseBase implements ParseCloneable { _saveChanges(); - final ParseNetworkResponse result = - await _client.post(url.toString(), data: body); + final Map headers = { + keyHeaderContentType: keyHeaderContentTypeJson, + }; + + if (context != null) { + headers + .addAll({keyHeaderCloudContext: json.encode(parseEncode(context))}); + } + + final ParseNetworkResponse result = await _client.post(url.toString(), + data: body, options: ParseNetworkOptions(headers: headers)); final response = handleResponse( this, result, ParseApiRQ.create, _debug, parseClassName); @@ -120,7 +130,7 @@ class ParseObject extends ParseBase implements ParseCloneable { /// The object should hold an [objectId] in order to update it /// /// Prefer using [save] over [update] - Future update() async { + Future update({dynamic context}) async { assert( objectId != null && (objectId?.isNotEmpty ?? false), "Can't update a parse object while the objectId property is null or empty", @@ -133,9 +143,14 @@ class ParseObject extends ParseBase implements ParseCloneable { _saveChanges(); final Map headers = { - keyHeaderContentType: keyHeaderContentTypeJson + keyHeaderContentType: keyHeaderContentTypeJson, }; + if (context != null) { + headers + .addAll({keyHeaderCloudContext: json.encode(parseEncode(context))}); + } + final ParseNetworkResponse result = await _client.put(url.toString(), data: body, options: ParseNetworkOptions(headers: headers)); @@ -153,6 +168,25 @@ class ParseObject extends ParseBase implements ParseCloneable { } } + Future saveEventually() async { + // save object + final ParseResponse response = await save(); + + if (response.success) { + // return success response + return response; + } else { + // if have network connection error + if ((response.error?.message ?? "").contains(keyNetworkError)) { + // save this object in CoreStore + await _addThisObjectToParseCoreDataList(keyParseStoreObjects); + } else { + return response; + } + } + return response; + } + /// Saves the current object online. /// /// If the object not saved yet, this will create it. Otherwise, @@ -185,14 +219,14 @@ class ParseObject extends ParseBase implements ParseCloneable { /// Its safe to call this function aging if an error occurred while saving. /// /// Prefer using [save] over [update] and [create] - Future save() async { - final ParseResponse childrenResponse = await _saveChildren(this); + Future save({dynamic context}) async { + final ParseResponse childrenResponse = await _saveChildren(this, _client); if (childrenResponse.success) { ParseResponse? response; if (objectId == null) { - response = await create(); + response = await create(context: context); } else if (_isDirty(false)) { - response = await update(); + response = await update(context: context); } if (response != null) { @@ -207,7 +241,7 @@ class ParseObject extends ParseBase implements ParseCloneable { return childrenResponse; } - Future _saveChildren(dynamic object) async { + static Future _saveChildren(dynamic object, client) async { final Set uniqueObjects = {}; final Set uniqueFiles = {}; if (!_collectionDirtyChildren( @@ -253,7 +287,7 @@ class ParseObject extends ParseBase implements ParseCloneable { // TODO(yulingtianxia): lazy User /* Batch requests have currently a limit of 50 packaged requests per single request - This splitting will split the overall array into segments of upto 50 requests + This splitting will split the overall array into segments of up to 50 requests and execute them concurrently with a wrapper task for all of them. */ final List> chunks = >[]; for (int i = 0; i < current.length; i += 50) { @@ -271,7 +305,7 @@ class ParseObject extends ParseBase implements ParseCloneable { final ParseResponse response = await batchRequest( requests, chunk, - client: _client, + client: client, ); totalResponse.success &= response.success; @@ -371,7 +405,7 @@ class ParseObject extends ParseBase implements ParseCloneable { return true; } - bool _collectionDirtyChildren( + static bool _collectionDirtyChildren( dynamic object, Set uniqueObjects, Set uniqueFiles, @@ -625,6 +659,32 @@ class ParseObject extends ParseBase implements ParseCloneable { } } + Future deleteEventually() async { + // save object + final ParseResponse response = await delete(); + + if (response.success) { + // return success response + return response; + } else { + // if have network connection error + if ((response.error?.message ?? "").contains(keyNetworkError)) { + // save this object in CoreStore + await _addThisObjectToParseCoreDataList(keyParseStoreDeletes); + } else { + return response; + } + } + return response; + } + + Future _addThisObjectToParseCoreDataList(String key) async { + final CoreStore coreStore = ParseCoreData().getStore(); + List list = await coreStore.getStringList(key) ?? []; + list.add(json.encode(toJson(full: true))); + await coreStore.setStringList(key, list); + } + /// Deletes the current object locally and online Future delete({ String? id, @@ -677,4 +737,114 @@ class ParseObject extends ParseBase implements ParseCloneable { return this; } } + + static Future submitEventually( + {ParseClient? client, bool? autoSendSessionId}) async { + await submitSaveEventually( + client: client, autoSendSessionId: autoSendSessionId); + await submitDeleteEventually( + client: client, autoSendSessionId: autoSendSessionId); + + Parse.objectsExistForEventually = await checkObjectsExistForEventually(); + } + + static Future submitSaveEventually( + {ParseClient? client, bool? autoSendSessionId}) async { + // get client + ParseClient localClient = client ?? + ParseCoreData().clientCreator( + sendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); + + // preparation ParseCoreData + final CoreStore coreStore = ParseCoreData().getStore(); + + // save + // get json parse saved objects + List? listSaves = + await coreStore.getStringList(keyParseStoreObjects); + + if (listSaves != null) { + List parseObjectList = []; + for (var element in listSaves) { + // decode json + dynamic object = json.decode(element); + parseObjectList + .add(ParseObject(object[keyVarClassName]).fromJson(object)); + } + + // send parseObjects to server + ParseResponse response = + await ParseObject._saveChildren(parseObjectList, localClient); + + // if success clear all objects + if (response.success) { + coreStore.setStringList(keyParseStoreObjects, []); + } + + return response; + } + + return null; + } + + static Future submitDeleteEventually( + {ParseClient? client, bool? autoSendSessionId}) async { + // preparation ParseCoreData + final CoreStore coreStore = ParseCoreData().getStore(); + + // delete + // get json parse saved objects + List? listDeletes = + await coreStore.getStringList(keyParseStoreDeletes); + + if (listDeletes != null) { + int firstLength = listDeletes.length; + List elementsToRemove = []; + for (var element in listDeletes) { + // decode json + dynamic object = json.decode(element); + + // crate parse object + ParseObject parseObject = ParseObject(object[keyVarClassName], + client: client, autoSendSessionId: autoSendSessionId) + .fromJson(object); + + // delete parse object + ParseResponse deleteResponse = await parseObject.delete(); + + if (deleteResponse.success) { + // remove from list Deletes + elementsToRemove.add(element); + } + } + + // Remove the elements after the loop + for (var elementToRemove in elementsToRemove) { + listDeletes.remove(elementToRemove); + } + + // set new list deletes in coreStore + coreStore.setStringList(keyParseStoreDeletes, listDeletes); + + bool success = true; + int statusCode = 200; + + if (listDeletes.length == firstLength) { + // Nothing has been deleted + success = false; + statusCode = -1; + } + + final ParseResponse response = ParseResponse() + ..success = success + ..results = [] + ..statusCode = statusCode; + + return response; + } + + return null; + } } diff --git a/packages/dart/lib/src/objects/parse_operation/parse_add_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_add_operation.dart index 16f892de6..d48b2fb76 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_add_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_add_operation.dart @@ -1,8 +1,8 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// An operation that adds a new element to an array class _ParseAddOperation extends _ParseArrayOperation { - _ParseAddOperation(List value) : super(value); + _ParseAddOperation(super.value); @override String get operationName => 'Add'; diff --git a/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart index 716868096..2eaa1b5d6 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart @@ -1,8 +1,8 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// An operation that adds new objects to a [ParseRelation] class _ParseAddRelationOperation extends _ParseRelationOperation { - _ParseAddRelationOperation(Set value) : super(value); + _ParseAddRelationOperation(super.value); @override String get operationName => 'AddRelation'; diff --git a/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart index a7cb87ceb..ac6066861 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart @@ -1,9 +1,9 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// An operation that adds a new element to an array field, /// only if it wasn't already present class _ParseAddUniqueOperation extends _ParseArrayOperation { - _ParseAddUniqueOperation(List value) : super(value); + _ParseAddUniqueOperation(super.value); @override String get operationName => 'AddUnique'; diff --git a/packages/dart/lib/src/objects/parse_operation/parse_increment_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_increment_operation.dart index 765cf3494..88de06b5f 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_increment_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_increment_operation.dart @@ -1,8 +1,8 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// An operation that increment a numeric value by a given amount class _ParseIncrementOperation extends _ParseNumberOperation { - _ParseIncrementOperation(num value) : super(value); + _ParseIncrementOperation(super.value); @override String get operationName => 'Increment'; diff --git a/packages/dart/lib/src/objects/parse_operation/parse_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_operation.dart index 68fc92ee4..f9e39b3cc 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_operation.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// Represents an operation performed on Parse data. It defines the core /// functionality of any operation performed on Parse data. @@ -182,7 +182,7 @@ abstract class _ParseOperation implements _Valuable { } abstract class _ParseArrayOperation extends _ParseOperation { - _ParseArrayOperation(List value) : super(value) { + _ParseArrayOperation(super.value) { super.valueForApiRequest = []; } @@ -229,7 +229,7 @@ abstract class _ParseArrayOperation extends _ParseOperation { abstract class _ParseRelationOperation extends _ParseOperation> { - _ParseRelationOperation(Set value) : super(value) { + _ParseRelationOperation(super.value) { super.valueForApiRequest = {}; } diff --git a/packages/dart/lib/src/objects/parse_operation/parse_remove_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_remove_operation.dart index 6ac974c4b..d27c427eb 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_remove_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_remove_operation.dart @@ -1,8 +1,8 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// An operation that removes every instance of an element from an array class _ParseRemoveOperation extends _ParseArrayOperation { - _ParseRemoveOperation(List value) : super(value); + _ParseRemoveOperation(super.value); @override String get operationName => 'Remove'; diff --git a/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart index 725701ba3..5985d3508 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart @@ -1,8 +1,8 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// An operation that Removes objects from a [ParseRelation] class _ParseRemoveRelationOperation extends _ParseRelationOperation { - _ParseRemoveRelationOperation(Set value) : super(value); + _ParseRemoveRelationOperation(super.value); @override String get operationName => 'RemoveRelation'; diff --git a/packages/dart/lib/src/objects/parse_relation.dart b/packages/dart/lib/src/objects/parse_relation.dart index 16d75f627..3be59616a 100644 --- a/packages/dart/lib/src/objects/parse_relation.dart +++ b/packages/dart/lib/src/objects/parse_relation.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; abstract class ParseRelation { //The owning object of this ParseRelation diff --git a/packages/dart/lib/src/objects/parse_response.dart b/packages/dart/lib/src/objects/parse_response.dart index 41a6950bb..ad1c21bd0 100644 --- a/packages/dart/lib/src/objects/parse_response.dart +++ b/packages/dart/lib/src/objects/parse_response.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseResponse { ParseResponse({ diff --git a/packages/dart/lib/src/objects/parse_save_state_aware_child.dart b/packages/dart/lib/src/objects/parse_save_state_aware_child.dart index 32fe4a5a1..bb1a2fe2e 100644 --- a/packages/dart/lib/src/objects/parse_save_state_aware_child.dart +++ b/packages/dart/lib/src/objects/parse_save_state_aware_child.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// An interface used to notify a child about its parent save state. /// diff --git a/packages/dart/lib/src/objects/parse_session.dart b/packages/dart/lib/src/objects/parse_session.dart index 2be307542..9f98ab1bb 100644 --- a/packages/dart/lib/src/objects/parse_session.dart +++ b/packages/dart/lib/src/objects/parse_session.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseSession extends ParseObject implements ParseCloneable { ParseSession({ diff --git a/packages/dart/lib/src/objects/parse_user.dart b/packages/dart/lib/src/objects/parse_user.dart index 8bdf0c7d3..eb91a9cba 100644 --- a/packages/dart/lib/src/objects/parse_user.dart +++ b/packages/dart/lib/src/objects/parse_user.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class ParseUser extends ParseObject implements ParseCloneable { /// Creates an instance of ParseUser @@ -393,7 +393,7 @@ class ParseUser extends ParseObject implements ParseCloneable { /// If changes are made to the current user, call save to sync them with /// Parse Server @override - Future save() async { + Future save({dynamic context}) async { if (objectId == null) { return await signUp(); } else { @@ -406,7 +406,7 @@ class ParseUser extends ParseObject implements ParseCloneable { } @override - Future update() async { + Future update({dynamic context}) async { if (objectId == null) { return await signUp(); } else { diff --git a/packages/dart/lib/src/objects/parse_x_file.dart b/packages/dart/lib/src/objects/parse_x_file.dart new file mode 100644 index 000000000..cb66e40dc --- /dev/null +++ b/packages/dart/lib/src/objects/parse_x_file.dart @@ -0,0 +1,154 @@ +part of '../../parse_server_sdk.dart'; + +class ParseXFile extends ParseFileBase { + /// Creates a new file base XFile + /// + /// {https://docs.parseplatform.org/rest/guide/#files/} + ParseXFile(this.file, + {String? name, + super.url, + super.debug, + super.client, + super.autoSendSessionId}) + : super( + name: file != null ? path.basename(file.path) : name!, + ); + + XFile? file; + CancelToken? _cancelToken; + ProgressCallback? _progressCallback; + + Future 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 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 upload({ProgressCallback? progressCallback}) async { + if (saved) { + //Creates a Fake Response to return the correct result + final Map response = { + 'url': url!, + 'name': name + }; + return handleResponse( + this, + ParseNetworkResponse(data: json.encode(response), statusCode: 201), + ParseApiRQ.upload, + _debug, + parseClassName); + } + + progressCallback ??= _progressCallback; + + _cancelToken = CancelToken(); + Map headers; + if (parseIsWeb) { + headers = { + HttpHeaders.contentTypeHeader: file?.mimeType ?? + lookupMimeType(url ?? file?.name ?? name, + headerBytes: await file?.readAsBytes()) ?? + 'application/octet-stream', + }; + } else { + headers = { + HttpHeaders.contentTypeHeader: file?.mimeType ?? + lookupMimeType(file!.path) ?? + 'application/octet-stream', + HttpHeaders.contentLengthHeader: '${await file!.length()}', + }; + } + + try { + final String uri = ParseCoreData().serverUrl + _path; + + Stream>? data; + if (parseIsWeb) { + data = Stream>.fromIterable( + >[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 map = json.decode(response.data); + url = map['url'].toString(); + name = map['name'].toString(); + } + return handleResponse( + 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; + } +} diff --git a/packages/dart/lib/src/objects/response/parse_error_response.dart b/packages/dart/lib/src/objects/response/parse_error_response.dart index 665de480b..ef1ccb504 100644 --- a/packages/dart/lib/src/objects/response/parse_error_response.dart +++ b/packages/dart/lib/src/objects/response/parse_error_response.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// Handles any errors returned in response ParseResponse buildErrorResponse( diff --git a/packages/dart/lib/src/objects/response/parse_exception_response.dart b/packages/dart/lib/src/objects/response/parse_exception_response.dart index 2302bd1d1..2450c3425 100644 --- a/packages/dart/lib/src/objects/response/parse_exception_response.dart +++ b/packages/dart/lib/src/objects/response/parse_exception_response.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// Handles exception instead of throwing an exception ParseResponse buildParseResponseWithException(Exception exception) { diff --git a/packages/dart/lib/src/objects/response/parse_response_builder.dart b/packages/dart/lib/src/objects/response/parse_response_builder.dart index 706cd1d28..8390476e5 100644 --- a/packages/dart/lib/src/objects/response/parse_response_builder.dart +++ b/packages/dart/lib/src/objects/response/parse_response_builder.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// Handles all the ParseObject responses /// diff --git a/packages/dart/lib/src/objects/response/parse_response_utils.dart b/packages/dart/lib/src/objects/response/parse_response_utils.dart index f125c321a..812849265 100644 --- a/packages/dart/lib/src/objects/response/parse_response_utils.dart +++ b/packages/dart/lib/src/objects/response/parse_response_utils.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// Handles an API response and logs data if [bool] debug is enabled @protected diff --git a/packages/dart/lib/src/objects/response/parse_success_no_results.dart b/packages/dart/lib/src/objects/response/parse_success_no_results.dart index 24271d265..0383458b5 100644 --- a/packages/dart/lib/src/objects/response/parse_success_no_results.dart +++ b/packages/dart/lib/src/objects/response/parse_success_no_results.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../../parse_server_sdk.dart'; /// Handles successful responses with no results ParseResponse buildSuccessResponseWithNoResults( diff --git a/packages/dart/lib/src/storage/core_store.dart b/packages/dart/lib/src/storage/core_store.dart index 5b06c2d2f..06ab62938 100644 --- a/packages/dart/lib/src/storage/core_store.dart +++ b/packages/dart/lib/src/storage/core_store.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; abstract class CoreStore { Future containsKey(String key); diff --git a/packages/dart/lib/src/storage/core_store_memory.dart b/packages/dart/lib/src/storage/core_store_memory.dart index b35c10322..696876cf7 100644 --- a/packages/dart/lib/src/storage/core_store_memory.dart +++ b/packages/dart/lib/src/storage/core_store_memory.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class CoreStoreMemoryImp implements CoreStore { static Map _data = {}; diff --git a/packages/dart/lib/src/storage/core_store_sem_impl.dart b/packages/dart/lib/src/storage/core_store_sem_impl.dart index 9fc826c8d..f0bb4451b 100644 --- a/packages/dart/lib/src/storage/core_store_sem_impl.dart +++ b/packages/dart/lib/src/storage/core_store_sem_impl.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; // ignore_for_file: deprecated_member_use class CoreStoreSembastImp implements CoreStore { diff --git a/packages/dart/lib/src/storage/xxtea_codec.dart b/packages/dart/lib/src/storage/xxtea_codec.dart index 11753cf01..843e78c65 100644 --- a/packages/dart/lib/src/storage/xxtea_codec.dart +++ b/packages/dart/lib/src/storage/xxtea_codec.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; class _XXTeaEncoder extends Converter, String> { _XXTeaEncoder(this.key); diff --git a/packages/dart/lib/src/utils/parse_date_format.dart b/packages/dart/lib/src/utils/parse_date_format.dart index 427829357..69b88e34d 100644 --- a/packages/dart/lib/src/utils/parse_date_format.dart +++ b/packages/dart/lib/src/utils/parse_date_format.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; final _ParseDateFormat _parseDateFormat = _ParseDateFormat._internal(); diff --git a/packages/dart/lib/src/utils/parse_decoder.dart b/packages/dart/lib/src/utils/parse_decoder.dart index 252793ee3..3a3f043f0 100644 --- a/packages/dart/lib/src/utils/parse_decoder.dart +++ b/packages/dart/lib/src/utils/parse_decoder.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; List _convertJSONArrayToList(List array) { return array.map(parseDecode).toList(); diff --git a/packages/dart/lib/src/utils/parse_encoder.dart b/packages/dart/lib/src/utils/parse_encoder.dart index d712acb83..c957a39e9 100644 --- a/packages/dart/lib/src/utils/parse_encoder.dart +++ b/packages/dart/lib/src/utils/parse_encoder.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// Custom encoder for DateTime dynamic dateTimeEncoder(dynamic item) { diff --git a/packages/dart/lib/src/utils/parse_live_list.dart b/packages/dart/lib/src/utils/parse_live_list.dart index 99df16cc2..43464c5e7 100644 --- a/packages/dart/lib/src/utils/parse_live_list.dart +++ b/packages/dart/lib/src/utils/parse_live_list.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; // ignore_for_file: invalid_use_of_protected_member class ParseLiveList { @@ -31,6 +31,7 @@ class ParseLiveList { } final QueryBuilder _query; + //The included Items, where LiveList should look for updates. final Map _listeningIncludes; final bool _lazyLoading; @@ -539,6 +540,10 @@ class ParseLiveElement extends ParseLiveListElement { super.object = parseResponse.result.first; } break; + case LiveQueryClientEvent.disconnected: + break; + case LiveQueryClientEvent.userDisconnected: + break; } }); }); @@ -742,6 +747,7 @@ class PathKey { final String key; Subscription? subscription; + @override String toString() { return 'PathKey(key: $key, subscription: ${subscription?.requestId})'; @@ -761,17 +767,17 @@ abstract class ParseLiveListEvent { class ParseLiveListAddEvent extends ParseLiveListEvent { - ParseLiveListAddEvent(int index, T object) : super(index, object); + ParseLiveListAddEvent(super.index, super.object); } class ParseLiveListUpdateEvent extends ParseLiveListEvent { - ParseLiveListUpdateEvent(int index, T object) : super(index, object); + ParseLiveListUpdateEvent(super.index, super.object); } class ParseLiveListDeleteEvent extends ParseLiveListEvent { - ParseLiveListDeleteEvent(int index, T object) : super(index, object); + ParseLiveListDeleteEvent(super.index, super.object); } class ParseLiveListElementSnapshot { diff --git a/packages/dart/lib/src/utils/parse_logger.dart b/packages/dart/lib/src/utils/parse_logger.dart index 0e3f507f5..e67bf6b8d 100644 --- a/packages/dart/lib/src/utils/parse_logger.dart +++ b/packages/dart/lib/src/utils/parse_logger.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; void logAPIResponse( String className, String type, ParseResponse parseResponse) { diff --git a/packages/dart/lib/src/utils/parse_login_helpers.dart b/packages/dart/lib/src/utils/parse_login_helpers.dart index 88f03a54a..8147bf30c 100644 --- a/packages/dart/lib/src/utils/parse_login_helpers.dart +++ b/packages/dart/lib/src/utils/parse_login_helpers.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; Map facebook(String token, String id, DateTime expires) { return { diff --git a/packages/dart/lib/src/utils/parse_utils.dart b/packages/dart/lib/src/utils/parse_utils.dart index 03bb37781..13dee46e5 100644 --- a/packages/dart/lib/src/utils/parse_utils.dart +++ b/packages/dart/lib/src/utils/parse_utils.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// Checks whether debug is enabled /// @@ -127,3 +127,41 @@ List removeDuplicateParseObjectByObjectId(Iterable iterable) { return list; } + +// check the coreStore for existing objects to delete or save eventually +Future checkObjectsExistForEventually() async { + // preparation ParseCoreData + final CoreStore coreStore = ParseCoreData().getStore(); + + List? listSaves = await coreStore.getStringList(keyParseStoreObjects); + + if (listSaves != null) { + if (listSaves.isNotEmpty) { + return true; + } + } + + List? listDeletes = + await coreStore.getStringList(keyParseStoreDeletes); + + if (listDeletes != null) { + if (listDeletes.isNotEmpty) { + return true; + } + } + + return false; +} + +// To get out of the cycle +bool _inSubmitEventually = false; + +Future checkForSubmitEventually() async { + if (_inSubmitEventually) return; + + if (Parse.objectsExistForEventually) { + _inSubmitEventually = true; + await ParseObject.submitEventually(); + _inSubmitEventually = false; + } +} diff --git a/packages/dart/lib/src/utils/valuable.dart b/packages/dart/lib/src/utils/valuable.dart index 8c1c79e9a..2a4522181 100644 --- a/packages/dart/lib/src/utils/valuable.dart +++ b/packages/dart/lib/src/utils/valuable.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk; +part of '../../parse_server_sdk.dart'; /// A unified interface used to expose the internal state of a private class. /// diff --git a/packages/dart/pubspec.yaml b/packages/dart/pubspec.yaml index b11457b16..369c91e8c 100644 --- a/packages/dart/pubspec.yaml +++ b/packages/dart/pubspec.yaml @@ -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: 5.1.3 +version: 7.0.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 @@ -18,35 +18,36 @@ topics: - backend environment: - sdk: ">=2.18.0 <4.0.0" + sdk: ">=3.0.7 <4.0.0" dependencies: # Networking - dio: ^5.2.0+1 - http: ^0.13.5 + dio: ^5.4.2+1 + http: ^1.1.0 web_socket_channel: ^2.4.0 #Database - sembast: ^3.4.6+1 - sembast_web: ^2.1.3 + sembast: ^3.6.0 + sembast_web: ^2.2.0 # Utils - uuid: ^3.0.7 - meta: ^1.8.0 - path: ^1.8.2 - mime_type: ^1.0.0 + uuid: ^4.3.3 + meta: ^1.12.0 + path: ^1.9.0 + mime: ^1.0.4 timezone: ^0.9.2 - universal_io: ^2.2.0 + universal_io: ^2.2.2 xxtea: ^2.1.0 - collection: ^1.16.0 + collection: ^1.18.0 + cross_file: ^0.3.3+7 dev_dependencies: - lints: ^2.0.1 + lints: ^3.0.0 # Testing - build_runner: ^2.3.3 - mockito: ^5.3.2 - test: ^1.23.1 + build_runner: ^2.4.9 + mockito: ^5.4.2 + test: ^1.24.9 screenshots: - description: Parse Platform logo. diff --git a/packages/dart/test/src/network/parse_live_query_test.dart b/packages/dart/test/src/network/parse_live_query_test.dart new file mode 100644 index 000000000..a7dc928e8 --- /dev/null +++ b/packages/dart/test/src/network/parse_live_query_test.dart @@ -0,0 +1,63 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:parse_server_sdk/parse_server_sdk.dart'; +import 'package:test/test.dart'; + +import '../../test_utils.dart'; + +void main() { + setUpAll(() async { + // Create a fake server + final channel = spawnHybridCode(r''' + import 'dart:io'; + import 'package:stream_channel/stream_channel.dart'; + + hybridMain(StreamChannel channel) async { + var server = await HttpServer.bind('localhost', 0); + server.transform(WebSocketTransformer()).listen((webSocket) { + webSocket.listen((request) { + webSocket.add(request); + }); + }); + channel.sink.add(server.port); + } + '''); + + // Get port server + int port = await channel.stream.first as int; + await initializeParse(liveQueryUrl: 'http://localhost:$port'); + }); + + test('should exist installationId in connect LiveQuery', () async { + // arrange + QueryBuilder query = + QueryBuilder(ParseObject('Test')); + + // Set installationId + ParseInstallation parseInstallation = ParseInstallation(); + parseInstallation.set(keyInstallationId, "1234"); + final String objectJson = json.encode(parseInstallation.toJson(full: true)); + await ParseCoreData() + .getStore() + .setString(keyParseStoreInstallation, objectJson); + + // Initialize LiveQuery + final LiveQuery liveQuery = LiveQuery(); + liveQuery.client.chanelStream = StreamController(); + + // act + await liveQuery.client.reconnect(); + await liveQuery.client.subscribe(query); + + // assert + liveQuery.client.chanelStream?.stream.listen((event) { + if (event.contains('connect')) { + expect(true, event.contains('1234')); + } + }); + + // 10 millisecond hold for stream + await Future.delayed(Duration(milliseconds: 10)); + }); +} diff --git a/packages/dart/test/src/objects/parse_object/parse_object_delete_eventually_test.dart b/packages/dart/test/src/objects/parse_object/parse_object_delete_eventually_test.dart new file mode 100644 index 000000000..0e333eb13 --- /dev/null +++ b/packages/dart/test/src/objects/parse_object/parse_object_delete_eventually_test.dart @@ -0,0 +1,76 @@ +import 'dart:convert'; + +import 'package:mockito/mockito.dart'; +import 'package:parse_server_sdk/parse_server_sdk.dart'; +import 'package:test/test.dart'; + +import '../../../parse_query_test.mocks.dart'; +import '../../../test_utils.dart'; + +void main() { + setUpAll(() async { + await initializeParse(); + }); + + group('deleteEventually()', () { + late MockParseClient client1; + late MockParseClient client2; + + late ParseObject dietPlansObject; + + setUp(() { + client1 = MockParseClient(); + client2 = MockParseClient(); + + dietPlansObject = ParseObject("Diet_Plans", client: client1); + + dietPlansObject.objectId = "fakeObjectId"; + }); + + test( + 'should exist parse object in ParseCoreData next saveEventually', + () async { + // arrange + when(client1.delete( + any, + options: anyNamed("options"), + )).thenThrow(Exception('NetworkError')); + + when(client2.delete( + "$serverUrl/classes/Diet_Plans/fakeObjectId", + options: anyNamed("options"), + )).thenAnswer( + (_) async => ParseNetworkResponse( + statusCode: 200, + data: jsonEncode([ + { + "success": { + "delete": "ok", + } + } + ]), + ), + ); + + // act + await dietPlansObject.deleteEventually(); + + final CoreStore coreStore = ParseCoreData().getStore(); + List list = + await coreStore.getStringList(keyParseStoreDeletes) ?? []; + + // assert + expect(list.length, 1); + + // act + await ParseObject.submitEventually(client: client2); + + List list2 = + await coreStore.getStringList(keyParseStoreDeletes) ?? []; + + // assert + expect(list2.length, 0); + }, + ); + }); +} diff --git a/packages/dart/test/src/objects/parse_object/parse_object_save_eventually_test.dart b/packages/dart/test/src/objects/parse_object/parse_object_save_eventually_test.dart new file mode 100644 index 000000000..5ba020a01 --- /dev/null +++ b/packages/dart/test/src/objects/parse_object/parse_object_save_eventually_test.dart @@ -0,0 +1,74 @@ +import 'dart:convert'; + +import 'package:mockito/mockito.dart'; +import 'package:parse_server_sdk/parse_server_sdk.dart'; +import 'package:test/test.dart'; + +import '../../../parse_query_test.mocks.dart'; +import '../../../test_utils.dart'; + +void main() { + setUpAll(() async { + await initializeParse(); + }); + + group('saveEventually()', () { + late MockParseClient client; + + late ParseObject dietPlansObject; + + setUp(() { + client = MockParseClient(); + + dietPlansObject = ParseObject("Diet_Plans", client: client); + }); + + test( + 'should exist parse object in ParseCoreData next saveEventually', + () async { + // arrange + when(client.post( + any, + options: anyNamed("options"), + data: anyNamed("data"), + )).thenThrow(Exception('NetworkError')); + + when(client.post( + "$serverUrl/batch", + options: anyNamed("options"), + data: anyNamed("data"), + )).thenAnswer( + (_) async => ParseNetworkResponse( + statusCode: 200, + data: jsonEncode([ + { + "success": { + "add": "ok", + } + } + ]), + ), + ); + + // act + await dietPlansObject.saveEventually(); + + final CoreStore coreStore = ParseCoreData().getStore(); + List list = + await coreStore.getStringList(keyParseStoreObjects) ?? []; + + // assert + expect(list.length, 1); + + // act + await ParseObject.submitEventually(client: client); + + List list2 = + await coreStore.getStringList(keyParseStoreObjects) ?? []; + + // assert + expect(list2.length, 0); + }, + ); + }); +} diff --git a/packages/dart/test/test_utils.dart b/packages/dart/test/test_utils.dart index 2f138551a..fbf7ee43b 100644 --- a/packages/dart/test/test_utils.dart +++ b/packages/dart/test/test_utils.dart @@ -3,10 +3,11 @@ import 'package:test/test.dart'; const serverUrl = 'https://example.com/'; -Future initializeParse() async { +Future initializeParse({String? liveQueryUrl}) async { await Parse().initialize( 'appId', serverUrl, + liveQueryUrl: liveQueryUrl, debug: true, // to prevent automatic detection fileDirectory: 'someDirectory', diff --git a/packages/flutter/CHANGELOG.md b/packages/flutter/CHANGELOG.md index 421029bfe..f7a334142 100644 --- a/packages/flutter/CHANGELOG.md +++ b/packages/flutter/CHANGELOG.md @@ -1,3 +1,19 @@ +## [8.0.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/flutter-7.0.0...flutter-8.0.0) (2024-05-15) + +### BREAKING CHANGES + +* This release removes support for Flutter 3.3, 3.7 ([#994](https://github.com/parse-community/Parse-SDK-Flutter/pull/994)) + +### Features + +* Add support for Flutter 3.13, 3.16, 3.19; remove support for Flutter 3.3, 3.7 ([#994](https://github.com/parse-community/Parse-SDK-Flutter/pull/994)) + +## [7.0.1](https://github.com/parse-community/Parse-SDK-Flutter/compare/flutter-7.0.0...flutter-7.0.1) (2024-02-03) + +### Bug Fixes + +* Conflict with new version of `connectivity_plus` dependency ([#987](https://github.com/parse-community/Parse-SDK-Flutter/pull/987)) + ## [7.0.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/flutter-6.0.0...flutter-7.0.0) (2023-10-16) ### BREAKING CHANGES diff --git a/packages/flutter/README.md b/packages/flutter/README.md index 5aa6c65ef..fe4989833 100644 --- a/packages/flutter/README.md +++ b/packages/flutter/README.md @@ -32,10 +32,10 @@ The Parse Flutter SDK is continuously tested with the most recent release of the | Version | Latest Version | End of Support | Compatible | |--------------|----------------|----------------|------------| -| Flutter 3.13 | 3.13.6 | Sep 2024 | ✅ Yes | | Flutter 3.10 | 3.10.6 | Jul 2024 | ✅ Yes | -| Flutter 3.7 | 3.7.12 | Apr 2024 | ✅ Yes | -| Flutter 3.3 | 3.3.10 | Dec 2024 | ✅ Yes | +| Flutter 3.13 | 3.13.9 | Oct 2024 | ✅ Yes | +| Flutter 3.16 | 3.16.9 | Jan 2025 | ✅ Yes | +| Flutter 3.19 | 3.19.5 | Mar 2025 | ✅ Yes | ## Getting Started diff --git a/packages/flutter/lib/src/notification/parse_notification.dart b/packages/flutter/lib/src/notification/parse_notification.dart index 92a2ec69d..547e2e32e 100644 --- a/packages/flutter/lib/src/notification/parse_notification.dart +++ b/packages/flutter/lib/src/notification/parse_notification.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk_flutter; +part of 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart'; /// A class that provides a mechanism for showing system notifications in the app. class ParseNotification { diff --git a/packages/flutter/lib/src/push/parse_push.dart b/packages/flutter/lib/src/push/parse_push.dart index 7147f24e1..7deaec45c 100644 --- a/packages/flutter/lib/src/push/parse_push.dart +++ b/packages/flutter/lib/src/push/parse_push.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk_flutter; +part of 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart'; /// A class that provides a mechanism for handling push notifications in the app. class ParsePush { diff --git a/packages/flutter/lib/src/storage/core_store_sembast.dart b/packages/flutter/lib/src/storage/core_store_sembast.dart index b6d213ce8..5e00d0ee0 100644 --- a/packages/flutter/lib/src/storage/core_store_sembast.dart +++ b/packages/flutter/lib/src/storage/core_store_sembast.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk_flutter; +part of 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart'; /// provides database operations using Sembast class CoreStoreSembast implements sdk.CoreStoreSembastImp { diff --git a/packages/flutter/lib/src/storage/core_store_shared_preferences.dart b/packages/flutter/lib/src/storage/core_store_shared_preferences.dart index 7fdd98dc2..30afc0a23 100644 --- a/packages/flutter/lib/src/storage/core_store_shared_preferences.dart +++ b/packages/flutter/lib/src/storage/core_store_shared_preferences.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk_flutter; +part of 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart'; /// A class that implements the `sdk.CoreStore` interface using `SharedPreferences`. class CoreStoreSharedPreferences implements sdk.CoreStore { diff --git a/packages/flutter/lib/src/utils/parse_live_grid.dart b/packages/flutter/lib/src/utils/parse_live_grid.dart index 6b4c91a06..41407ffd4 100644 --- a/packages/flutter/lib/src/utils/parse_live_grid.dart +++ b/packages/flutter/lib/src/utils/parse_live_grid.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk_flutter; +part of 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart'; /// A widget that displays a live grid of Parse objects. /// @@ -11,7 +11,7 @@ part of flutter_parse_sdk_flutter; /// refreshing the live list of objects. class ParseLiveGridWidget extends StatefulWidget { const ParseLiveGridWidget({ - Key? key, + super.key, required this.query, this.gridLoadingElement, this.queryEmptyElement, @@ -34,7 +34,7 @@ class ParseLiveGridWidget extends StatefulWidget { this.crossAxisSpacing = 5.0, this.mainAxisSpacing = 5.0, this.childAspectRatio = 0.80, - }) : super(key: key); + }); final sdk.QueryBuilder query; final Widget? gridLoadingElement; diff --git a/packages/flutter/lib/src/utils/parse_live_list.dart b/packages/flutter/lib/src/utils/parse_live_list.dart index 020fcf2ca..da212eb07 100644 --- a/packages/flutter/lib/src/utils/parse_live_list.dart +++ b/packages/flutter/lib/src/utils/parse_live_list.dart @@ -1,4 +1,4 @@ -part of flutter_parse_sdk_flutter; +part of 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart'; /// The type of function that builds a child widget for a ParseLiveList element. typedef ChildBuilder = Widget Function( @@ -20,7 +20,7 @@ typedef DataGetter = T? Function(); /// lazy loading of objects in the list. class ParseLiveListWidget extends StatefulWidget { const ParseLiveListWidget({ - Key? key, + super.key, required this.query, this.listLoadingElement, this.queryEmptyElement, @@ -38,7 +38,7 @@ class ParseLiveListWidget extends StatefulWidget { this.listeningIncludes, this.lazyLoading = true, this.preloadedColumns, - }) : super(key: key); + }); final sdk.QueryBuilder query; final Widget? listLoadingElement; @@ -209,14 +209,13 @@ class _ParseLiveListWidgetState class ParseLiveListElementWidget extends StatefulWidget { const ParseLiveListElementWidget( - {Key? key, + {super.key, this.stream, this.loadedData, this.preLoadedData, required this.sizeFactor, required this.duration, - required this.childBuilder}) - : super(key: key); + required this.childBuilder}); final StreamGetter? stream; final DataGetter? loadedData; diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 4ebb01698..7a6453fdd 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: parse_server_sdk_flutter description: The Flutter SDK to connect to Parse Server. Build your apps faster with Parse Platform, the complete application stack. -version: 7.0.0 +version: 8.0.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 @@ -18,38 +18,38 @@ topics: - backend environment: - sdk: ">=2.19.6 <4.0.0" - flutter: ">=3.3.10" + sdk: ">=3.0.6 <4.0.0" + flutter: ">=3.10.6" dependencies: flutter: sdk: flutter - parse_server_sdk: ^5.1.3 + parse_server_sdk: ^6.4.0 # Uncomment for local testing #parse_server_sdk: # path: ../dart # Networking - connectivity_plus: ^3.0.6 + connectivity_plus: ^5.0.2 #Database - shared_preferences: ^2.1.2 - sembast: ^3.4.6+1 - sembast_web: ^2.1.3 + shared_preferences: ^2.2.2 + sembast: ^3.6.0 + sembast_web: ^2.2.0 # Utils - path_provider: ^2.0.15 - package_info_plus: ^4.0.2 - path: ^1.8.2 + path_provider: ^2.1.2 + package_info_plus: ^4.2.0 + path: ^1.8.3 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.1 - path_provider_platform_interface: ^2.0.6 - plugin_platform_interface: ^2.1.4 + flutter_lints: ^3.0.1 + path_provider_platform_interface: ^2.1.2 + plugin_platform_interface: ^2.1.8 screenshots: - description: Parse Platform logo.