Пример #1
0
        public void SaveWorkout(HKWorkoutSession workoutSession, NSDate startDate, NSDate endDate)
        {
            // Create and save a workout sample
            var configuration = workoutSession.WorkoutConfiguration;
            var metadata      = new HKMetadata
            {
                IndoorWorkout = configuration.LocationType == HKWorkoutSessionLocationType.Indoor,
            };

            var workout = HKWorkout.Create(configuration.ActivityType,
                                           startDate,
                                           endDate,
                                           this.workoutEvents.ToArray(),
                                           this.TotalBurningEnergyQuantity(),
                                           this.TotalDistanceQuantity(),
                                           metadata);

            this.healthStore.SaveObject(workout, (isSuccess, error) =>
            {
                if (isSuccess)
                {
                    this.AddSamples(workout, startDate, endDate);
                }
            });
        }
        public override void Awake(NSObject context)
        {
            base.Awake(context);

            this.workout = context as HKWorkout;
            this.SetTitle("Summary");
        }
Пример #3
0
        private void MakeWorkoutsSlothy(HKWorkout workout)
        {
            // Query for workout's rotes
            var routeType        = HKSeriesType.WorkoutRouteType;
            var workoutPredicate = HKQuery.GetPredicateForObjectsFromWorkout(workout);
            var routeQuery       = new HKSampleQuery(routeType, workoutPredicate, HKSampleQuery.NoLimit, null, (sender, results, error) =>
            {
                var route = results?.FirstOrDefault() as HKWorkoutRoute;
                if (route != null)
                {
                    var version = route.Metadata?.SyncVersion;
                    if (!version.HasValue)
                    {
                        Console.WriteLine($"Route does not have a sync version ({route})");
                    }
                    else if (version.Value == 1)
                    {
                        this.MakeRouteWorkoutsSlothy(workout, route);
                    }
                }
                else
                {
                    Console.WriteLine($"An error occurred fetching the route ({error?.LocalizedDescription ?? "Workout has no routes"})");
                }
            });

            this.healthStore.ExecuteQuery(routeQuery);
        }
Пример #4
0
 private void MakeRouteWorkoutsSlothy(HKWorkout workout, HKWorkoutRoute route)
 {
     // Get all of the locations
     this.LoadRouteLocations(route, (locations) =>
     {
         // Slothify route
         var newLocations = this.SlothifyRouteLocations(locations);
         this.UpdateWorkoutLocationsRoute(workout, route, newLocations);
     });
 }
Пример #5
0
        public void SaveWorkout()
        {
            // Obtain the `HKObjectType` for active energy burned.
            var activeEnergyType = HKQuantityType.Create(HKQuantityTypeIdentifier.ActiveEnergyBurned);

            if (activeEnergyType == null)
            {
                return;
            }

            var beginDate = WorkoutBeginDate;
            var endDate   = WorkoutEndDate;

            var          timeDifference = endDate.Subtract(beginDate);
            double       duration       = timeDifference.TotalSeconds;
            NSDictionary metadata       = null;

            var workout = HKWorkout.Create(HKWorkoutActivityType.Walking,
                                           (NSDate)beginDate,
                                           (NSDate)endDate,
                                           duration,
                                           CurrentActiveEnergyQuantity,
                                           HKQuantity.FromQuantity(HKUnit.Mile, 0.0),
                                           metadata);

            var finalActiveEnergySamples = ActiveEnergySamples;

            if (HealthStore.GetAuthorizationStatus(activeEnergyType) != HKAuthorizationStatus.SharingAuthorized ||
                HealthStore.GetAuthorizationStatus(HKObjectType.GetWorkoutType()) != HKAuthorizationStatus.SharingAuthorized)
            {
                return;
            }

            HealthStore.SaveObject(workout, (success, error) => {
                if (!success)
                {
                    Console.WriteLine($"An error occured saving the workout. In your app, try to handle this gracefully. The error was: {error}.");
                    return;
                }

                if (finalActiveEnergySamples.Count > 0)
                {
                    HealthStore.AddSamples(finalActiveEnergySamples.ToArray(), workout, (addSuccess, addError) => {
                        // Handle any errors
                        if (addError != null)
                        {
                            Console.WriteLine($"An error occurred adding the samples. In your app, try to handle this gracefully. The error was: {error.ToString()}.");
                        }
                    });
                }
            });
        }
