Changed workout states logic.
authorAndrzej Krawczyk <a.krawczyk@samsung.com>
Mon, 2 Aug 2021 14:46:33 +0000 (16:46 +0200)
committerPiotr Czaja <p.czaja@samsung.com>
Tue, 14 Sep 2021 11:01:34 +0000 (13:01 +0200)
Fitness/Models/WorkoutState.cs
Fitness/ViewModels/ExercisingViewModel.cs
Fitness/Views/ExercisingView.xaml.cs
Fitness/res/layout/ExercisingView.xaml

index 03435fa50962578969e47cb4f9a7de99291a148d..b889b3c98e16054851cb0cce3c10b5e1f03a296f 100644 (file)
@@ -1,25 +1,28 @@
-using System;
-
 namespace Fitness.Models
 {
     /// <summary>
-    /// Current state of workout
+    /// Current state of workout.
     /// </summary>
     public enum WorkoutState
     {
         /// <summary>
-        /// the workout has been paused, preserving current progress
+        /// The countdown to start is processing.
         /// </summary>
-        Paused,
+        Loading,
 
         /// <summary>
-        /// the workout is playing
+        /// The workout is playing.
         /// </summary>
         Playing,
 
         /// <summary>
-        /// the workout has been stopped,
+        /// The workout has been paused preserving PlayingView.
+        /// </summary>
+        OnHold,
+
+        /// <summary>
+        /// The workout has been paused to PasueView.
         /// </summary>
-        Stopped,
+        Paused,
     }
 }
index bd137d384355ab45a71b00e727475b4a1abdd995..3cb05c61d96f50059568cb4b024172bcae50aa5b 100644 (file)
@@ -28,7 +28,6 @@ namespace Fitness.ViewModels
         private ICommand summaryBackCommand;
         private ICommand summaryOkCommand;
         private string summaryTitle;
-        private bool isLoading;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ExercisingViewModel"/> class.
@@ -39,7 +38,6 @@ namespace Fitness.ViewModels
             PauseResumeWorkout = new Command(TriggerPauseResumeWorkout);
             TryAgain = new Command(ConfirmTryAgain);
             EndWorkout = new Command(ConfirmEndWorkout);
-            State = WorkoutState.Playing;
             CurrentWorkout = workoutViewModel;
             SquatService = new SquatService()
             {
@@ -80,22 +78,6 @@ namespace Fitness.ViewModels
             }
         }
 
-        /// <summary>
-        /// Gets or sets a value indicating whether the loading view is visible and counting.
-        /// </summary>
-        public bool IsLoading
-        {
-            get => isLoading;
-            set
-            {
-                if (value != isLoading)
-                {
-                    isLoading = value;
-                    RaisePropertyChanged();
-                }
-            }
-        }
-
         /// <summary>
         /// Gets a title text of summary pop-up.
         /// </summary>
@@ -278,7 +260,7 @@ namespace Fitness.ViewModels
         {
             if (State == WorkoutState.Playing)
             {
-                State = WorkoutState.Paused;
+                State = WorkoutState.OnHold;
                 SummaryBackCommand = new Command(ExecuteCloseSummaryAndPlay);
             }
             else
@@ -315,9 +297,8 @@ namespace Fitness.ViewModels
 
         private void StartNewWorkout()
         {
-            State = WorkoutState.Playing;
+            State = WorkoutState.Loading;
             IsSummaryVisible = false;
-            IsLoading = true;
         }
 
         private string GetSummaryTitle(SummaryType type)
index b0bf819de4282da213208f7b673898eb694993db..65c69e3d115a46867a1d9a10959bb670745505ac 100644 (file)
@@ -15,27 +15,16 @@ namespace Fitness.Views
         /// <summary>
         /// Is workout playing bindable property.
         /// </summary>
-        public static readonly BindableProperty IsPlayingProperty = BindableProperty.Create(
-            "IsPlaying",
-            typeof(bool),
+        public static readonly BindableProperty WorkoutStateProperty = BindableProperty.Create(
+            "WorkoutState",
+            typeof(WorkoutState),
             typeof(ExercisingView),
-            true,
-            propertyChanged: OnIsPlayingChanged);
-
-        /// <summary>
-        /// Is workout loading bindable property.
-        /// </summary>
-        public static readonly BindableProperty IsLoadingProperty = BindableProperty.Create(
-            "IsLoading",
-            typeof(bool),
-            typeof(ExercisingView),
-            true,
-            propertyChanged: OnIsLoadingChanged);
+            WorkoutState.Loading,
+            propertyChanged: OnWorkoutStateChanged);
 
         private const int TransitionTime = 500;
         private CancellationTokenSource source;
         private bool isInitialized = false;
-        private bool isLoading = false;
         private (Coordinates Preview, Coordinates Camera) playing;
         private (Coordinates Preview, Coordinates Camera) pause =
         (
@@ -82,24 +71,11 @@ namespace Fitness.Views
             }
         }
 
