From e5c0850fe1c2333f2fd69568b3868cceed9e7faf Mon Sep 17 00:00:00 2001 From: maaeps Date: Fri, 28 Aug 2020 14:58:42 +0200 Subject: [PATCH 01/11] Set TODO's Set TODO's, needed for https://github.com/parse-community/Parse-SDK-Flutter/issues/78#issuecomment-682154173 --- lib/parse_server_sdk.dart | 8 ++++---- lib/src/network/parse_live_query.dart | 5 +++-- lib/src/network/parse_live_query_web.dart | 4 ++-- lib/src/utils/parse_live_list.dart | 2 +- pubspec.yaml | 11 ++++++----- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index 606fd131c..776494681 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -7,16 +7,16 @@ import 'dart:math'; import 'dart:typed_data'; import 'dart:ui' as ui; -import 'package:devicelocale/devicelocale.dart'; +import 'package:devicelocale/devicelocale.dart'; // TODO(maaeps): 'remove' from dart part import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:meta/meta.dart'; -import 'package:package_info/package_info.dart'; +import 'package:package_info/package_info.dart'; // TODO(maaeps): 'remove' from dart part import 'package:path/path.dart' as path; -import 'package:path_provider/path_provider.dart'; +import 'package:path_provider/path_provider.dart'; // TODO(maaeps): 'remove' from dart part import 'package:sembast/sembast.dart'; import 'package:sembast/sembast_io.dart'; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:shared_preferences/shared_preferences.dart'; // TODO(maaeps): 'remove' from dart part import 'package:uuid/uuid.dart'; import 'package:xxtea/xxtea.dart'; diff --git a/lib/src/network/parse_live_query.dart b/lib/src/network/parse_live_query.dart index ca90110c0..c85de925e 100644 --- a/lib/src/network/parse_live_query.dart +++ b/lib/src/network/parse_live_query.dart @@ -1,9 +1,10 @@ +// TODO(maaeps): Combine both liveQuery versions import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:connectivity/connectivity.dart'; -import 'package:flutter/widgets.dart'; +import 'package:connectivity/connectivity.dart'; // TODO(maaeps): 'remove' from dart part +import 'package:flutter/widgets.dart'; // TODO(maaeps): 'remove' from dart part import 'package:web_socket_channel/io.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; diff --git a/lib/src/network/parse_live_query_web.dart b/lib/src/network/parse_live_query_web.dart index 6d9012785..58f62e850 100644 --- a/lib/src/network/parse_live_query_web.dart +++ b/lib/src/network/parse_live_query_web.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'dart:html' as html; -import 'package:connectivity/connectivity.dart'; -import 'package:flutter/widgets.dart'; +import 'package:connectivity/connectivity.dart'; // TODO(maaeps): 'remove' from dart part +import 'package:flutter/widgets.dart'; // TODO(maaeps): 'remove' from dart part import '../../parse_server_sdk.dart'; diff --git a/lib/src/utils/parse_live_list.dart b/lib/src/utils/parse_live_list.dart index 0528e676d..0dd6d1197 100644 --- a/lib/src/utils/parse_live_list.dart +++ b/lib/src/utils/parse_live_list.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; // TODO(maaeps): 'remove' from dart part import '../../parse_server_sdk.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index ed3c92eac..6e9e51892 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,18 +13,19 @@ dependencies: # Networking web_socket_channel: ^1.1.0 - connectivity: ^0.4.9+2 + connectivity: ^0.4.9+2 # TODO(maaeps): 'remove' from dart part #Database sembast: ^2.4.7+6 xxtea: ^2.0.3 - shared_preferences: ^0.5.10 + shared_preferences: ^0.5.10 # TODO(maaeps): 'remove' from dart part # Utils - path_provider: ^1.6.14 + path_provider: ^1.6.14 # TODO(maaeps): 'remove' from dart part uuid: ^2.2.2 - package_info: ^0.4.3 - devicelocale: ^0.3.1 + package_info: ^0.4.3 # TODO(maaeps): 'remove' from dart part + devicelocale: ^0.3.1 # TODO(maaeps): 'remove' from dart part + # TODO(maaeps): remplace with flutter_device_locale? (Web support) meta: ^1.1.8 path: ^1.7.0 From 5f95300c99b14100295c5785a1c4831d08f8ff5f Mon Sep 17 00:00:00 2001 From: maaeps Date: Tue, 1 Sep 2020 12:41:59 +0200 Subject: [PATCH 02/11] First step of seperating the flutter and the dart parts --- lib/parse_server_sdk.dart | 169 +++++----------------- lib/parse_server_sdk_dart.dart | 159 ++++++++++++++++++++ lib/src/data/parse_core_data.dart | 10 ++ lib/src/objects/parse_installation.dart | 14 +- lib/src/utils/parse_live_list.dart | 10 +- pubspec.yaml | 2 +- test/parse_client_configuration_test.dart | 6 +- test/parse_query_test.dart | 6 +- 8 files changed, 227 insertions(+), 149 deletions(-) create mode 100644 lib/parse_server_sdk_dart.dart diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index b4df49e9d..0b3bc90e1 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -1,156 +1,65 @@ -library flutter_parse_sdk; - -import 'dart:async'; -import 'dart:convert'; import 'dart:io'; -import 'dart:math'; -import 'dart:typed_data'; -import 'dart:ui' as ui; - -import 'package:connectivity/connectivity.dart'; // TODO(maaeps): 'remove' from dart part -import 'package:flutter/widgets.dart'; -import 'package:http/http.dart'; -import 'package:http/io_client.dart'; -import 'package:meta/meta.dart'; -import 'package:package_info/package_info.dart'; // TODO(maaeps): 'remove' from dart part -import 'package:parse_server_sdk/src/network/parse_websocket.dart' - as parse_web_socket; -import 'package:path/path.dart' as path; -import 'package:path_provider/path_provider.dart'; // TODO(maaeps): 'remove' from dart part -import 'package:sembast/sembast.dart'; -import 'package:sembast/sembast_io.dart'; -import 'package:shared_preferences/shared_preferences.dart'; // TODO(maaeps): 'remove' from dart part -import 'package:uuid/uuid.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; -import 'package:xxtea/xxtea.dart'; -export 'src/utils/parse_live_list.dart'; +import 'package:package_info/package_info.dart'; -part 'package:parse_server_sdk/src/data/core_store.dart'; -part 'package:parse_server_sdk/src/data/parse_subclass_handler.dart'; -part 'package:parse_server_sdk/src/objects/response/parse_error_response.dart'; -part 'package:parse_server_sdk/src/objects/response/parse_exception_response.dart'; -part 'package:parse_server_sdk/src/objects/response/parse_response_builder.dart'; -part 'package:parse_server_sdk/src/objects/response/parse_response_utils.dart'; -part 'package:parse_server_sdk/src/objects/response/parse_success_no_results.dart'; -part 'package:parse_server_sdk/src/storage/core_store_sem_impl.dart'; -part 'package:parse_server_sdk/src/storage/core_store_sp_impl.dart'; -part 'package:parse_server_sdk/src/storage/xxtea_codec.dart'; -part 'src/base/parse_constants.dart'; -part 'src/data/parse_core_data.dart'; -part 'src/enums/parse_enum_api_rq.dart'; -part 'src/network/parse_http_client.dart'; -part 'src/network/parse_live_query.dart'; -part 'src/network/parse_query.dart'; -part 'src/objects/parse_acl.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_file.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_merge.dart'; -part 'src/objects/parse_object.dart'; -part 'src/objects/parse_relation.dart'; -part 'src/objects/parse_response.dart'; -part 'src/objects/parse_session.dart'; -part 'src/objects/parse_user.dart'; -part 'src/utils/parse_date_format.dart'; -part 'src/utils/parse_decoder.dart'; -part 'src/utils/parse_encoder.dart'; -part 'src/utils/parse_file_extensions.dart'; -part 'src/utils/parse_logger.dart'; -part 'src/utils/parse_login_helpers.dart'; -part 'src/utils/parse_utils.dart'; +import 'parse_server_sdk_dart.dart' as sdk; -class Parse { - ParseCoreData data; - bool _hasBeenInitialized = false; +export 'parse_server_sdk_dart.dart' hide Parse; +class Parse extends sdk.Parse { /// To initialize Parse Server in your application /// /// This should be initialized in MyApp() creation /// /// ``` /// Parse().initialize( - // "PARSE_APP_ID", - // "https://parse.myaddress.com/parse/, - // masterKey: "asd23rjh234r234r234r", - // debug: true, - // liveQuery: true); - // ``` + /// "PARSE_APP_ID", + /// "https://parse.myaddress.com/parse/, + /// masterKey: "asd23rjh234r234r234r", + /// debug: true, + /// liveQuery: true); + /// ``` + /// [appName], [appVersion] and [appPackageName] are automatically set on Android and IOS, if they are not defined. You should provide a value on web. + @override Future initialize( String appId, String serverUrl, { bool debug = false, - String appName = '', + String appName, + String appVersion, + String appPackageName, String liveQueryUrl, String clientKey, String masterKey, String sessionId, bool autoSendSessionId, SecurityContext securityContext, - CoreStore coreStore, - Map registeredSubClassMap, - ParseUserConstructor parseUserConstructor, - ParseFileConstructor parseFileConstructor, + sdk.CoreStore coreStore, + Map registeredSubClassMap, + sdk.ParseUserConstructor parseUserConstructor, + sdk.ParseFileConstructor parseFileConstructor, List liveListRetryIntervals, }) async { - final String url = removeTrailingSlash(serverUrl); - - await ParseCoreData.init( - appId, - url, - debug: debug, - appName: appName, - liveQueryUrl: liveQueryUrl, - masterKey: masterKey, - clientKey: clientKey, - sessionId: sessionId, - autoSendSessionId: autoSendSessionId, - securityContext: securityContext, - store: coreStore, - registeredSubClassMap: registeredSubClassMap, - parseUserConstructor: parseUserConstructor, - parseFileConstructor: parseFileConstructor, - liveListRetryIntervals: liveListRetryIntervals, - ); - - _hasBeenInitialized = true; - - return this; - } - - bool hasParseBeenInitialized() => _hasBeenInitialized; - - Future healthCheck( - {bool debug, ParseHTTPClient client, bool sendSessionIdByDefault}) async { - ParseResponse parseResponse; - - final bool _debug = isDebugEnabled(objectLevelDebug: debug); - - final ParseHTTPClient _client = client ?? - ParseHTTPClient( - sendSessionId: - sendSessionIdByDefault ?? ParseCoreData().autoSendSessionId, - securityContext: ParseCoreData().securityContext); - - const String className = 'parseBase'; - const ParseApiRQ type = ParseApiRQ.healthCheck; - - try { - final Response response = - await _client.get('${ParseCoreData().serverUrl}$keyEndPointHealth'); - parseResponse = - handleResponse(null, response, type, _debug, className); - } on Exception catch (e) { - parseResponse = handleException(e, type, _debug, className); + if (!sdk.parseIsWeb) { + final PackageInfo packageInfo = await PackageInfo.fromPlatform(); + appName ??= packageInfo.appName; + appVersion ??= packageInfo.version; + appPackageName ??= packageInfo.packageName; } - - return parseResponse; + return await super.initialize(appId, serverUrl, + debug: debug, + appName: appName, + appVersion: appVersion, + appPackageName: appPackageName, + liveQueryUrl: liveQueryUrl, + clientKey: clientKey, + masterKey: masterKey, + sessionId: sessionId, + autoSendSessionId: autoSendSessionId, + securityContext: securityContext, + coreStore: coreStore, + registeredSubClassMap: registeredSubClassMap, + parseUserConstructor: parseUserConstructor, + parseFileConstructor: parseFileConstructor); } } diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart new file mode 100644 index 000000000..efaa6c782 --- /dev/null +++ b/lib/parse_server_sdk_dart.dart @@ -0,0 +1,159 @@ +library flutter_parse_sdk; + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:connectivity/connectivity.dart'; // TODO(maaeps): 'remove' from dart part +import 'package:flutter/widgets.dart'; +import 'package:http/http.dart'; +import 'package:http/io_client.dart'; +import 'package:meta/meta.dart'; +import 'package:parse_server_sdk/src/network/parse_websocket.dart' + as parse_web_socket; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; // TODO(maaeps): 'remove' from dart part +import 'package:sembast/sembast.dart'; +import 'package:sembast/sembast_io.dart'; +import 'package:shared_preferences/shared_preferences.dart'; // TODO(maaeps): 'remove' from dart part +import 'package:uuid/uuid.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:xxtea/xxtea.dart'; + +export 'src/utils/parse_live_list.dart'; + +part 'package:parse_server_sdk/src/data/core_store.dart'; +part 'package:parse_server_sdk/src/data/parse_subclass_handler.dart'; +part 'package:parse_server_sdk/src/objects/response/parse_error_response.dart'; +part 'package:parse_server_sdk/src/objects/response/parse_exception_response.dart'; +part 'package:parse_server_sdk/src/objects/response/parse_response_builder.dart'; +part 'package:parse_server_sdk/src/objects/response/parse_response_utils.dart'; +part 'package:parse_server_sdk/src/objects/response/parse_success_no_results.dart'; +part 'package:parse_server_sdk/src/storage/core_store_sem_impl.dart'; +part 'package:parse_server_sdk/src/storage/core_store_sp_impl.dart'; +part 'package:parse_server_sdk/src/storage/xxtea_codec.dart'; +part 'src/base/parse_constants.dart'; +part 'src/data/parse_core_data.dart'; +part 'src/enums/parse_enum_api_rq.dart'; +part 'src/network/parse_http_client.dart'; +part 'src/network/parse_live_query.dart'; +part 'src/network/parse_query.dart'; +part 'src/objects/parse_acl.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_file.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_merge.dart'; +part 'src/objects/parse_object.dart'; +part 'src/objects/parse_relation.dart'; +part 'src/objects/parse_response.dart'; +part 'src/objects/parse_session.dart'; +part 'src/objects/parse_user.dart'; +part 'src/utils/parse_date_format.dart'; +part 'src/utils/parse_decoder.dart'; +part 'src/utils/parse_encoder.dart'; +part 'src/utils/parse_file_extensions.dart'; +part 'src/utils/parse_logger.dart'; +part 'src/utils/parse_login_helpers.dart'; +part 'src/utils/parse_utils.dart'; + +class Parse { + ParseCoreData data; + bool _hasBeenInitialized = false; + + /// To initialize Parse Server in your application + /// + /// This should be initialized in MyApp() creation + /// + /// ``` + /// Parse().initialize( + /// "PARSE_APP_ID", + /// "https://parse.myaddress.com/parse/, + /// masterKey: "asd23rjh234r234r234r", + /// debug: true, + /// liveQuery: true); + /// ``` + Future initialize( + String appId, + String serverUrl, { + bool debug = false, + String appName, + String appVersion, + String appPackageName, + String liveQueryUrl, + String clientKey, + String masterKey, + String sessionId, + bool autoSendSessionId, + SecurityContext securityContext, + CoreStore coreStore, + Map registeredSubClassMap, + ParseUserConstructor parseUserConstructor, + ParseFileConstructor parseFileConstructor, + List liveListRetryIntervals, + }) async { + final String url = removeTrailingSlash(serverUrl); + + await ParseCoreData.init( + appId, + url, + debug: debug, + appName: appName, + appVersion: appVersion, + appPackageName: appPackageName, + liveQueryUrl: liveQueryUrl, + masterKey: masterKey, + clientKey: clientKey, + sessionId: sessionId, + autoSendSessionId: autoSendSessionId, + securityContext: securityContext, + store: coreStore, + registeredSubClassMap: registeredSubClassMap, + parseUserConstructor: parseUserConstructor, + parseFileConstructor: parseFileConstructor, + liveListRetryIntervals: liveListRetryIntervals, + ); + + _hasBeenInitialized = true; + + return this; + } + + bool hasParseBeenInitialized() => _hasBeenInitialized; + + Future healthCheck( + {bool debug, ParseHTTPClient client, bool sendSessionIdByDefault}) async { + ParseResponse parseResponse; + + final bool _debug = isDebugEnabled(objectLevelDebug: debug); + + final ParseHTTPClient _client = client ?? + ParseHTTPClient( + sendSessionId: + sendSessionIdByDefault ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); + + const String className = 'parseBase'; + const ParseApiRQ type = ParseApiRQ.healthCheck; + + try { + final Response response = + await _client.get('${ParseCoreData().serverUrl}$keyEndPointHealth'); + parseResponse = + handleResponse(null, response, type, _debug, className); + } on Exception catch (e) { + parseResponse = handleException(e, type, _debug, className); + } + + return parseResponse; + } +} diff --git a/lib/src/data/parse_core_data.dart b/lib/src/data/parse_core_data.dart index 02b37c2af..67a59a05d 100644 --- a/lib/src/data/parse_core_data.dart +++ b/lib/src/data/parse_core_data.dart @@ -19,6 +19,8 @@ class ParseCoreData { String serverUrl, { bool debug, String appName, + String appVersion, + String appPackageName, String liveQueryUrl, String masterKey, String clientKey, @@ -42,6 +44,12 @@ class ParseCoreData { if (appName != null) { _instance.appName = appName; } + if (appVersion != null) { + _instance.appVersion = appVersion; + } + if (appPackageName != null) { + _instance.appPackageName = appPackageName; + } if (liveQueryUrl != null) { _instance.liveQueryURL = liveQueryUrl; } @@ -76,6 +84,8 @@ class ParseCoreData { } String appName; + String appVersion; + String appPackageName; String applicationId; String serverUrl; String liveQueryURL; diff --git a/lib/src/objects/parse_installation.dart b/lib/src/objects/parse_installation.dart index ad44b3470..a54a3d7fa 100644 --- a/lib/src/objects/parse_installation.dart +++ b/lib/src/objects/parse_installation.dart @@ -83,9 +83,8 @@ class ParseInstallation extends ParseObject { } //Locale - final String locale = parseIsWeb - ? ui.window.locale.toString() - : Platform.localeName; + final String locale = + parseIsWeb ? ui.window.locale.toString() : Platform.localeName; if (locale != null && locale.isNotEmpty) { set(keyLocaleIdentifier, locale); } @@ -93,12 +92,9 @@ class ParseInstallation extends ParseObject { //Timezone //App info - if (!parseIsWeb) { - final PackageInfo packageInfo = await PackageInfo.fromPlatform(); - set(keyAppName, packageInfo.appName); - set(keyAppVersion, packageInfo.version); - set(keyAppIdentifier, packageInfo.packageName); - } + set(keyAppName, ParseCoreData().appName); + set(keyAppVersion, ParseCoreData().appVersion); + set(keyAppIdentifier, ParseCoreData().appPackageName); set(keyParseVersion, keySdkVersion); } diff --git a/lib/src/utils/parse_live_list.dart b/lib/src/utils/parse_live_list.dart index 0dd6d1197..a123e478e 100644 --- a/lib/src/utils/parse_live_list.dart +++ b/lib/src/utils/parse_live_list.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; // TODO(maaeps): 'remove' from dart part -import '../../parse_server_sdk.dart'; +import '../../parse_server_sdk_dart.dart'; // ignore_for_file: invalid_use_of_protected_member class ParseLiveList { @@ -335,8 +335,8 @@ class ParseLiveList { includeList.add(key); // ignore: avoid_as if ((includes[key] as Map).isNotEmpty) { - includeList - .addAll(_toIncludeStringList(includes[key]).map((String e) => '$key.$e')); + includeList.addAll( + _toIncludeStringList(includes[key]).map((String e) => '$key.$e')); } } return includeList; @@ -678,8 +678,8 @@ class ParseLiveListElement { ..keysToReturn([keyVarUpdatedAt]) ..whereEqualTo(keyVarObjectId, subObject.objectId); final ParseResponse parseResponse = await queryBuilder.query(); - if (parseResponse.success && parseResponse.results.first.updatedAt != - subObject.updatedAt) { + if (parseResponse.success && + parseResponse.results.first.updatedAt != subObject.updatedAt) { queryBuilder.limiters.remove('keys'); queryBuilder.includeObject(_getIncludeList(path[key])); final ParseResponse parseResponse = await queryBuilder.query(); diff --git a/pubspec.yaml b/pubspec.yaml index 0befeb641..13ad67963 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: # Utils path_provider: ^1.6.14 # TODO(maaeps): 'remove' from dart part uuid: ^2.2.2 - package_info: ^0.4.3 # TODO(maaeps): 'remove' from dart part + package_info: ^0.4.3 # only used in the flutter part meta: ^1.1.8 path: ^1.7.0 diff --git a/test/parse_client_configuration_test.dart b/test/parse_client_configuration_test.dart index 94c8b1e8c..e5a64173f 100644 --- a/test/parse_client_configuration_test.dart +++ b/test/parse_client_configuration_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:parse_server_sdk/parse_server_sdk.dart'; +import 'package:parse_server_sdk/parse_server_sdk_dart.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { @@ -10,6 +10,8 @@ void main() { clientKey: 'clientKey', liveQueryUrl: 'liveQueryUrl', appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', masterKey: 'masterKey', sessionId: 'sessionId', debug: true); @@ -19,6 +21,8 @@ void main() { expect(ParseCoreData().clientKey, 'clientKey'); expect(ParseCoreData().liveQueryURL, 'liveQueryUrl'); expect(ParseCoreData().appName, 'appName'); + expect(ParseCoreData().appPackageName, 'somePackageName'); + expect(ParseCoreData().appVersion, 'someAppVersion'); expect(ParseCoreData().masterKey, 'masterKey'); expect(ParseCoreData().sessionId, 'sessionId'); expect(ParseCoreData().debug, true); diff --git a/test/parse_query_test.dart b/test/parse_query_test.dart index 7506f095f..67cabf0b9 100644 --- a/test/parse_query_test.dart +++ b/test/parse_query_test.dart @@ -1,6 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:parse_server_sdk/parse_server_sdk.dart'; +import 'package:parse_server_sdk/parse_server_sdk_dart.dart'; import 'package:shared_preferences/shared_preferences.dart'; class MockClient extends Mock implements ParseHTTPClient {} @@ -15,7 +15,7 @@ void main() { await Parse().initialize('appId', 'https://test.parse.com', debug: true); final QueryBuilder queryBuilder = - QueryBuilder(ParseObject('_User', client: client)); + QueryBuilder(ParseObject('_User', client: client)); queryBuilder.whereRelatedTo('likes', 'Post', '8TOXdXf3tz'); when(client.data).thenReturn(ParseCoreData()); @@ -27,7 +27,7 @@ void main() { final Uri expectedQuery = Uri( query: - 'where={"\$relatedTo":{"object":{"__type":"Pointer","className":"Post","objectId":"8TOXdXf3tz"},"key":"likes"}}'); + 'where={"\$relatedTo":{"object":{"__type":"Pointer","className":"Post","objectId":"8TOXdXf3tz"},"key":"likes"}}'); expect(result.query, expectedQuery.query); }); }); From 90b566ea6097077d2def770ac8f8beabc7541051 Mon Sep 17 00:00:00 2001 From: maaeps Date: Tue, 1 Sep 2020 12:54:52 +0200 Subject: [PATCH 03/11] added one todo --- lib/parse_server_sdk_dart.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart index efaa6c782..ede543a10 100644 --- a/lib/parse_server_sdk_dart.dart +++ b/lib/parse_server_sdk_dart.dart @@ -8,7 +8,7 @@ import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:connectivity/connectivity.dart'; // TODO(maaeps): 'remove' from dart part -import 'package:flutter/widgets.dart'; +import 'package:flutter/widgets.dart'; // TODO(maaeps): 'remove' from dart part import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:meta/meta.dart'; From 447a55299837e0cb325bb00b30ac073d6032b0c0 Mon Sep 17 00:00:00 2001 From: maaeps Date: Tue, 1 Sep 2020 13:37:57 +0200 Subject: [PATCH 04/11] remove connectivity from the dart part --- lib/parse_server_sdk.dart | 69 +++++++++++++++++++------ lib/parse_server_sdk_dart.dart | 4 +- lib/src/data/parse_core_data.dart | 5 ++ lib/src/network/parse_connectivity.dart | 18 +++++++ lib/src/network/parse_live_query.dart | 18 ++++--- pubspec.yaml | 2 +- 6 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 lib/src/network/parse_connectivity.dart diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index 0b3bc90e1..6ea118a35 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -1,12 +1,13 @@ import 'dart:io'; +import 'package:connectivity/connectivity.dart'; import 'package:package_info/package_info.dart'; import 'parse_server_sdk_dart.dart' as sdk; export 'parse_server_sdk_dart.dart' hide Parse; -class Parse extends sdk.Parse { +class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { /// To initialize Parse Server in your application /// /// This should be initialized in MyApp() creation @@ -39,6 +40,7 @@ class Parse extends sdk.Parse { sdk.ParseUserConstructor parseUserConstructor, sdk.ParseFileConstructor parseFileConstructor, List liveListRetryIntervals, + sdk.ParseConnectivityProvider connectivityProvider, }) async { if (!sdk.parseIsWeb) { final PackageInfo packageInfo = await PackageInfo.fromPlatform(); @@ -46,20 +48,55 @@ class Parse extends sdk.Parse { appVersion ??= packageInfo.version; appPackageName ??= packageInfo.packageName; } - return await super.initialize(appId, serverUrl, - debug: debug, - appName: appName, - appVersion: appVersion, - appPackageName: appPackageName, - liveQueryUrl: liveQueryUrl, - clientKey: clientKey, - masterKey: masterKey, - sessionId: sessionId, - autoSendSessionId: autoSendSessionId, - securityContext: securityContext, - coreStore: coreStore, - registeredSubClassMap: registeredSubClassMap, - parseUserConstructor: parseUserConstructor, - parseFileConstructor: parseFileConstructor); + + return await super.initialize( + appId, + serverUrl, + debug: debug, + appName: appName, + appVersion: appVersion, + appPackageName: appPackageName, + liveQueryUrl: liveQueryUrl, + clientKey: clientKey, + masterKey: masterKey, + sessionId: sessionId, + autoSendSessionId: autoSendSessionId, + securityContext: securityContext, + coreStore: coreStore, + registeredSubClassMap: registeredSubClassMap, + parseUserConstructor: parseUserConstructor, + parseFileConstructor: parseFileConstructor, + connectivityProvider: connectivityProvider ?? this, + ); + } + + @override + Future checkConnectivity() async { + //Connectivity works differently on web + if (!sdk.parseIsWeb) { + switch (await Connectivity().checkConnectivity()) { + case ConnectivityResult.wifi: + return sdk.ParseConnectivityResult.wifi; + case ConnectivityResult.mobile: + return sdk.ParseConnectivityResult.mobile; + case ConnectivityResult.none: + return sdk.ParseConnectivityResult.none; + } + } + return sdk.ParseConnectivityResult.wifi; + } + + @override + Stream get connectivityStream { + return Connectivity().onConnectivityChanged.map((ConnectivityResult event) { + switch (event) { + case ConnectivityResult.wifi: + return sdk.ParseConnectivityResult.wifi; + case ConnectivityResult.mobile: + return sdk.ParseConnectivityResult.mobile; + default: + return sdk.ParseConnectivityResult.none; + } + }); } } diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart index ede543a10..30060777b 100644 --- a/lib/parse_server_sdk_dart.dart +++ b/lib/parse_server_sdk_dart.dart @@ -7,7 +7,6 @@ import 'dart:math'; import 'dart:typed_data'; import 'dart:ui' as ui; -import 'package:connectivity/connectivity.dart'; // TODO(maaeps): 'remove' from dart part import 'package:flutter/widgets.dart'; // TODO(maaeps): 'remove' from dart part import 'package:http/http.dart'; import 'package:http/io_client.dart'; @@ -38,6 +37,7 @@ part 'package:parse_server_sdk/src/storage/xxtea_codec.dart'; part 'src/base/parse_constants.dart'; part 'src/data/parse_core_data.dart'; part 'src/enums/parse_enum_api_rq.dart'; +part 'src/network/parse_connectivity.dart'; part 'src/network/parse_http_client.dart'; part 'src/network/parse_live_query.dart'; part 'src/network/parse_query.dart'; @@ -100,6 +100,7 @@ class Parse { ParseUserConstructor parseUserConstructor, ParseFileConstructor parseFileConstructor, List liveListRetryIntervals, + ParseConnectivityProvider connectivityProvider, }) async { final String url = removeTrailingSlash(serverUrl); @@ -121,6 +122,7 @@ class Parse { parseUserConstructor: parseUserConstructor, parseFileConstructor: parseFileConstructor, liveListRetryIntervals: liveListRetryIntervals, + connectivityProvider: connectivityProvider, ); _hasBeenInitialized = true; diff --git a/lib/src/data/parse_core_data.dart b/lib/src/data/parse_core_data.dart index 67a59a05d..14dc01343 100644 --- a/lib/src/data/parse_core_data.dart +++ b/lib/src/data/parse_core_data.dart @@ -32,6 +32,7 @@ class ParseCoreData { ParseUserConstructor parseUserConstructor, ParseFileConstructor parseFileConstructor, List liveListRetryIntervals, + ParseConnectivityProvider connectivityProvider, }) async { _instance = ParseCoreData._init(appId, serverUrl); @@ -81,6 +82,9 @@ class ParseCoreData { parseUserConstructor: parseUserConstructor, parseFileConstructor: parseFileConstructor, ); + if (connectivityProvider != null) { + _instance.connectivityProvider = connectivityProvider; + } } String appName; @@ -98,6 +102,7 @@ class ParseCoreData { CoreStore storage; ParseSubClassHandler _subClassHandler; List liveListRetryIntervals; + ParseConnectivityProvider connectivityProvider; void registerSubClass( String className, ParseObjectConstructor objectConstructor) { diff --git a/lib/src/network/parse_connectivity.dart b/lib/src/network/parse_connectivity.dart new file mode 100644 index 000000000..731ad1a4b --- /dev/null +++ b/lib/src/network/parse_connectivity.dart @@ -0,0 +1,18 @@ +part of flutter_parse_sdk; + +/// Connection status check result. +enum ParseConnectivityResult { + /// WiFi: Device connected via Wi-Fi + wifi, + + /// Mobile: Device connected to cellular network + mobile, + + /// None: Device not connected to any network + none +} + +abstract class ParseConnectivityProvider { + Future checkConnectivity(); + Stream get connectivityStream; +} diff --git a/lib/src/network/parse_live_query.dart b/lib/src/network/parse_live_query.dart index 05e6be9a4..864049062 100644 --- a/lib/src/network/parse_live_query.dart +++ b/lib/src/network/parse_live_query.dart @@ -36,12 +36,14 @@ enum LiveQueryClientEvent { CONNECTED, DISCONNECTED, USER_DISCONNECTED } class LiveQueryReconnectingController with WidgetsBindingObserver { LiveQueryReconnectingController( this._reconnect, this._eventStream, this.debug) { - //Connectivity works differently on web - if (!parseIsWeb) { - Connectivity().checkConnectivity().then(_connectivityChanged); - Connectivity().onConnectivityChanged.listen(_connectivityChanged); + final ParseConnectivityProvider connectivityProvider = + ParseCoreData().connectivityProvider; + if (connectivityProvider != null) { + connectivityProvider.checkConnectivity().then(_connectivityChanged); + connectivityProvider.connectivityStream.listen(_connectivityChanged); } else { - _connectivityChanged(ConnectivityResult.wifi); + print( + 'LiveQuery does not work, if there is ParseConnectivityProvider provided.'); } _eventStream.listen((LiveQueryClientEvent event) { switch (event) { @@ -84,11 +86,11 @@ class LiveQueryReconnectingController with WidgetsBindingObserver { Timer _currentTimer; - void _connectivityChanged(ConnectivityResult state) { - if (!_isOnline && state != ConnectivityResult.none) { + void _connectivityChanged(ParseConnectivityResult state) { + if (!_isOnline && state != ParseConnectivityResult.none) { _retryState = 0; } - _isOnline = state != ConnectivityResult.none; + _isOnline = state != ParseConnectivityResult.none; if (debug) { print('$DEBUG_TAG: $state'); } diff --git a/pubspec.yaml b/pubspec.yaml index 13ad67963..58a607a48 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: # Networking web_socket_channel: ^1.1.0 - connectivity: ^0.4.9+2 # TODO(maaeps): 'remove' from dart part + connectivity: ^0.4.9+2 # only used in the flutter part #Database sembast: ^2.4.7+6 From 7c001c1c6d27bc920b828413a4c630d25ff506a5 Mon Sep 17 00:00:00 2001 From: maaeps Date: Thu, 3 Sep 2020 19:52:52 +0200 Subject: [PATCH 05/11] Removed path_provider from the dart part Not so happy with the fact that `CoreStoreSembastImp implements sdk.CoreStoreSembastImp` in `parse_server_sdk.dart` but I didn't find a better solution. --- example/pubspec.yaml | 2 + lib/parse_server_sdk.dart | 75 +++++++++++++++++++++++- lib/parse_server_sdk_dart.dart | 3 +- lib/src/data/parse_core_data.dart | 6 ++ lib/src/objects/parse_file.dart | 7 +-- lib/src/storage/core_store_sem_impl.dart | 7 +-- pubspec.yaml | 2 +- 7 files changed, 88 insertions(+), 14 deletions(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 620f1db5f..889345e65 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,6 +11,8 @@ dependencies: sembast: ^2.0.1 shared_preferences: ^0.5.0 + path_provider: ^1.6.14 + dev_dependencies: parse_server_sdk: path: ../ diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index 6ea118a35..6dccea390 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -2,10 +2,13 @@ import 'dart:io'; import 'package:connectivity/connectivity.dart'; import 'package:package_info/package_info.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; +import 'package:sembast/sembast.dart'; import 'parse_server_sdk_dart.dart' as sdk; -export 'parse_server_sdk_dart.dart' hide Parse; +export 'parse_server_sdk_dart.dart' hide Parse, CoreStoreSembastImp; class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { /// To initialize Parse Server in your application @@ -21,6 +24,7 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { /// liveQuery: true); /// ``` /// [appName], [appVersion] and [appPackageName] are automatically set on Android and IOS, if they are not defined. You should provide a value on web. + /// [fileDirectory] is not used on web @override Future initialize( String appId, @@ -41,6 +45,7 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { sdk.ParseFileConstructor parseFileConstructor, List liveListRetryIntervals, sdk.ParseConnectivityProvider connectivityProvider, + String fileDirectory, }) async { if (!sdk.parseIsWeb) { final PackageInfo packageInfo = await PackageInfo.fromPlatform(); @@ -67,6 +72,7 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { parseUserConstructor: parseUserConstructor, parseFileConstructor: parseFileConstructor, connectivityProvider: connectivityProvider ?? this, + fileDirectory: fileDirectory ?? (await getTemporaryDirectory()).path, ); } @@ -100,3 +106,70 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { }); } } + +class CoreStoreSembastImp implements sdk.CoreStoreSembastImp { + CoreStoreSembastImp._(); + + static sdk.CoreStoreSembastImp _sembastImp; + + static Future getInstance(String dbPath, + {DatabaseFactory factory, String password}) async { + if (_sembastImp == null) { + String dbDirectory = ''; + if (!sdk.parseIsWeb && + (Platform.isIOS || Platform.isAndroid || Platform.isMacOS)) + dbDirectory = (await getApplicationDocumentsDirectory()).path; + final String dbPath = path.join('$dbDirectory/parse', 'parse.db'); + _sembastImp ??= await sdk.CoreStoreSembastImp.getInstance(dbPath, + factory: factory, password: password); + } + return CoreStoreSembastImp._(); + } + + @override + Future clear() => _sembastImp.clear(); + + @override + Future containsKey(String key) => _sembastImp.containsKey(key); + + @override + Future get(String key) => _sembastImp.get(key); + + @override + Future getBool(String key) => _sembastImp.getBool(key); + + @override + Future getDouble(String key) => _sembastImp.getDouble(key); + + @override + Future getInt(String key) => _sembastImp.getInt(key); + + @override + Future getString(String key) => _sembastImp.getString(key); + + @override + Future> getStringList(String key) => + _sembastImp.getStringList(key); + + @override + Future remove(String key) => _sembastImp.remove(key); + + @override + Future setBool(String key, bool value) => + _sembastImp.setBool(key, value); + + @override + Future setDouble(String key, double value) => + _sembastImp.setDouble(key, value); + + @override + Future setInt(String key, int value) => _sembastImp.setInt(key, value); + + @override + Future setString(String key, String value) => + _sembastImp.setString(key, value); + + @override + Future setStringList(String key, List values) => + _sembastImp.setStringList(key, values); +} diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart index 30060777b..85d7d555b 100644 --- a/lib/parse_server_sdk_dart.dart +++ b/lib/parse_server_sdk_dart.dart @@ -14,7 +14,6 @@ import 'package:meta/meta.dart'; import 'package:parse_server_sdk/src/network/parse_websocket.dart' as parse_web_socket; import 'package:path/path.dart' as path; -import 'package:path_provider/path_provider.dart'; // TODO(maaeps): 'remove' from dart part import 'package:sembast/sembast.dart'; import 'package:sembast/sembast_io.dart'; import 'package:shared_preferences/shared_preferences.dart'; // TODO(maaeps): 'remove' from dart part @@ -101,6 +100,7 @@ class Parse { ParseFileConstructor parseFileConstructor, List liveListRetryIntervals, ParseConnectivityProvider connectivityProvider, + String fileDirectory, }) async { final String url = removeTrailingSlash(serverUrl); @@ -123,6 +123,7 @@ class Parse { parseFileConstructor: parseFileConstructor, liveListRetryIntervals: liveListRetryIntervals, connectivityProvider: connectivityProvider, + fileDirectory: fileDirectory, ); _hasBeenInitialized = true; diff --git a/lib/src/data/parse_core_data.dart b/lib/src/data/parse_core_data.dart index 14dc01343..57f9a16a6 100644 --- a/lib/src/data/parse_core_data.dart +++ b/lib/src/data/parse_core_data.dart @@ -33,6 +33,7 @@ class ParseCoreData { ParseFileConstructor parseFileConstructor, List liveListRetryIntervals, ParseConnectivityProvider connectivityProvider, + String fileDirectory, }) async { _instance = ParseCoreData._init(appId, serverUrl); @@ -85,6 +86,10 @@ class ParseCoreData { if (connectivityProvider != null) { _instance.connectivityProvider = connectivityProvider; } + + if (fileDirectory != null) { + _instance.fileDirectory = fileDirectory; + } } String appName; @@ -103,6 +108,7 @@ class ParseCoreData { ParseSubClassHandler _subClassHandler; List liveListRetryIntervals; ParseConnectivityProvider connectivityProvider; + String fileDirectory; void registerSubClass( String className, ParseObjectConstructor objectConstructor) { diff --git a/lib/src/objects/parse_file.dart b/lib/src/objects/parse_file.dart index c44d63ab3..a149839df 100644 --- a/lib/src/objects/parse_file.dart +++ b/lib/src/objects/parse_file.dart @@ -21,14 +21,12 @@ class ParseFile extends ParseFileBase { File file; Future loadStorage() async { - final Directory tempPath = await getTemporaryDirectory(); - if (name == null) { file = null; return this; } - final File possibleFile = File('${tempPath.path}/$name'); + final File possibleFile = File('${ParseCoreData().fileDirectory}/$name'); // ignore: avoid_slow_async_io final bool exists = await possibleFile.exists(); @@ -47,8 +45,7 @@ class ParseFile extends ParseFileBase { return this; } - final Directory tempPath = await getTemporaryDirectory(); - file = File('${tempPath.path}/$name'); + file = File('${ParseCoreData().fileDirectory}/$name'); await file.create(); final Response response = await _client.get(url); await file.writeAsBytes(response.bodyBytes); diff --git a/lib/src/storage/core_store_sem_impl.dart b/lib/src/storage/core_store_sem_impl.dart index f8e2c317d..bf60602bd 100644 --- a/lib/src/storage/core_store_sem_impl.dart +++ b/lib/src/storage/core_store_sem_impl.dart @@ -6,16 +6,11 @@ class CoreStoreSembastImp implements CoreStore { static CoreStoreSembastImp _instance; - static Future getInstance( + static Future getInstance(String dbPath, {DatabaseFactory factory, String password = 'flutter_sdk'}) async { if (_instance == null) { factory ??= databaseFactoryIo; final SembastCodec codec = getXXTeaSembastCodec(password: password); - String dbDirectory = ''; - if (!parseIsWeb && - (Platform.isIOS || Platform.isAndroid || Platform.isMacOS)) - dbDirectory = (await getApplicationDocumentsDirectory()).path; - final String dbPath = path.join('$dbDirectory/parse', 'parse.db'); final Database db = await factory.openDatabase(dbPath, codec: codec); _instance = CoreStoreSembastImp._internal(db, StoreRef.main()); diff --git a/pubspec.yaml b/pubspec.yaml index 58a607a48..ed591865a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: shared_preferences: ^0.5.10 # TODO(maaeps): 'remove' from dart part # Utils - path_provider: ^1.6.14 # TODO(maaeps): 'remove' from dart part + path_provider: ^1.6.14 # only used in the flutter part uuid: ^2.2.2 package_info: ^0.4.3 # only used in the flutter part meta: ^1.1.8 From a1373dcc971ae254db4d2ec568ce3faf7251be0c Mon Sep 17 00:00:00 2001 From: maaeps Date: Thu, 3 Sep 2020 20:09:14 +0200 Subject: [PATCH 06/11] Removed shared_preferences from the dart part --- lib/parse_server_sdk.dart | 5 ++++- lib/parse_server_sdk_dart.dart | 2 -- lib/src/data/parse_core_data.dart | 6 ++++-- lib/src/storage/core_store_sp_impl.dart | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index 6dccea390..5ae45473b 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -7,8 +7,10 @@ import 'package:path_provider/path_provider.dart'; import 'package:sembast/sembast.dart'; import 'parse_server_sdk_dart.dart' as sdk; +import 'src/storage/core_store_sp_impl.dart'; export 'parse_server_sdk_dart.dart' hide Parse, CoreStoreSembastImp; +export 'src/storage/core_store_sp_impl.dart'; class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { /// To initialize Parse Server in your application @@ -67,7 +69,8 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { sessionId: sessionId, autoSendSessionId: autoSendSessionId, securityContext: securityContext, - coreStore: coreStore, + coreStore: coreStore ?? + await CoreStoreSharedPrefsImp.getInstance(password: masterKey), registeredSubClassMap: registeredSubClassMap, parseUserConstructor: parseUserConstructor, parseFileConstructor: parseFileConstructor, diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart index 85d7d555b..6444010db 100644 --- a/lib/parse_server_sdk_dart.dart +++ b/lib/parse_server_sdk_dart.dart @@ -16,7 +16,6 @@ import 'package:parse_server_sdk/src/network/parse_websocket.dart' import 'package:path/path.dart' as path; import 'package:sembast/sembast.dart'; import 'package:sembast/sembast_io.dart'; -import 'package:shared_preferences/shared_preferences.dart'; // TODO(maaeps): 'remove' from dart part import 'package:uuid/uuid.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:xxtea/xxtea.dart'; @@ -31,7 +30,6 @@ part 'package:parse_server_sdk/src/objects/response/parse_response_builder.dart' part 'package:parse_server_sdk/src/objects/response/parse_response_utils.dart'; part 'package:parse_server_sdk/src/objects/response/parse_success_no_results.dart'; part 'package:parse_server_sdk/src/storage/core_store_sem_impl.dart'; -part 'package:parse_server_sdk/src/storage/core_store_sp_impl.dart'; part 'package:parse_server_sdk/src/storage/xxtea_codec.dart'; part 'src/base/parse_constants.dart'; part 'src/data/parse_core_data.dart'; diff --git a/lib/src/data/parse_core_data.dart b/lib/src/data/parse_core_data.dart index 57f9a16a6..4ba75322f 100644 --- a/lib/src/data/parse_core_data.dart +++ b/lib/src/data/parse_core_data.dart @@ -37,8 +37,10 @@ class ParseCoreData { }) async { _instance = ParseCoreData._init(appId, serverUrl); - _instance.storage ??= - store ?? await CoreStoreSharedPrefsImp.getInstance(password: masterKey); + assert(_instance.storage != null || store != null, + 'There is no CoreStore set.'); + + _instance.storage ??= store; if (debug != null) { _instance.debug = debug; diff --git a/lib/src/storage/core_store_sp_impl.dart b/lib/src/storage/core_store_sp_impl.dart index c09e6970a..e41693c43 100644 --- a/lib/src/storage/core_store_sp_impl.dart +++ b/lib/src/storage/core_store_sp_impl.dart @@ -1,4 +1,5 @@ -part of flutter_parse_sdk; +import 'package:parse_server_sdk/parse_server_sdk_dart.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class CoreStoreSharedPrefsImp implements CoreStore { CoreStoreSharedPrefsImp._internal(this._store); From 13cda8c5996f7d7380d00e08b9177c9a8b34900d Mon Sep 17 00:00:00 2001 From: maaeps Date: Thu, 3 Sep 2020 20:09:50 +0200 Subject: [PATCH 07/11] Update pubspec.yaml --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index ed591865a..50a5bfed7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: #Database sembast: ^2.4.7+6 xxtea: ^2.0.3 - shared_preferences: ^0.5.10 # TODO(maaeps): 'remove' from dart part + shared_preferences: ^0.5.10 # only used in the flutter part # Utils path_provider: ^1.6.14 # only used in the flutter part From 5eea44c58df046b16786322b5c2c6ba06a61393c Mon Sep 17 00:00:00 2001 From: maaeps Date: Thu, 3 Sep 2020 21:06:51 +0200 Subject: [PATCH 08/11] Update parse_server_sdk_dart.dart --- lib/parse_server_sdk_dart.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart index 6444010db..cc792cd00 100644 --- a/lib/parse_server_sdk_dart.dart +++ b/lib/parse_server_sdk_dart.dart @@ -5,7 +5,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; -import 'dart:ui' as ui; +import 'dart:ui' as ui; // TODO(maaeps): 'remove' from dart part import 'package:flutter/widgets.dart'; // TODO(maaeps): 'remove' from dart part import 'package:http/http.dart'; From f454e6f021e93841c2ff408789aafca62fc81336 Mon Sep 17 00:00:00 2001 From: maaeps Date: Thu, 3 Sep 2020 21:59:20 +0200 Subject: [PATCH 09/11] removed dart:ui from dart part --- lib/parse_server_sdk.dart | 5 +++++ lib/parse_server_sdk_dart.dart | 3 ++- lib/src/data/parse_core_data.dart | 5 +++++ lib/src/objects/parse_installation.dart | 6 +----- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index 5ae45473b..8d35e96f3 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:ui' as ui; import 'package:connectivity/connectivity.dart'; import 'package:package_info/package_info.dart'; @@ -35,6 +36,7 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { String appName, String appVersion, String appPackageName, + String locale, String liveQueryUrl, String clientKey, String masterKey, @@ -63,6 +65,9 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { appName: appName, appVersion: appVersion, appPackageName: appPackageName, + locale: locale ?? sdk.parseIsWeb + ? ui.window.locale.toString() + : Platform.localeName, liveQueryUrl: liveQueryUrl, clientKey: clientKey, masterKey: masterKey, diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart index cc792cd00..4be7f2e39 100644 --- a/lib/parse_server_sdk_dart.dart +++ b/lib/parse_server_sdk_dart.dart @@ -5,7 +5,6 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; -import 'dart:ui' as ui; // TODO(maaeps): 'remove' from dart part import 'package:flutter/widgets.dart'; // TODO(maaeps): 'remove' from dart part import 'package:http/http.dart'; @@ -86,6 +85,7 @@ class Parse { String appName, String appVersion, String appPackageName, + String locale, String liveQueryUrl, String clientKey, String masterKey, @@ -109,6 +109,7 @@ class Parse { appName: appName, appVersion: appVersion, appPackageName: appPackageName, + locale: locale, liveQueryUrl: liveQueryUrl, masterKey: masterKey, clientKey: clientKey, diff --git a/lib/src/data/parse_core_data.dart b/lib/src/data/parse_core_data.dart index 4ba75322f..fb95dcdb9 100644 --- a/lib/src/data/parse_core_data.dart +++ b/lib/src/data/parse_core_data.dart @@ -21,6 +21,7 @@ class ParseCoreData { String appName, String appVersion, String appPackageName, + String locale, String liveQueryUrl, String masterKey, String clientKey, @@ -54,6 +55,9 @@ class ParseCoreData { if (appPackageName != null) { _instance.appPackageName = appPackageName; } + if (locale != null) { + _instance.locale = locale; + } if (liveQueryUrl != null) { _instance.liveQueryURL = liveQueryUrl; } @@ -98,6 +102,7 @@ class ParseCoreData { String appVersion; String appPackageName; String applicationId; + String locale; String serverUrl; String liveQueryURL; String masterKey; diff --git a/lib/src/objects/parse_installation.dart b/lib/src/objects/parse_installation.dart index a54a3d7fa..c30937742 100644 --- a/lib/src/objects/parse_installation.dart +++ b/lib/src/objects/parse_installation.dart @@ -83,11 +83,7 @@ class ParseInstallation extends ParseObject { } //Locale - final String locale = - parseIsWeb ? ui.window.locale.toString() : Platform.localeName; - if (locale != null && locale.isNotEmpty) { - set(keyLocaleIdentifier, locale); - } + set(keyLocaleIdentifier, ParseCoreData().locale); //Timezone From c544362ff3d3977d010ca3b356eede3465a94201 Mon Sep 17 00:00:00 2001 From: maaeps Date: Thu, 3 Sep 2020 22:41:22 +0200 Subject: [PATCH 10/11] removed flutter from dart part --- lib/parse_server_sdk.dart | 17 +- lib/parse_server_sdk_dart.dart | 6 +- lib/src/data/parse_core_data.dart | 6 + lib/src/network/parse_live_query.dart | 20 +- lib/src/utils/parse_live_list.dart | 245 +-------------------- lib/src/utils/parse_live_list_flutter.dart | 245 +++++++++++++++++++++ 6 files changed, 278 insertions(+), 261 deletions(-) create mode 100644 lib/src/utils/parse_live_list_flutter.dart diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index 8d35e96f3..deb29a3c1 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -1,7 +1,9 @@ +import 'dart:async'; import 'dart:io'; import 'dart:ui' as ui; import 'package:connectivity/connectivity.dart'; +import 'package:flutter/widgets.dart'; import 'package:package_info/package_info.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; @@ -12,8 +14,11 @@ import 'src/storage/core_store_sp_impl.dart'; export 'parse_server_sdk_dart.dart' hide Parse, CoreStoreSembastImp; export 'src/storage/core_store_sp_impl.dart'; +export 'src/utils/parse_live_list_flutter.dart'; -class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { +class Parse extends sdk.Parse + with WidgetsBindingObserver + implements sdk.ParseConnectivityProvider { /// To initialize Parse Server in your application /// /// This should be initialized in MyApp() creation @@ -50,6 +55,7 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { List liveListRetryIntervals, sdk.ParseConnectivityProvider connectivityProvider, String fileDirectory, + Stream appResumedStream, }) async { if (!sdk.parseIsWeb) { final PackageInfo packageInfo = await PackageInfo.fromPlatform(); @@ -81,9 +87,13 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { parseFileConstructor: parseFileConstructor, connectivityProvider: connectivityProvider ?? this, fileDirectory: fileDirectory ?? (await getTemporaryDirectory()).path, + appResumedStream: appResumedStream ?? _appResumedStreamController.stream, ); } + final StreamController _appResumedStreamController = + StreamController(); + @override Future checkConnectivity() async { //Connectivity works differently on web @@ -113,6 +123,11 @@ class Parse extends sdk.Parse implements sdk.ParseConnectivityProvider { } }); } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + _appResumedStreamController.sink.add(null); + } } class CoreStoreSembastImp implements sdk.CoreStoreSembastImp { diff --git a/lib/parse_server_sdk_dart.dart b/lib/parse_server_sdk_dart.dart index 4be7f2e39..1da9ae8ae 100644 --- a/lib/parse_server_sdk_dart.dart +++ b/lib/parse_server_sdk_dart.dart @@ -6,7 +6,6 @@ import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; -import 'package:flutter/widgets.dart'; // TODO(maaeps): 'remove' from dart part import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:meta/meta.dart'; @@ -19,8 +18,6 @@ import 'package:uuid/uuid.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:xxtea/xxtea.dart'; -export 'src/utils/parse_live_list.dart'; - part 'package:parse_server_sdk/src/data/core_store.dart'; part 'package:parse_server_sdk/src/data/parse_subclass_handler.dart'; part 'package:parse_server_sdk/src/objects/response/parse_error_response.dart'; @@ -61,6 +58,7 @@ part 'src/utils/parse_file_extensions.dart'; part 'src/utils/parse_logger.dart'; part 'src/utils/parse_login_helpers.dart'; part 'src/utils/parse_utils.dart'; +part 'src/utils/parse_live_list.dart'; class Parse { ParseCoreData data; @@ -99,6 +97,7 @@ class Parse { List liveListRetryIntervals, ParseConnectivityProvider connectivityProvider, String fileDirectory, + Stream appResumedStream, }) async { final String url = removeTrailingSlash(serverUrl); @@ -123,6 +122,7 @@ class Parse { liveListRetryIntervals: liveListRetryIntervals, connectivityProvider: connectivityProvider, fileDirectory: fileDirectory, + appResumedStream: appResumedStream, ); _hasBeenInitialized = true; diff --git a/lib/src/data/parse_core_data.dart b/lib/src/data/parse_core_data.dart index fb95dcdb9..514b83dd5 100644 --- a/lib/src/data/parse_core_data.dart +++ b/lib/src/data/parse_core_data.dart @@ -35,6 +35,7 @@ class ParseCoreData { List liveListRetryIntervals, ParseConnectivityProvider connectivityProvider, String fileDirectory, + Stream appResumedStream, }) async { _instance = ParseCoreData._init(appId, serverUrl); @@ -96,6 +97,10 @@ class ParseCoreData { if (fileDirectory != null) { _instance.fileDirectory = fileDirectory; } + + if(appResumedStream!= null){ + _instance.appResumedStream = appResumedStream; + } } String appName; @@ -116,6 +121,7 @@ class ParseCoreData { List liveListRetryIntervals; ParseConnectivityProvider connectivityProvider; String fileDirectory; + Stream appResumedStream; void registerSubClass( String className, ParseObjectConstructor objectConstructor) { diff --git a/lib/src/network/parse_live_query.dart b/lib/src/network/parse_live_query.dart index 864049062..cd2b861be 100644 --- a/lib/src/network/parse_live_query.dart +++ b/lib/src/network/parse_live_query.dart @@ -33,9 +33,12 @@ class Subscription { enum LiveQueryClientEvent { CONNECTED, DISCONNECTED, USER_DISCONNECTED } -class LiveQueryReconnectingController with WidgetsBindingObserver { +class LiveQueryReconnectingController { LiveQueryReconnectingController( - this._reconnect, this._eventStream, this.debug) { + this._reconnect, + this._eventStream, + this.debug, + ) { final ParseConnectivityProvider connectivityProvider = ParseCoreData().connectivityProvider; if (connectivityProvider != null) { @@ -69,7 +72,7 @@ class LiveQueryReconnectingController with WidgetsBindingObserver { print('$DEBUG_TAG: $event'); } }); - WidgetsBinding.instance.addObserver(this); + ParseCoreData().appResumedStream?.listen((void _) => _setReconnect()); } static List get retryInterval => ParseCoreData().liveListRetryIntervals; @@ -97,17 +100,6 @@ class LiveQueryReconnectingController with WidgetsBindingObserver { _setReconnect(); } - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - switch (state) { - case AppLifecycleState.resumed: - _setReconnect(); - break; - default: - break; - } - } - void _setReconnect() { if (_isOnline && !_isConnected && diff --git a/lib/src/utils/parse_live_list.dart b/lib/src/utils/parse_live_list.dart index a123e478e..827e27f6b 100644 --- a/lib/src/utils/parse_live_list.dart +++ b/lib/src/utils/parse_live_list.dart @@ -1,8 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; // TODO(maaeps): 'remove' from dart part - -import '../../parse_server_sdk_dart.dart'; +part of flutter_parse_sdk; // ignore_for_file: invalid_use_of_protected_member class ParseLiveList { @@ -735,8 +731,7 @@ class ParseLiveListDeleteEvent typedef StreamGetter = Stream Function(); typedef DataGetter = T Function(); -typedef ChildBuilder = Widget Function( - BuildContext context, ParseLiveListElementSnapshot snapshot); + class ParseLiveListElementSnapshot { ParseLiveListElementSnapshot({this.loadedData, this.error}); @@ -749,240 +744,4 @@ class ParseLiveListElementSnapshot { bool get failed => error != null; } -class ParseLiveListWidget extends StatefulWidget { - const ParseLiveListWidget({ - Key key, - @required this.query, - this.listLoadingElement, - this.duration = const Duration(milliseconds: 300), - this.scrollPhysics, - this.scrollController, - this.scrollDirection = Axis.vertical, - this.padding, - this.primary, - this.reverse = false, - this.childBuilder, - this.shrinkWrap = false, - this.removedItemBuilder, - this.listenOnAllSubItems, - this.listeningIncludes, - this.lazyLoading = true, - }) : super(key: key); - - final QueryBuilder query; - final Widget listLoadingElement; - final Duration duration; - final ScrollPhysics scrollPhysics; - final ScrollController scrollController; - - final Axis scrollDirection; - final EdgeInsetsGeometry padding; - final bool primary; - final bool reverse; - final bool shrinkWrap; - - final ChildBuilder childBuilder; - final ChildBuilder removedItemBuilder; - - final bool listenOnAllSubItems; - final List listeningIncludes; - - final bool lazyLoading; - - @override - _ParseLiveListWidgetState createState() => _ParseLiveListWidgetState( - query: query, - removedItemBuilder: removedItemBuilder, - listenOnAllSubItems: listenOnAllSubItems, - listeningIncludes: listeningIncludes, - lazyLoading: lazyLoading, - ); - - static Widget defaultChildBuilder( - BuildContext context, ParseLiveListElementSnapshot snapshot) { - Widget child; - if (snapshot.failed) { - child = const Text('something went wrong!'); - } else if (snapshot.hasData) { - child = ListTile( - title: Text( - snapshot.loadedData.get(keyVarObjectId), - ), - ); - } else { - child = const ListTile( - leading: CircularProgressIndicator(), - ); - } - return child; - } -} - -class _ParseLiveListWidgetState - extends State> { - _ParseLiveListWidgetState( - {@required this.query, - @required this.removedItemBuilder, - bool listenOnAllSubItems, - List listeningIncludes, - bool lazyLoading = true}) { - ParseLiveList.create( - query, - listenOnAllSubItems: listenOnAllSubItems, - listeningIncludes: listeningIncludes, - lazyLoading: lazyLoading, - ).then((ParseLiveList value) { - setState(() { - _liveList = value; - _liveList.stream.listen((ParseLiveListEvent event) { - if (event is ParseLiveListAddEvent) { - if (_animatedListKey.currentState != null) - _animatedListKey.currentState - .insertItem(event.index, duration: widget.duration); - } else if (event is ParseLiveListDeleteEvent) { - _animatedListKey.currentState.removeItem( - event.index, - (BuildContext context, Animation animation) => - ParseLiveListElementWidget( - key: ValueKey(event.object?.get( - keyVarObjectId, - defaultValue: 'removingItem')), - childBuilder: widget.childBuilder ?? - ParseLiveListWidget.defaultChildBuilder, - sizeFactor: animation, - duration: widget.duration, - loadedData: () => event.object, - ), - duration: widget.duration); - } - }); - }); - }); - } - - final QueryBuilder query; - ParseLiveList _liveList; - final GlobalKey _animatedListKey = - GlobalKey(); - final ChildBuilder removedItemBuilder; - @override - Widget build(BuildContext context) { - return _liveList == null - ? widget.listLoadingElement ?? Container() - : buildAnimatedList(); - } - - Widget buildAnimatedList() { - return AnimatedList( - key: _animatedListKey, - physics: widget.scrollPhysics, - controller: widget.scrollController, - scrollDirection: widget.scrollDirection, - padding: widget.padding, - primary: widget.primary, - reverse: widget.reverse, - shrinkWrap: widget.shrinkWrap, - initialItemCount: _liveList?.size, - itemBuilder: - (BuildContext context, int index, Animation animation) { - return ParseLiveListElementWidget( - key: ValueKey( - _liveList?.getIdentifier(index) ?? '_NotFound'), - stream: () => _liveList?.getAt(index), - loadedData: () => _liveList?.getLoadedAt(index), - sizeFactor: animation, - duration: widget.duration, - childBuilder: - widget.childBuilder ?? ParseLiveListWidget.defaultChildBuilder, - ); - }); - } - - @override - void dispose() { - _liveList?.dispose(); - _liveList = null; - super.dispose(); - } -} - -class ParseLiveListElementWidget extends StatefulWidget { - const ParseLiveListElementWidget( - {Key key, - this.stream, - this.loadedData, - @required this.sizeFactor, - @required this.duration, - @required this.childBuilder}) - : super(key: key); - - final StreamGetter stream; - final DataGetter loadedData; - final Animation sizeFactor; - final Duration duration; - final ChildBuilder childBuilder; - - @override - _ParseLiveListElementWidgetState createState() { - return _ParseLiveListElementWidgetState(loadedData, stream); - } -} - -class _ParseLiveListElementWidgetState - extends State> - with SingleTickerProviderStateMixin { - _ParseLiveListElementWidgetState( - DataGetter loadedDataGetter, StreamGetter stream) { - _snapshot = ParseLiveListElementSnapshot(loadedData: loadedDataGetter()); - if (stream != null) { - _streamSubscription = stream().listen( - (T data) { - if (widget != null) { - setState(() { - _snapshot = ParseLiveListElementSnapshot(loadedData: data); - }); - } else { - _snapshot = ParseLiveListElementSnapshot(loadedData: data); - } - }, - onError: (Object error) { - if (error is ParseError) { - if (widget != null) { - setState(() { - _snapshot = ParseLiveListElementSnapshot(error: error); - }); - } else { - _snapshot = ParseLiveListElementSnapshot(error: error); - } - } - }, - cancelOnError: false, - ); - } - } - - ParseLiveListElementSnapshot _snapshot; - - StreamSubscription _streamSubscription; - - @override - void dispose() { - _streamSubscription?.cancel(); - _streamSubscription = null; - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final Widget result = SizeTransition( - sizeFactor: widget.sizeFactor, - child: AnimatedSize( - duration: widget.duration, - vsync: this, - child: widget.childBuilder(context, _snapshot), - ), - ); - return result; - } -} diff --git a/lib/src/utils/parse_live_list_flutter.dart b/lib/src/utils/parse_live_list_flutter.dart new file mode 100644 index 000000000..1d6eb394a --- /dev/null +++ b/lib/src/utils/parse_live_list_flutter.dart @@ -0,0 +1,245 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:parse_server_sdk/parse_server_sdk_dart.dart'; + +typedef ChildBuilder = Widget Function( + BuildContext context, ParseLiveListElementSnapshot snapshot); + +class ParseLiveListWidget extends StatefulWidget { + const ParseLiveListWidget({ + Key key, + @required this.query, + this.listLoadingElement, + this.duration = const Duration(milliseconds: 300), + this.scrollPhysics, + this.scrollController, + this.scrollDirection = Axis.vertical, + this.padding, + this.primary, + this.reverse = false, + this.childBuilder, + this.shrinkWrap = false, + this.removedItemBuilder, + this.listenOnAllSubItems, + this.listeningIncludes, + this.lazyLoading = true, + }) : super(key: key); + + final QueryBuilder query; + final Widget listLoadingElement; + final Duration duration; + final ScrollPhysics scrollPhysics; + final ScrollController scrollController; + + final Axis scrollDirection; + final EdgeInsetsGeometry padding; + final bool primary; + final bool reverse; + final bool shrinkWrap; + + final ChildBuilder childBuilder; + final ChildBuilder removedItemBuilder; + + final bool listenOnAllSubItems; + final List listeningIncludes; + + final bool lazyLoading; + + @override + _ParseLiveListWidgetState createState() => _ParseLiveListWidgetState( + query: query, + removedItemBuilder: removedItemBuilder, + listenOnAllSubItems: listenOnAllSubItems, + listeningIncludes: listeningIncludes, + lazyLoading: lazyLoading, + ); + + static Widget defaultChildBuilder( + BuildContext context, ParseLiveListElementSnapshot snapshot) { + Widget child; + if (snapshot.failed) { + child = const Text('something went wrong!'); + } else if (snapshot.hasData) { + child = ListTile( + title: Text( + snapshot.loadedData.get(keyVarObjectId), + ), + ); + } else { + child = const ListTile( + leading: CircularProgressIndicator(), + ); + } + return child; + } +} + +class _ParseLiveListWidgetState + extends State> { + _ParseLiveListWidgetState( + {@required this.query, + @required this.removedItemBuilder, + bool listenOnAllSubItems, + List listeningIncludes, + bool lazyLoading = true}) { + ParseLiveList.create( + query, + listenOnAllSubItems: listenOnAllSubItems, + listeningIncludes: listeningIncludes, + lazyLoading: lazyLoading, + ).then((ParseLiveList value) { + setState(() { + _liveList = value; + _liveList.stream.listen((ParseLiveListEvent event) { + if (event is ParseLiveListAddEvent) { + if (_animatedListKey.currentState != null) + _animatedListKey.currentState + .insertItem(event.index, duration: widget.duration); + } else if (event is ParseLiveListDeleteEvent) { + _animatedListKey.currentState.removeItem( + event.index, + (BuildContext context, Animation animation) => + ParseLiveListElementWidget( + key: ValueKey(event.object?.get( + keyVarObjectId, + defaultValue: 'removingItem')), + childBuilder: widget.childBuilder ?? + ParseLiveListWidget.defaultChildBuilder, + sizeFactor: animation, + duration: widget.duration, + loadedData: () => event.object, + ), + duration: widget.duration); + } + }); + }); + }); + } + + final QueryBuilder query; + ParseLiveList _liveList; + final GlobalKey _animatedListKey = + GlobalKey(); + final ChildBuilder removedItemBuilder; + + @override + Widget build(BuildContext context) { + return _liveList == null + ? widget.listLoadingElement ?? Container() + : buildAnimatedList(); + } + + Widget buildAnimatedList() { + return AnimatedList( + key: _animatedListKey, + physics: widget.scrollPhysics, + controller: widget.scrollController, + scrollDirection: widget.scrollDirection, + padding: widget.padding, + primary: widget.primary, + reverse: widget.reverse, + shrinkWrap: widget.shrinkWrap, + initialItemCount: _liveList?.size, + itemBuilder: + (BuildContext context, int index, Animation animation) { + return ParseLiveListElementWidget( + key: ValueKey( + _liveList?.getIdentifier(index) ?? '_NotFound'), + stream: () => _liveList?.getAt(index), + loadedData: () => _liveList?.getLoadedAt(index), + sizeFactor: animation, + duration: widget.duration, + childBuilder: + widget.childBuilder ?? ParseLiveListWidget.defaultChildBuilder, + ); + }); + } + + @override + void dispose() { + _liveList?.dispose(); + _liveList = null; + super.dispose(); + } +} + +class ParseLiveListElementWidget extends StatefulWidget { + const ParseLiveListElementWidget( + {Key key, + this.stream, + this.loadedData, + @required this.sizeFactor, + @required this.duration, + @required this.childBuilder}) + : super(key: key); + + final StreamGetter stream; + final DataGetter loadedData; + final Animation sizeFactor; + final Duration duration; + final ChildBuilder childBuilder; + + @override + _ParseLiveListElementWidgetState createState() { + return _ParseLiveListElementWidgetState(loadedData, stream); + } +} + +class _ParseLiveListElementWidgetState + extends State> + with SingleTickerProviderStateMixin { + _ParseLiveListElementWidgetState( + DataGetter loadedDataGetter, StreamGetter stream) { + _snapshot = ParseLiveListElementSnapshot(loadedData: loadedDataGetter()); + if (stream != null) { + _streamSubscription = stream().listen( + (T data) { + if (widget != null) { + setState(() { + _snapshot = ParseLiveListElementSnapshot(loadedData: data); + }); + } else { + _snapshot = ParseLiveListElementSnapshot(loadedData: data); + } + }, + onError: (Object error) { + if (error is ParseError) { + if (widget != null) { + setState(() { + _snapshot = ParseLiveListElementSnapshot(error: error); + }); + } else { + _snapshot = ParseLiveListElementSnapshot(error: error); + } + } + }, + cancelOnError: false, + ); + } + } + + ParseLiveListElementSnapshot _snapshot; + + StreamSubscription _streamSubscription; + + @override + void dispose() { + _streamSubscription?.cancel(); + _streamSubscription = null; + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final Widget result = SizeTransition( + sizeFactor: widget.sizeFactor, + child: AnimatedSize( + duration: widget.duration, + vsync: this, + child: widget.childBuilder(context, _snapshot), + ), + ); + return result; + } +} From a9ea83358edb72907ddecb3ba2f76ee261bf7cdb Mon Sep 17 00:00:00 2001 From: maaeps Date: Thu, 3 Sep 2020 22:52:27 +0200 Subject: [PATCH 11/11] fixed tests --- lib/parse_server_sdk.dart | 2 +- test/parse_client_configuration_test.dart | 4 +++- test/parse_query_test.dart | 16 ++++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index deb29a3c1..b84c7a83b 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -57,7 +57,7 @@ class Parse extends sdk.Parse String fileDirectory, Stream appResumedStream, }) async { - if (!sdk.parseIsWeb) { + if (!sdk.parseIsWeb && (appName == null || appVersion == null || appPackageName == null)) { final PackageInfo packageInfo = await PackageInfo.fromPlatform(); appName ??= packageInfo.appName; appVersion ??= packageInfo.version; diff --git a/test/parse_client_configuration_test.dart b/test/parse_client_configuration_test.dart index e5a64173f..87f9ab35c 100644 --- a/test/parse_client_configuration_test.dart +++ b/test/parse_client_configuration_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:parse_server_sdk/parse_server_sdk_dart.dart'; +import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { @@ -14,6 +14,7 @@ void main() { appVersion: 'someAppVersion', masterKey: 'masterKey', sessionId: 'sessionId', + fileDirectory: 'someDirectory', debug: true); expect(ParseCoreData().applicationId, 'appId'); @@ -26,5 +27,6 @@ void main() { expect(ParseCoreData().masterKey, 'masterKey'); expect(ParseCoreData().sessionId, 'sessionId'); expect(ParseCoreData().debug, true); + expect(ParseCoreData().fileDirectory, 'someDirectory'); }); } diff --git a/test/parse_query_test.dart b/test/parse_query_test.dart index 67cabf0b9..3a5133fbc 100644 --- a/test/parse_query_test.dart +++ b/test/parse_query_test.dart @@ -1,6 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:parse_server_sdk/parse_server_sdk_dart.dart'; +import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'package:shared_preferences/shared_preferences.dart'; class MockClient extends Mock implements ParseHTTPClient {} @@ -12,7 +12,19 @@ void main() { test('whereRelatedTo', () async { final MockClient client = MockClient(); - await Parse().initialize('appId', 'https://test.parse.com', debug: true); + await Parse().initialize( + 'appId', + 'https://test.parse.com', + debug: true, + // to prevent automatic detection + fileDirectory: 'someDirectory', + // to prevent automatic detection + appName: 'appName', + // to prevent automatic detection + appPackageName: 'somePackageName', + // to prevent automatic detection + appVersion: 'someAppVersion', + ); final QueryBuilder queryBuilder = QueryBuilder(ParseObject('_User', client: client));