Skip to content

Commit

Permalink
Merge pull request cph-cachet#394 from Crewlan/bugfix/android
Browse files Browse the repository at this point in the history
added functions to request authorization
  • Loading branch information
bardram committed Aug 9, 2021
2 parents 250a75c + 4d12e0c commit ffefefa
Showing 1 changed file with 36 additions and 26 deletions.
62 changes: 36 additions & 26 deletions packages/health/lib/src/health_factory.dart
Expand Up @@ -6,14 +6,33 @@ class HealthFactory {
String? _deviceId;
final _deviceInfo = DeviceInfoPlugin();

static PlatformType _platformType =
Platform.isAndroid ? PlatformType.ANDROID : PlatformType.IOS;
static PlatformType _platformType = Platform.isAndroid ? PlatformType.ANDROID : PlatformType.IOS;

/// Check if a given data type is available on the platform
bool isDataTypeAvailable(HealthDataType dataType) =>
_platformType == PlatformType.ANDROID
? _dataTypeKeysAndroid.contains(dataType)
: _dataTypeKeysIOS.contains(dataType);
bool isDataTypeAvailable(HealthDataType dataType) => _platformType == PlatformType.ANDROID
? _dataTypeKeysAndroid.contains(dataType)
: _dataTypeKeysIOS.contains(dataType);

/// iOS isn't completely supported by HealthKit, false means no, true means user has approved or declined permissions.
/// In case user has declined permissions read will just return empty list for declined data types.
static Future<bool?> hasPermissions(List<HealthDataType> types) async {
return await _channel.invokeMethod('hasPermissions', {
"types": types.map((type) => _enumToString(type)).toList(),
});
}

/// If you're using more than one DataType it's advised to call requestPermissions with all the data types once,
/// otherwise iOS HealthKit will ask to approve every permission one by one in separate screens.
static Future<bool?> requestPermissions(List<HealthDataType> types) async {
return await _channel.invokeMethod('requestPermissions', {
"types": types.map((type) => _enumToString(type)).toList(),
});
}

/// iOS isn't supported by HealthKit, method does nothing.
static Future<void> revokePermissions() async {
return await _channel.invokeMethod('revokePermissions');
}

/// Request access to GoogleFit or Apple HealthKit
Future<bool> requestAuthorization(List<HealthDataType> types) async {
Expand All @@ -29,23 +48,19 @@ class HealthFactory {
}

List<String> keys = types.map((e) => _enumToString(e)).toList();
final bool isAuthorized =
await _channel.invokeMethod('requestAuthorization', {'types': keys});
final bool isAuthorized = await _channel.invokeMethod('requestAuthorization', {'types': keys});
return isAuthorized;
}

/// Calculate the BMI using the last observed height and weight values.
Future<List<HealthDataPoint>> _computeAndroidBMI(
DateTime startDate, DateTime endDate) async {
List<HealthDataPoint> heights =
await _prepareQuery(startDate, endDate, HealthDataType.HEIGHT);
Future<List<HealthDataPoint>> _computeAndroidBMI(DateTime startDate, DateTime endDate) async {
List<HealthDataPoint> heights = await _prepareQuery(startDate, endDate, HealthDataType.HEIGHT);

if (heights.isEmpty) {
return [];
}

List<HealthDataPoint> weights =
await _prepareQuery(startDate, endDate, HealthDataType.WEIGHT);
List<HealthDataPoint> weights = await _prepareQuery(startDate, endDate, HealthDataType.WEIGHT);

double h = heights.last.value.toDouble();

Expand All @@ -55,8 +70,8 @@ class HealthFactory {
final bmiHealthPoints = <HealthDataPoint>[];
for (var i = 0; i < weights.length; i++) {
final bmiValue = weights[i].value.toDouble() / (h * h);
final x = HealthDataPoint(bmiValue, dataType, unit, weights[i].dateFrom,
weights[i].dateTo, _platformType, _deviceId!, '', '');
final x = HealthDataPoint(
bmiValue, dataType, unit, weights[i].dateFrom, weights[i].dateTo, _platformType, _deviceId!, '', '');

bmiHealthPoints.add(x);
}
Expand All @@ -76,30 +91,26 @@ class HealthFactory {
}

/// Prepares a query, i.e. checks if the types are available, etc.
Future<List<HealthDataPoint>> _prepareQuery(
DateTime startDate, DateTime endDate, HealthDataType dataType) async {
Future<List<HealthDataPoint>> _prepareQuery(DateTime startDate, DateTime endDate, HealthDataType dataType) async {
// Ask for device ID only once
_deviceId ??= _platformType == PlatformType.ANDROID
? (await _deviceInfo.androidInfo).androidId
: (await _deviceInfo.iosInfo).identifierForVendor;

// If not implemented on platform, throw an exception
if (!isDataTypeAvailable(dataType)) {
throw _HealthException(
dataType, 'Not available on platform $_platformType');
throw _HealthException(dataType, 'Not available on platform $_platformType');
}

// If BodyMassIndex is requested on Android, calculate this manually
if (dataType == HealthDataType.BODY_MASS_INDEX &&
_platformType == PlatformType.ANDROID) {
if (dataType == HealthDataType.BODY_MASS_INDEX && _platformType == PlatformType.ANDROID) {
return _computeAndroidBMI(startDate, endDate);
}
return await _dataQuery(startDate, endDate, dataType);
}

/// The main function for fetching health data
Future<List<HealthDataPoint>> _dataQuery(
DateTime startDate, DateTime endDate, HealthDataType dataType) async {
Future<List<HealthDataPoint>> _dataQuery(DateTime startDate, DateTime endDate, HealthDataType dataType) async {
// Set parameters for method channel request
final args = <String, dynamic>{
'dataTypeKey': _enumToString(dataType),
Expand All @@ -113,8 +124,7 @@ class HealthFactory {
if (fetchedDataPoints != null) {
return fetchedDataPoints.map<HealthDataPoint>((e) {
final num value = e['value'];
final DateTime from =
DateTime.fromMillisecondsSinceEpoch(e['date_from']);
final DateTime from = DateTime.fromMillisecondsSinceEpoch(e['date_from']);
final DateTime to = DateTime.fromMillisecondsSinceEpoch(e['date_to']);
final String sourceId = e["source_id"];
final String sourceName = e["source_name"];
Expand Down

0 comments on commit ffefefa

Please sign in to comment.