-        private static void OnIsPlayingChanged(BindableObject bindable, object oldValue, object newValue)
+        private static void OnWorkoutStateChanged(BindableObject bindable, object oldValue, object newValue)
         {
-            if (newValue is bool isPlaying && bindable is ExercisingView view)
+            if (newValue is WorkoutState newState && oldValue is WorkoutState oldState && bindable is ExercisingView view)
             {
-                _ = view.TriggerStates(isPlaying);
-            }
-        }
-
-        private static void OnIsLoadingChanged(BindableObject bindable, object oldValue, object newValue)
-        {
-            if (newValue is bool isLoading && bindable is ExercisingView view)
-            {
-                view.isLoading = isLoading;
-
-                if (isLoading)
-                {
-                    view.RestartLoading();
-                }
+                view.ExecuteNewState(newState, oldState);
             }
         }
 
@@ -149,68 +125,168 @@ namespace Fitness.Views
             cameraView.Preview += DetectPreview;
         }
 
-        private async Task TriggerStates(bool isPlaying)
+        private void ExecuteNewState(WorkoutState newState, WorkoutState oldState)
+        {
+            if (!isInitialized)
+            {
+                return;
+            }
+
+            source?.Cancel();
+            source?.Dispose();
+            source = new CancellationTokenSource();
+
+            switch (newState)
+            {
+                case WorkoutState.Loading:
+                    _ = ExecuteLoadingSate(oldState);
+                    break;
+
+                case WorkoutState.Playing:
+                    _ = ExecutePlayingSate(oldState);
+                    break;
+
+                case WorkoutState.OnHold:
+                    ExecuteOnHoldSate(oldState);
+                    break;
+
+                case WorkoutState.Paused:
+                    _ = ExecutePausedSate(oldState);
+                    break;
+
+                default:
+                    Services.Logger.Warn("unhandled workout state");
+                    break;
+            }
+        }
+
+        private async Task ExecuteLoadingSate(WorkoutState oldState)
+        {
+            Preview.Stop();
+            LoadingView.Show();
+
+            switch (oldState)
+            {
+                case WorkoutState.OnHold:
+                    break;
+
+                case WorkoutState.Paused:
+                    (Task scalePreview, Task movePreview) = Animate(Preview, pause.Preview, playing.Preview, source.Token);
+                    (Task scaleCamera, Task moveCamera) = Animate(cameraOverlayView, pause.Camera, playing.Camera, source.Token);
+
+                    await Task.WhenAll(scalePreview, movePreview, scaleCamera, moveCamera);
+
+                    PauseView.Hide();
+                    PlayingView.Show();
+
+                    if (!source.IsCancellationRequested)
+                    {
+                        SetPositionAndSize(WorkoutState.Playing);
+                    }
+
+                    break;
+
+                default:
+                    Services.Logger.Warn("unhandled workout state");
+                    break;
+            }
+
+            LoadingView.StartLoading();
+            LoadingView.Loaded += OnLoaded;
+        }
+
+        private async Task ExecutePlayingSate(WorkoutState oldState)
         {
-            if (isInitialized)
+            switch (oldState)
             {
-                source?.Cancel();
-                source?.Dispose();
-                source = new CancellationTokenSource();
+                case WorkoutState.Loading:
+                case WorkoutState.OnHold:
+                    break;
 
-                if (isPlaying)
-                {
+                case WorkoutState.Paused:
                     (Task scalePreview, Task movePreview) = Animate(Preview, pause.Preview, playing.Preview, source.Token);
                     (Task scaleCamera, Task moveCamera) = Animate(cameraOverlayView, pause.Camera, playing.Camera, source.Token);
+
                     await Task.WhenAll(scalePreview, movePreview, scaleCamera, moveCamera);
 
                     PauseView.Hide();
                     PlayingView.Show();
-                    if (!isLoading)
+
+                    if (!source.IsCancellationRequested)
                     {
-                        Preview.Play();
+                        SetPositionAndSize(WorkoutState.Playing);
                     }
-                }
-                else
-                {
+
+                    break;
+
+                default:
+                    Services.Logger.Warn("unhandled workout state");
+                    break;
+            }
+
+            Preview.Play();
+        }
+
+        private void ExecuteOnHoldSate(WorkoutState oldState)
+        {
+            switch (oldState)
+            {
+                case WorkoutState.Playing:
+                    Preview.Pause();
+                    break;
+
+                default:
+                    Services.Logger.Warn("unhandled workout state");
+                    break;
+            }
+        }
+
+        private async Task ExecutePausedSate(WorkoutState oldState)
+        {
+            switch (oldState)
+            {
+                case WorkoutState.Playing:
+
                     Preview.Pause();
                     PlayingView.Hide();
                     PauseView.Show();
 
                     (Task scalePreview, Task movePreview) = Animate(Preview, playing.Preview, pause.Preview, source.Token);
                     (Task scaleCamera, Task moveCamera) = Animate(cameraOverlayView, playing.Camera, pause.Camera, source.Token);
+
                     await Task.WhenAll(scalePreview, movePreview, scaleCamera, moveCamera);
-                }
 
-                if (!source.IsCancellationRequested)
-                {
-                    SetPositionAndSize(isPlaying);
-                }
+                    if (!source.IsCancellationRequested)
+                    {
+                        SetPositionAndSize(WorkoutState.Paused);
+                    }
+
+                    break;
+
+                default:
+                    Services.Logger.Warn("unhandled workout state");
+                    break;
             }
         }
 
         private void OnPlayingViewRelayout(object sender, System.EventArgs e)
         {
-            UpdatePositionAndSize();
+            SetPositionAndSize();
+            PlayingView.PreviewStub.Relayout -= OnPlayingViewRelayout;
             isInitialized = true;
         }
 
