diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index a6c9ff267..acd4616df 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -13,6 +13,8 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:web_socket_channel/io.dart'; import 'package:uuid/uuid.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:devicelocale/devicelocale.dart'; +import 'package:package_info/package_info.dart'; part 'src/base/parse_constants.dart'; @@ -46,6 +48,8 @@ part 'src/objects/parse_response.dart'; part 'src/objects/parse_user.dart'; +part 'src/objects/parse_installation.dart'; + part 'src/utils/parse_decoder.dart'; part 'src/utils/parse_encoder.dart'; diff --git a/lib/src/base/parse_constants.dart b/lib/src/base/parse_constants.dart index e4f7b094f..1d6037a9e 100644 --- a/lib/src/base/parse_constants.dart +++ b/lib/src/base/parse_constants.dart @@ -28,6 +28,7 @@ const String keyVarAcl = 'ACL'; // Classes const String keyClassMain = 'ParseMain'; const String keyClassUser = '_User'; +const String keyClassInstallation = '_Installation'; const String keyGeoPoint = 'GeoPoint'; const String keyFile = 'File'; @@ -47,3 +48,4 @@ const String keyParamSessionToken = 'sessionToken'; // Storage const String keyParseStoreBase = 'flutter_parse_sdk_'; const String keyParseStoreUser = "${keyParseStoreBase}user"; +const String keyParseStoreInstallation = "${keyParseStoreBase}installation"; diff --git a/lib/src/objects/parse_installation.dart b/lib/src/objects/parse_installation.dart new file mode 100644 index 000000000..32d148f9c --- /dev/null +++ b/lib/src/objects/parse_installation.dart @@ -0,0 +1,148 @@ +part of flutter_parse_sdk; + +class ParseInstallation extends ParseObject { + static final String keyTimeZone = 'timeZone'; + static final String keyLocaleIdentifier = 'localeIdentifier'; + static final String keyDeviceToken = 'deviceToken'; + static final String keyDeviceType = 'deviceType'; + static final String keyInstallationId = 'installationId'; + static final String keyAppName = 'appName'; + static final String keyAppVersion = 'appVersion'; + static final String keyAppIdentifier = 'appIdentifier'; + static final String keyParseVersion = 'parseVersion'; + static final List readOnlyKeys = [ //TODO + keyDeviceToken, keyDeviceType, keyInstallationId, + keyAppName, keyAppVersion, keyAppIdentifier, keyParseVersion + ]; + static String _currentInstallationId; + + //Getters/setters + + Map get acl => super.get(keyVarAcl); + + set acl(Map acl) => set(keyVarAcl, acl); + + String get deviceToken => super.get(keyDeviceToken); + + set deviceToken(String deviceToken) => set(keyDeviceToken, deviceToken); + + String get deviceType => super.get(keyDeviceType); + + String get installationId => super.get(keyInstallationId); + + set _installationId(String installationId) => set(keyInstallationId, installationId); + + String get appName => super.get(keyAppName); + + String get appVersion => super.get(keyAppVersion); + + String get appIdentifier => super.get(keyAppIdentifier); + + String get parseVersion => super.get(keyParseVersion); + + /// Creates an instance of ParseInstallation + ParseInstallation( + {bool debug, + ParseHTTPClient client, + bool autoSendSessionId}) + : super(keyClassInstallation) { + _debug = isDebugEnabled(objectLevelDebug: debug); + _client = client ?? + ParseHTTPClient( + autoSendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); + } + + ParseInstallation.forQuery() : super(keyClassUser); + + static Future isCurrent(ParseInstallation installation) async { + if (_currentInstallationId == null) { + _currentInstallationId = (await _getFromLocalStore()).installationId; + } + return _currentInstallationId != null && installation.installationId == _currentInstallationId; + } + + /// Gets the current installation from storage + static Future currentInstallation() async { + var installation = await _getFromLocalStore(); + if (installation == null) { + installation = await _createInstallation(); + } + return installation; + } + + /// Updates the installation with current device data + _updateInstallation() async { + //Device type + if (Platform.isAndroid) set(keyDeviceType, "android"); + else if (Platform.isIOS) set(keyDeviceType, "ios"); + else throw Exception("Unsupported platform/operating system"); + + //Locale + String locale = await Devicelocale.currentLocale; + if (locale != null && locale.isNotEmpty) { + set(keyLocaleIdentifier, locale); + } + + //Timezone + //TODO set(keyTimeZone, ); + + //App info + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + set(keyAppName, packageInfo.appName); + set(keyAppVersion, packageInfo.version); + set(keyAppIdentifier, packageInfo.packageName); + set(keyParseVersion, keySdkVersion); + } + + Future create() async { + var isCurrent = await ParseInstallation.isCurrent(this); + if (isCurrent) await _updateInstallation(); + ParseResponse parseResponse = await super.create(); + if (parseResponse.success && isCurrent) { + saveInStorage(keyParseStoreInstallation); + } + return parseResponse; + } + + /// Saves the current installation + Future save() async { + var isCurrent = await ParseInstallation.isCurrent(this); + if (isCurrent) await _updateInstallation(); + ParseResponse parseResponse = await super.save(); + if (parseResponse.success && isCurrent) { + saveInStorage(keyParseStoreInstallation); + } + return parseResponse; + } + + /// Gets the locally stored installation + static Future _getFromLocalStore() async { + var installationJson = + (await ParseCoreData().getStore()).getString(keyParseStoreInstallation); + + if (installationJson != null) { + var installationMap = parseDecode(json.decode(installationJson)); + + if (installationMap != null) { + return new ParseInstallation()..fromJson(installationMap); + } + } + + return null; + } + + /// Creates a installation for current device + /// Assumes that this is called because there is no previous installation + /// so it creates and sets the static current installation UUID + static Future _createInstallation() async { + if (_currentInstallationId == null) { + _currentInstallationId = Uuid().v4(); + } + var installation = new ParseInstallation(); + installation._installationId = _currentInstallationId; + await installation._updateInstallation(); + return installation; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 7f67d35dd..771e1f1d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,8 @@ dependencies: shared_preferences: ^0.4.3 path_provider: ^0.4.1 uuid: ^1.0.3 + package_info: ^0.4.0 + devicelocale: ^0.1.1 dev_dependencies: # Testing