/// </summary>
public void StopPreview() => camera.StopPreview();
+ /// <summary>
+ /// Starts capturing and drawing preview frames on the screen.
+ /// </summary>
+ public void StartPreview() => camera.StartPreview();
+
/// <summary>
/// Dispose.
/// </summary>
using System;
using System.Threading.Tasks;
using Fitness.Controls;
+using Fitness.Models;
+using Fitness.ViewModels;
using Fitness.Views;
using Tizen.NUI;
navigation.Push(new MainView());
}
- public void NavigateToExercisingView()
+ public async Task NavigateToExercisingView(WorkoutViewModel workoutViewModel)
{
- navigation.Push(new ExercisingView());
+ var result = await PrivilegeService.Instance.CheckCameraPrivilege();
+ if (result == Tizen.Security.RequestResult.AllowForever)
+ {
+ var view = new ExercisingView()
+ {
+ BindingContext = new ExercisingViewModel(workoutViewModel),
+ };
+ navigation.Push(view);
+ }
}
public void NavigateToExercisePreviewView(string workoutId)
}
}
- public async Task NavigateToLoadingView()
+ public void NavigateToSummaryView(SummaryType summaryType, WorkoutViewModel workoutViewModel)
{
- navigation.HideLast();
- var result = await PrivilegeService.Instance.CheckCameraPrivilege();
- navigation.ShowLast();
- if (result == Tizen.Security.RequestResult.AllowForever)
+ var view = new SummaryView()
{
- navigation.Push(new LoadingView());
- }
- }
-
- public void NavigateToSummaryView()
- {
- navigation.Push(new SummaryView());
+ BindingContext = new SummaryViewModel(summaryType, workoutViewModel),
+ };
+ navigation.Push(view);
}
public void Pop()
--- /dev/null
+using System.Collections.Generic;
+using System.Windows.Input;
+using Fitness.Services;
+using Tizen.NUI.Binding;
+
+namespace Fitness.ViewModels
+{
+ /// <summary>
+ /// Class handling the workout change.
+ /// </summary>
+ public abstract class ChangeWorkoutViewModel : BaseViewModel
+ {
+ private WorkoutViewModel currentWorkout;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ChangeWorkoutViewModel"/> class.
+ /// </summary>
+ public ChangeWorkoutViewModel()
+ {
+ PreviousWorkout = new Command(GoPrevious);
+ NextWorkout = new Command(GoNext);
+
+ Workouts = WorkoutRepository.Instance.GetAll();
+ }
+
+ /// <summary>
+ /// Gets or sets review movement.
+ /// </summary>
+ public WorkoutViewModel CurrentWorkout
+ {
+ get => currentWorkout;
+ set
+ {
+ if (value != currentWorkout)
+ {
+ currentWorkout = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets previous workout.
+ /// </summary>
+ public ICommand PreviousWorkout { get; private set; }
+
+ /// <summary>
+ /// Gets next workout.
+ /// </summary>
+ public ICommand NextWorkout { get; private set; }
+
+ /// <summary>
+ /// Gets list of all available workouts.
+ /// </summary>
+ public IList<WorkoutViewModel> Workouts { get; private set; }
+
+ /// <summary>
+ /// Go to next workout.
+ /// </summary>
+ protected virtual void GoNext()
+ {
+ MoveBy(1);
+ }
+
+ /// <summary>
+ /// Go to previous workout.
+ /// </summary>
+ protected virtual void GoPrevious()
+ {
+ MoveBy(-1);
+ }
+
+ private void MoveBy(int offset)
+ {
+ int idx = Workouts.IndexOf(CurrentWorkout) + offset;
+ if (idx >= 0 && idx < Workouts.Count)
+ {
+ CurrentWorkout = Workouts[idx];
+ }
+ }
+ }
+}
namespace Fitness.ViewModels
{
- public class ExercisePreviewViewModel : BaseViewModel
+ public class ExercisePreviewViewModel : ChangeWorkoutViewModel
{
- private WorkoutViewModel currentWorkout;
-
public ExercisePreviewViewModel()
{
- Skip = new Command(NavigationService.Instance.NavigateToExercisingView);
+ Skip = new Command(() => { _ = NavigationService.Instance.NavigateToExercisingView(CurrentWorkout); });
Back = new Command(NavigationService.Instance.Pop);
- PreviousWorkout = new Command(GoPrevious);
- NextWorkout = new Command(GoNext);
-
- Workouts = WorkoutRepository.Instance.GetAll();
- }
-
- /// <summary>
- /// Review movement
- /// </summary>
- public WorkoutViewModel CurrentWorkout
- {
- get => currentWorkout;
- set
- {
- if (value != currentWorkout)
- {
- currentWorkout = value;
- RaisePropertyChanged();
- }
- }
}
/// <summary>
/// Skip review
/// </summary>
public ICommand Skip { get; private set; }
-
- /// <summary>
- /// previous workout
- /// </summary>
- public ICommand PreviousWorkout { get; private set; }
-
- /// <summary>
- /// next workout
- /// </summary>
- public ICommand NextWorkout { get; private set; }
-
- /// <summary>
- /// List of all available workouts
- /// </summary>
- public IList<WorkoutViewModel> Workouts { get; private set; }
-
- private void GoNext()
- {
- MoveBy(1);
- }
-
- private void GoPrevious()
- {
- MoveBy(-1);
- }
-
- private void MoveBy(int offset)
- {
- int idx = Workouts.IndexOf(CurrentWorkout) + offset;
- if (idx >= 0 && idx < Workouts.Count)
- {
- CurrentWorkout = Workouts[idx];
- }
- }
}
}
namespace Fitness.ViewModels
{
- public class ExercisingViewModel : BaseViewModel
+ public class ExercisingViewModel : ChangeWorkoutViewModel
{
private WorkoutState state;
- public ExercisingViewModel()
+ public ExercisingViewModel(WorkoutViewModel workoutViewModel)
{
PauseResumeWorkout = new Command(TriggerPauseResumeWorkout);
+ TryAgain = new Command(ExecuteTryAgain);
EndWorkout = new Command(ExecuteEndWorkout);
- Prev = new Command(ExecutePrev);
- Next = new Command(ExecuteNext);
State = WorkoutState.Playing;
+ CurrentWorkout = workoutViewModel;
}
- /// <summary>
- /// Gets title.
- /// </summary>
- public string Title { get; private set; } = "Sit-up";
-
/// <summary>
/// Current score
/// </summary>
public ICommand PauseResumeWorkout { get; private set; }
/// <summary>
- /// Gets ReviewMovement Command.
+ /// Gets TryAgain Command.
/// </summary>
- public ICommand ReviewMovement { get; private set; }
+ public ICommand TryAgain { get; private set; }
/// <summary>
/// Gets EndWorkout Command.
public string PauseResumeLabel { get; private set; } = "Pause";
+ protected override void GoPrevious()
+ {
+ Services.NavigationService.Instance.NavigateToSummaryView(SummaryType.ChangeToPreviousWorkout, CurrentWorkout);
+ }
+
+ protected override void GoNext()
+ {
+ Services.NavigationService.Instance.NavigateToSummaryView(SummaryType.ChangeToNextWorkout, CurrentWorkout);
+ }
+
private void TriggerPauseResumeWorkout()
{
if (State == WorkoutState.Paused)
}
}
- private void ExecuteEndWorkout()
+ private void ExecuteTryAgain()
{
- Services.NavigationService.Instance.NavigateToSummaryView();
+ Services.NavigationService.Instance.NavigateToSummaryView(SummaryType.TryAgain, CurrentWorkout);
}
- private void ExecutePrev()
- {
- }
-
- private void ExecuteNext()
+ private void ExecuteEndWorkout()
{
+ Services.NavigationService.Instance.NavigateToSummaryView(SummaryType.EndWorkout, CurrentWorkout);
}
}
}
--- /dev/null
+namespace Fitness.Models
+{
+ /// <summary>
+ /// Type of summary view.
+ /// </summary>
+ public enum SummaryType
+ {
+ /// <summary>
+ /// End workout.
+ /// </summary>
+ EndWorkout,
+
+ /// <summary>
+ /// Change to the next workout.
+ /// </summary>
+ ChangeToNextWorkout,
+
+ /// <summary>
+ /// Change to the previous workout.
+ /// </summary>
+ ChangeToPreviousWorkout,
+
+ /// <summary>
+ /// Try again.
+ /// </summary>
+ TryAgain,
+
+ /// <summary>
+ /// Time's up.
+ /// </summary>
+ TimeIsUp,
+ }
+}
using System;
+using System.Collections.Generic;
using System.Windows.Input;
+using Fitness.Models;
using Fitness.Services;
using Tizen.NUI.Binding;
/// </summary>
public class SummaryViewModel : BaseViewModel
{
+ private const string EndWorkoutTitle = "The current session will be stopped.";
+ private const string ChangeWorkoutTitle = "Do you want to change workout?";
+ private const string TryAgainTitle = "Do you want to try again?";
+ private const string TimeIsUpTitle = "Great job!";
+
+ private SummaryType currentSummaryType;
+ private string title;
+ private Dictionary<SummaryType, string> summaryTitleMap;
+ private ICommand ok;
+
/// <summary>
/// Initializes a new instance of the <see cref="SummaryViewModel"/> class.
/// </summary>
- public SummaryViewModel()
+ public SummaryViewModel(SummaryType summaryType, WorkoutViewModel workoutViewModel)
{
Back = new Command(() => { NavigationService.Instance.Pop(); });
- Ok = new Command(() => { NavigationService.Instance.NavigateToMainView(); });
+ InitializeTitleMap();
+ UpdateTitle();
+ SetOkCommand();
+ CurrentSummaryType = summaryType;
+ CurrentWorkout = workoutViewModel;
+ Workouts = WorkoutRepository.Instance.GetAll();
}
/// <summary>
/// <summary>
/// Gets Ok command.
/// </summary>
- public ICommand Ok { get; private set; }
+ public ICommand Ok
+ {
+ get => ok;
+ private set
+ {
+ if (ok != value)
+ {
+ ok = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the current summary type.
+ /// </summary>
+ public SummaryType CurrentSummaryType
+ {
+ get => currentSummaryType;
+ set
+ {
+ if (value != currentSummaryType)
+ {
+ currentSummaryType = value;
+ RaisePropertyChanged();
+ }
+
+ UpdateTitle();
+ SetOkCommand();
+ }
+ }
+
+ /// <summary>
+ /// Gets list of all available workouts.
+ /// </summary>
+ public IList<WorkoutViewModel> Workouts { get; private set; }
/// <summary>
/// Gets title.
/// </summary>
- public string Title { get; private set; } = "Great job!";
+ public string Title
+ {
+ get => title;
+ private set
+ {
+ if (title != value)
+ {
+ title = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
/// <summary>
/// Gets TotalTime.
/// Gets AverageScore.
/// </summary>
public int AverageScore { get; private set; } = 98;
+
+ /// <summary>
+ /// Gets current workout.
+ /// </summary>
+ public WorkoutViewModel CurrentWorkout { get; internal set; }
+
+ private void InitializeTitleMap()
+ {
+ summaryTitleMap = new Dictionary<SummaryType, string>
+ {
+ { SummaryType.EndWorkout, EndWorkoutTitle },
+ { SummaryType.ChangeToPreviousWorkout, ChangeWorkoutTitle },
+ { SummaryType.ChangeToNextWorkout, ChangeWorkoutTitle },
+ { SummaryType.TryAgain, TryAgainTitle },
+ { SummaryType.TimeIsUp, TimeIsUpTitle },
+ };
+ }
+
+ private void UpdateTitle()
+ {
+ if (summaryTitleMap.TryGetValue(currentSummaryType, out string title))
+ {
+ Title = title;
+ }
+ }
+
+ private void SetOkCommand()
+ {
+ switch (currentSummaryType)
+ {
+ case SummaryType.ChangeToPreviousWorkout:
+ Ok = new Command(() => { ChangeWorkout(-1); });
+ break;
+ case SummaryType.ChangeToNextWorkout:
+ Ok = new Command(() => { ChangeWorkout(1); });
+ break;
+ case SummaryType.TryAgain:
+ Ok = new Command(() => { ChangeWorkout(); });
+ break;
+ case SummaryType.EndWorkout:
+ case SummaryType.TimeIsUp:
+ default:
+ Ok = new Command(() =>
+ {
+ NavigationService.Instance.Pop();
+ NavigationService.Instance.NavigateToMainView();
+ });
+ break;
+ }
+ }
+
+ private void ChangeWorkout(int offset = 0)
+ {
+ WorkoutViewModel nextWorkout;
+
+ int idx = Workouts.IndexOf(CurrentWorkout) + offset;
+ if (idx >= 0 && idx < Workouts.Count)
+ {
+ nextWorkout = Workouts[idx];
+ }
+ else
+ {
+ nextWorkout = CurrentWorkout;
+ }
+
+ NavigationService.Instance.Pop();
+ NavigationService.Instance.Pop();
+ _ = NavigationService.Instance.NavigateToExercisingView(nextWorkout);
+ }
}
}
null,
propertyChanged: OnNextCommandChanged);
+ /// <summary>
+ /// Title bindable property.
+ /// </summary>
+ public static readonly BindableProperty TitleProperty = BindableProperty.Create(
+ "Title",
+ typeof(string),
+ typeof(BarView),
+ null,
+ propertyChanged: OnTitleChanged);
+
public BarView()
{
InitializeComponent();
view.next.Command = command;
}
}
+
+ private static void OnTitleChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ if (bindable is BarView view && newValue is string title)
+ {
+ view.title.Text = title;
+ }
+ }
}
}
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Fitness.Models;
+using Fitness.ViewModels;
using Tizen.NUI;
using Tizen.NUI.BaseComponents;
using Tizen.NUI.Binding;
Size = new Size(500, 292),
});
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ExercisingView"/> class.
+ /// </summary>
public ExercisingView()
{
- InitializeComponent();
-
- PlayingView.PreviewStub.Relayout += OnPlayingViewRelayout;
+ Initialize();
}
/// <summary>
}
}
+ /// <summary>
+ /// OnAppearing.
+ /// </summary>
+ protected override void OnAppearing()
+ {
+ if (cameraView.PreviewState == Tizen.Multimedia.CameraState.Created || cameraView.PreviewState == Tizen.Multimedia.CameraState.Captured)
+ {
+ cameraView.StartPreview();
+ }
+ }
+
private static void OnIsPlayingChanged(BindableObject bindable, object oldValue, object newValue)
{
if (newValue is bool isPlaying && bindable is ExercisingView view)
return position;
}
+ private void Initialize()
+ {
+ InitializeComponent();
+
+ PlayingView.PreviewStub.Relayout += OnPlayingViewRelayout;
+ }
+
private async Task TriggerStates(bool isPlaying)
{
if (isInitialized)
Position="{views:PositionInUnits X=17, Y=10}"
Size="{views:SizeInUnits Width=64, Height=20}"
behaviors:StyleSetter.Style="{x:Static styles:Buttons.Previous}"/>
- <TextLabel BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"
- Text="{Binding Title}"
+ <TextLabel x:Name="title"
TextColor="#000C2B"
PixelSize="32"
HorizontalAlignment="Center"
- Position="{views:PositionInUnits X=220, Y=15}"
- Size="{views:SizeInUnits Width=40, Height=10}"/>
+ Position="{views:PositionInUnits X=190, Y=15}"
+ Size="{views:SizeInUnits Width=100, Height=10}"/>
<ctrl:NinePatchButton Text="next"
x:Name="next"
Position="{views:PositionInUnits X=400, Y=10}"
x:Name="Root"
BackgroundColor="#EEEFF1"
IsPlaying="{Binding State, Converter={x:Static converters:WorkoutStateToBoolConverter.Converter}}">
- <View.BindingContext>
- <vm:ExercisingViewModel/>
- </View.BindingContext>
<views:PlayingView x:Name="PlayingView"
BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"/>
<!--Layer-->
BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"/>
<!--Layer-->
<views:BarView BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"
- PrevCommand="{Binding Prev}"
- NextCommand="{Binding Next}"/>
+ PrevCommand="{Binding PreviousWorkout}"
+ NextCommand="{Binding NextWorkout}"
+ Title="{Binding CurrentWorkout.Title}"/>
<views:LoadingView x:Name="LoadingView"/>
</ctrl:Page>
<ctrl:NinePatchButton BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"
HeightSpecification="-1"
WidthSpecification="-1"
- Text="Review movement"
+ Text="Try again"
Weight="1"
- Command="{Binding ReviewMovement}"
+ Command="{Binding TryAgain}"
behaviors:StyleSetter.Style="{Binding Source={x:Static styles:Buttons.ReviewMovement}}"/>
<View HeightSpecification="-1"
WidthSpecification="-1"
xmlns:behaviors="clr-namespace:Fitness.Views.Behaviors"
xmlns:styles="clr-namespace:Fitness.Views.Styles"
x:Name="Root">
- <View.BindingContext>
- <vm:SummaryViewModel/>
- </View.BindingContext>
<ImageView HeightSpecification="-1"
WidthSpecification="-1"
ResourceUrl="*Resource*/layout/images/0_BG_dim.png">
<View.Layout>
<LinearLayout LinearOrientation="Vertical"/>
</View.Layout>
- <View Size="{views:SizeInUnits Height=10}"/>
+ <View Size="{views:SizeInUnits Height=10}" HeightSpecification="-1"/>
<TextLabel BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"
Text="{Binding Title}"
PixelSize="40"
WidthSpecification="-1"
+ HeightSpecification="-1"
Size="{views:SizeInUnits Height=14}"
HorizontalAlignment="Center"
TextColor="#000C2B"/>
- <View WidthSpecification="-1"
+ <View WidthSpecification="-1" HeightSpecification="-1"
Weight="1"/>
<TextLabel Text="Your session summary:"
PixelSize="32"
WidthSpecification="-1"
+ HeightSpecification="-1"
Margin="{views:ExtentsInUnits Start=27}"
Size="{views:SizeInUnits Height=11}"
HorizontalAlignment="Begin"
TextColor="#000C2B"/>
<View Size="{views:SizeInUnits Height=7}"/>
- <View WidthSpecification="-1">
+ <View WidthSpecification="-1" >
<View.Layout>
<LinearLayout LinearOrientation="Horizontal"/>
</View.Layout>
- <TextLabel Text="Total time"
+ <View WidthSpecification="-1">
+ <TextLabel Text="Total time"
HorizontalAlignment="End"
Weight="1"
PixelSize="32"
Size="{views:SizeInUnits Height=11}"/>
+ </View>
<View Size="{views:SizeInUnits Width=11}"/>
<TextLabel BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"
Text="{Binding TotalTime, StringFormat='{0:m\\:ss}'}"
<View.Layout>
<LinearLayout LinearOrientation="Horizontal"/>
</View.Layout>
- <TextLabel Text="Total count"
+ <View WidthSpecification="-1">
+ <TextLabel Text="Total count"
HorizontalAlignment="End"
Weight="1"
PixelSize="32"
Size="{views:SizeInUnits Height=11}"/>
+ </View>
<View Size="{views:SizeInUnits Width=11}"/>
<TextLabel BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"
Text="{Binding TotalCount}"
<View.Layout>
<LinearLayout LinearOrientation="Horizontal"/>
</View.Layout>
- <TextLabel Text="Average score"
+ <View WidthSpecification="-1">
+ <TextLabel Text="Average score"
HorizontalAlignment="End"
Weight="1"
PixelSize="32"
Size="{views:SizeInUnits Height=11}"/>
+ </View>
<View Size="{views:SizeInUnits Width=11}"/>
<TextLabel BindingContext="{Binding Source={x:Reference Root}, Path=BindingContext}"
Text="{Binding AverageScore}"
PixelSize="32"
Size="{views:SizeInUnits Height=11}"/>
</View>
- <View WidthSpecification="-1"
+ <View WidthSpecification="-1" HeightSpecification="-1"
Weight="1"/>
<View WidthSpecification="-1">
<View.Layout>