-        private void RestartLoading()
-        {
-            Preview.Stop();
-            LoadingView.StartLoading();
-        }
-
         private void OnLoaded(object sender, System.EventArgs e)
         {
             if (BindingContext is ExercisingViewModel viewModel)
             {
-                viewModel.IsLoading = false;
+                viewModel.State = WorkoutState.Playing;
             }
 
-            Preview.Play();
+            LoadingView.Loaded -= OnLoaded;
         }
 
-        private void UpdatePositionAndSize()
+        private void SetPositionAndSize()
         {
             playing.Camera = new Coordinates()
             {
@@ -228,27 +304,15 @@ namespace Fitness.Views
             pause.Camera.Scale = pause.Camera.Size.Width / playing.Camera.Size.Width;
             pause.Preview.Scale = pause.Preview.Size.Width / playing.Preview.Size.Width;
 
-            SetPositionAndSize((bool)GetValue(IsPlayingProperty));
+            SetPositionAndSize((WorkoutState)GetValue(WorkoutStateProperty));
         }
 
-        private void SetPositionAndSize(bool isPlaying)
+        private void SetPositionAndSize(WorkoutState state)
         {
             cameraOverlayView.Size = playing.Camera.Size;
             Preview.Size = playing.Preview.Size;
 
-            if (isPlaying)
-            {
-                cameraOverlayView.Position = playing.Camera.Position;
-                cameraOverlayView.ScaleX = 1;
-                cameraOverlayView.ScaleY = 1;
-                Preview.Position = playing.Preview.Position;
-                Preview.ScaleX = 1;
-                Preview.ScaleY = 1;
-
-                PauseView.Hide();
-                PlayingView.Show();
-            }
-            else
+            if (state == WorkoutState.Paused)
             {
                 var cameraScale = pause.Camera.Size.Width / playing.Camera.Size.Width;
                 cameraOverlayView.Position = pause.Camera.Position;
@@ -265,6 +329,18 @@ namespace Fitness.Views
                 PlayingView.Hide();
                 PauseView.Show();
             }
+            else
+            {
+                cameraOverlayView.Position = playing.Camera.Position;
+                cameraOverlayView.ScaleX = 1;
+                cameraOverlayView.ScaleY = 1;
+                Preview.Position = playing.Preview.Position;
+                Preview.ScaleX = 1;
+                Preview.ScaleY = 1;
+
+                PauseView.Hide();
+                PlayingView.Show();
+            }
         }
 
         private void DetectPreview(object sender, PreviewEventArgs e)
index deb64a75cdf25ef3ead94d25485c4306383c3037..fdd427fd5ad6d2bc0886377109d2392d2be1510d 100644 (file)
@@ -9,8 +9,7 @@
            xmlns:behaviors="clr-namespace:Fitness.Views.Behaviors"
            x:Name="Root"
            BackgroundColor="#EEEFF1"
-           IsPlaying="{Binding State, Converter={x:Static converters:WorkoutStateToBoolConverter.Converter}}"
-           IsLoading="{Binding IsLoading}">
+           WorkoutState="{Binding State}">
 
     <views:PlayingView x:Name="PlayingView"
                        BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"/>