Пример #6
0
        //More info for init HKUnit:
        //https://developer.apple.com/documentation/healthkit/hkunit/1615733-init

        //More info on datatype:
        //https://github.com/dariosalvi78/cordova-plugin-health

        //TODO: come gestire active+basal per calorie?
        //TODO: HKQuantityTypeIdentifierActiveEnergyBurned + HKQuantityTypeIdentifierBasalEnergyBurned


        internal static WorkoutDataType WorkoutDataType(this HKWorkout hKWorkout)
        {
            return(hKWorkout.WorkoutActivityType switch
            {
                HKWorkoutActivityType.Flexibility => Health.WorkoutDataType.Flexibility,
                HKWorkoutActivityType.Cycling => Health.WorkoutDataType.Biking,
                HKWorkoutActivityType.MindAndBody => Health.WorkoutDataType.MindAndBody,
                HKWorkoutActivityType.FunctionalStrengthTraining => Health.WorkoutDataType.FunctionalStrengthTraining,
                HKWorkoutActivityType.TraditionalStrengthTraining => Health.WorkoutDataType.TraditionalStrengthTraining,
                HKWorkoutActivityType.Yoga => Health.WorkoutDataType.Yoga,
                HKWorkoutActivityType.Running => Health.WorkoutDataType.Running,
                HKWorkoutActivityType.CoreTraining => Health.WorkoutDataType.CoreTraining,
                HKWorkoutActivityType.Other => Health.WorkoutDataType.Other,
                _ => throw new NotSupportedException(),
            });
Пример #7
0
        private void AddSamples(HKWorkout workout, NSDate startDate, NSDate endDate)
        {
            // Create energy and distance sample
            var totalEnergyBurnedSample = HKQuantitySample.FromType(HKQuantityType.Create(HKQuantityTypeIdentifier.ActiveEnergyBurned),
                                                                    this.TotalBurningEnergyQuantity(),
                                                                    startDate,
                                                                    endDate);

            var totalDistanceSample = HKQuantitySample.FromType(HKQuantityType.Create(HKQuantityTypeIdentifier.DistanceWalkingRunning),
                                                                this.TotalDistanceQuantity(),
                                                                startDate,
                                                                endDate);

            // add samples to workout
            this.healthStore.AddSamples(new HKSample[] { totalEnergyBurnedSample, totalDistanceSample }, workout, (isSuccess, error) =>
            {
                if (isSuccess)
                {
                    DispatchQueue.MainQueue.DispatchAsync(() =>
                    {
                        WKInterfaceController.ReloadRootPageControllers(new string[] { nameof(SummaryInterfaceController) },
                                                                        new NSObject[] { workout },
                                                                        WKPageOrientation.Vertical,
                                                                        0);
                    });
                }
                else
                {
                    Console.WriteLine($"Adding workout subsamples failed with error: ({error?.Description ?? "unknown"})");
                }
            });

            // finish the route with a syn identifier so we can easily update the route later
            var objects = new NSObject[] { new NSString(new NSUuid().AsString()), NSNumber.FromInt32(1) };
            var keys    = new NSString[] { HKMetadataKey.SyncIdentifier, HKMetadataKey.SyncVersion };

            var dictionary = NSDictionary.FromObjectsAndKeys(objects, keys);
            var metadata   = new HKMetadata(dictionary);

            this.workoutRouteBuilder?.FinishRoute(workout, metadata, (workoutRoute, error) =>
            {
                if (workoutRoute == null)
                {
                    Console.WriteLine($"Finishing route failed with error: ({error?.Description ?? "unknown"})");
                }
            });
        }
Пример #8
0
        /*
         * public async Task<bool> SaveBmi(double value, DateTime start, DateTime? end)
         * {
         *  return await WriteAsync(HealthDataType.iOS_BodyMassIndex, value, start, end);
         * }
         *
         * public async Task<bool> SaveMindfulSession(int value, DateTime start, DateTime? end)
         * {
         *  return await WriteAsync(HealthDataType.MindfulSession, value, start, end);
         * }
         *
         * public async Task<bool> SaveHeight(double value, DateTime start, DateTime? end)
         * {
         *  return await WriteAsync(HealthDataType.Height, value, start, end);
         * }
         *
         * public async Task<bool> SaveWeight(double value, DateTime start, DateTime? end)
         * {
         *  return await WriteAsync(HealthDataType.Weight, value, start, end);
         * }
         *
         * public async Task<bool> SaveStep(int value, DateTime start, DateTime? end)
         * {
         *  return await WriteAsync(HealthDataType.StepCount, value, start, end);
         * }
         *
         * public async Task<bool> SaveSleepAnalysis(HKCategoryValueSleepAnalysis value, DateTime start, DateTime end)
         * {
         *  return await WriteAsync(HealthDataType.SleepAnalysis, (int)value, start, end);
         * }
         */

        public override async Task <bool> WriteAsync(WorkoutDataType workoutDataType, double calories, DateTime start, DateTime?end = null, string name = null)
        {
            var totalEnergyBurned = HKQuantity.FromQuantity(HKUnit.CreateJouleUnit(HKMetricPrefix.Kilo), 20);

            var metadata = new HKMetadata();

            if (name != null)
            {
                metadata.WorkoutBrandName = name;
            }

            var workout = HKWorkout.Create(Convert(workoutDataType), (NSDate)start, (NSDate)end, new HKWorkoutEvent[] { }, totalEnergyBurned, null, metadata);


            var(success, error) = await _healthStore.SaveObjectAsync(workout);

            return(success);
        }
Пример #9
0
        private void UpdateWorkoutLocationsRoute(HKWorkout workout, HKWorkoutRoute route, List <CLLocation> newLocations)
        {
            // create a workout route builder
            var workoutRouteBuilder = new HKWorkoutRouteBuilder(this.healthStore, null);

            // insert updated route locations
            workoutRouteBuilder.InsertRouteData(newLocations.ToArray(), (success, error) =>
            {
                if (success)
                {
                    var syncIdentifier = route.Metadata?.SyncIdentifier;
                    if (!string.IsNullOrEmpty(syncIdentifier))
                    {
                        // new metadata with the same sync identifier and a higher version
                        var objects = new NSObject[] { new NSString(syncIdentifier), NSNumber.FromInt32(2) };
                        var keys    = new NSString[] { HKMetadataKey.SyncIdentifier, HKMetadataKey.SyncVersion };

                        var dictionary = NSDictionary.FromObjectsAndKeys(objects, keys);
                        var metadata   = new HKMetadata(dictionary);

                        // finish the route with updated metadata
                        workoutRouteBuilder.FinishRoute(workout, metadata, (workoutRoute, routeRrror) =>
                        {
                            if (workoutRoute != null)
                            {
                                Console.WriteLine($"Workout route updated: ({route})");
                            }
                            else
                            {
                                Console.WriteLine($"An error occurred while finishing the new route: ({error?.LocalizedDescription ?? "Unknown"})");
                            }
                        });
                    }
                    else
                    {
                        throw new ArgumentNullException(nameof(syncIdentifier), "Missing expected sync identifier on route");
                    }
                }
                else
                {
                    Console.WriteLine($"An error occurred while inserting route data ({error?.LocalizedDescription ?? "Unknown"})");
                }
            });
        }
Пример #10
0
        public Task <ExerciseData> AddExercise(ExerciseData data)
        {
            var completionSource = new TaskCompletionSource <ExerciseData>();
            var metadata         = new HKMetadata()
            {
                GroupFitness   = true,
                IndoorWorkout  = true,
                CoachedWorkout = true,
            };

            if (data.Time.TotalMinutes == 0)
            {
                DateTime start = ((DateTime)data.DateInit).ToLocalTime();
                DateTime end   = ((DateTime)data.DateEnd).ToLocalTime();

                data.Time = end.Subtract(start);
            }
            HKQuantity calories = getCaloriesFromData(data);

            HKWorkout workOut = HKWorkout.Create(HKWorkoutActivityType.TraditionalStrengthTraining,
                                                 data.DateInit,
                                                 data.DateEnd,
                                                 null,
                                                 calories,
                                                 null,
                                                 metadata);

            HealthStore.SaveObject(workOut, (succes, error) => {
                if (succes)
                {
                    data.Kilocalories = calories.GetDoubleValue(HKUnit.Kilocalorie);

                    completionSource.SetResult(data);
                }
                else
                {
                    completionSource.SetResult(null);
                }
            });

            return(completionSource.Task);
        }
Пример #11
0
        public static Workout ParseWorkout(HKWorkout workout)
        {
            var startDate = workout.StartDate.ToInstant();
            var endDate   = workout.EndDate.ToInstant();

            return(new Workout
            {
                WorkoutType = workout.WorkoutActivityType.ToString(),
                SourceName = workout.Source.Name,
                EndDate = endDate,
                StartDate = startDate,
                Duration = Duration.FromSeconds(workout.Duration),
                Distance = workout.TotalDistance.Apply(Optional).Match(
                    Some: d => Length.FromMeters(workout.TotalDistance.GetDoubleValue(HKUnit.Meter)),
                    None: () => Length.Zero),
                Energy = workout.TotalEnergyBurned.Apply(Optional).Match(
                    Some: e => Energy.FromCalories(workout.TotalEnergyBurned.GetDoubleValue(HKUnit.Calorie)),
                    None: () => Energy.Zero),
                Device = workout.Device?.Name ?? "<no device>",
            });
        }