--- /dev/null
+using System.Collections.Generic;
+using Fitness.Services;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Components;
+
+namespace Fitness.Controls
+{
+ public class BindableRecyclerView : RecyclerView
+ {
+ public static readonly BindableProperty ItemsSourceProperty =
+ BindableProperty.Create(nameof(ItemsSource), typeof(List<object>), typeof(BindableRecyclerView), null, propertyChanged: OnItemsSourceChanged);
+
+ public static readonly BindableProperty SelectedItemProperty =
+ BindableProperty.Create(nameof(SelectedItem), typeof(object), typeof(BindableRecyclerView), null, propertyChanged: OnSelectedItemChanged);
+
+ public BindableRecyclerView()
+ : base(new RecycleAdapter(), new LinearRecycleLayoutManager())
+ {
+ // TODO workaround orientation set bug
+ LayoutManager.LayoutOrientation = RecycleLayoutManager.Orientation.Horizontal;
+ }
+
+ public List<object> ItemsSource
+ {
+ get => (List<object>)GetValue(ItemsSourceProperty);
+ set
+ {
+ SetValue(ItemsSourceProperty, value);
+ }
+ }
+
+ public object SelectedItem
+ {
+ get => (object)GetValue(SelectedItemProperty);
+ set
+ {
+ SetValue(SelectedItemProperty, value);
+ }
+ }
+
+ public static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var recycler = bindable as BindableRecyclerView;
+ if (recycler != null && recycler.Adapter != null)
+ {
+ var newList = newValue as List<object>;
+ recycler.Adapter.Data = newList;
+
+ // Set selected item by default on first item
+ if (newList.Count > 0)
+ {
+ recycler.SelectedItem = newList[0];
+ }
+ }
+ }
+
+ public static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var recycler = bindable as BindableRecyclerView;
+ if (recycler != null && recycler.Adapter != null)
+ {
+ recycler.SelectedItem = newValue;
+ }
+ }
+ }
+}
using System;
using System.Collections.Generic;
-using System.Windows.Input;
using Fitness.Models;
using Fitness.Services;
using Tizen.Applications;
{
public class MainViewModel : BaseViewModel
{
- private WorkoutViewModel selectedWorkout;
-
public MainViewModel()
{
Workouts = new List<object>(new[]
ThumbnailUrl = Application.Current.DirectoryInfo.Resource + "media/video-0002.jpeg",
},
});
-
- WatchPreview = new Command(() => { NavigationService.Instance.NavigateToExercisePreviewView(); });
- StartWorkout = new Command(() => { NavigationService.Instance.NavigateToExercisingView(); });
- SelectedWorkout = Workouts[0] as WorkoutViewModel;
}
/// <summary>
/// List of all available workouts
/// </summary>
public List<object> Workouts { get; private set; }
-
- /// <summary>
- /// Currently selected workout
- /// </summary>
- public WorkoutViewModel SelectedWorkout
- {
- get => selectedWorkout;
- set
- {
- if (value != selectedWorkout)
- {
- selectedWorkout = value;
- RaisePropertyChanged();
- }
- }
- }
-
- /// <summary>
- /// Stop workout
- /// </summary>
- public ICommand WatchPreview { get; private set; }
-
- /// <summary>
- /// Start selected workout.
- /// </summary>
- public ICommand StartWorkout { get; private set; }
}
}
using System;
using System.Windows.Input;
using Fitness.Models;
+using Fitness.Services;
using Fitness.ViewModels;
+using Tizen.NUI.Binding;
-namespace Fitness.Models
+namespace Fitness.ViewModels
{
/// <summary>
/// WorkoutViewModel's information.
/// </summary>
public class WorkoutViewModel : BaseViewModel
{
+ public WorkoutViewModel()
+ {
+ WatchPreview = new Command(() => { NavigationService.Instance.NavigateToExercisePreviewView(); });
+ StartWorkout = new Command(() => { NavigationService.Instance.NavigateToScanningView(); });
+ }
+
/// <summary>
/// Current score
/// </summary>
/// Url to workout video
/// </summary>
public string VideoUrl { get; set; }
+
+ /// <summary>
+ /// Stop workout
+ /// </summary>
+ public ICommand WatchPreview { get; private set; }
+
+ /// <summary>
+ /// Start selected workout.
+ /// </summary>
+ public ICommand StartWorkout { get; private set; }
}
}
--- /dev/null
+using Fitness.Services;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Components;
+
+namespace Fitness.Views
+{
+ public partial class FitnessItemView : RecycleItem
+ {
+ public FitnessItemView()
+ {
+ InitializeComponent();
+ }
+ }
+}
--- /dev/null
+using Fitness.Services;
+using Tizen.NUI;
+using Tizen.NUI.Components;
+
+namespace Fitness.Views
+{
+ public class FitnessItemViewRecycleAdapter : RecycleAdapter
+ {
+ public FitnessItemViewRecycleAdapter()
+ {
+ }
+
+ public override RecycleItem CreateRecycleItem()
+ {
+ return new FitnessItemView();
+ }
+
+ public override void BindData(RecycleItem item)
+ {
+ item.BindingContext = Data[item.DataIndex];
+ if (item is FitnessItemView fitnessItem)
+ {
+ fitnessItem.image.BindingContext = item.BindingContext;
+ fitnessItem.label.BindingContext = item.BindingContext;
+ fitnessItem.favourite.BindingContext = item.BindingContext;
+ }
+ }
+ }
+}
using Fitness.Controls;
using Tizen.NUI;
using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Components;
namespace Fitness.Views
{
this.button1.ApplyStyle(Styles.Buttons.Inverse);
this.button2.ApplyStyle(Styles.Buttons.Regular);
+ this.scroller.ScrollingDirection = ScrollableBase.Direction.Horizontal;
}
}
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<nui:RecycleItem x:Class="Fitness.Views.FitnessItemView"
+ xmlns="http://tizen.org/Tizen.NUI/2018/XAML"
+ xmlns:nui="clr-namespace:Tizen.NUI.Components"
+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+ xmlns:views="clr-namespace:Fitness.Views"
+ xmlns:converters="clr-namespace:Fitness.Views.Converters"
+ Size="{views:SizeInUnits Width=82,Height=44}">
+ <View Size="{views:SizeInUnits Width=78,Height=44}" >
+ <ImageView x:Name="image" HeightResizePolicy="FillToParent" WidthResizePolicy="FillToParent" ResourceUrl="{Binding ThumbnailUrl}"/>
+ <TextLabel x:Name="label" PositionUsesPivotPoint="true" PivotPoint="0.0,1.0" ParentOrigin="0.0,1.0" PointSize="24" Text="{Binding Title}"/>
+ <ImageView x:Name="favourite" Size="30,30" PositionUsesPivotPoint="true" PivotPoint="1.0,0.0" ParentOrigin="1.0,0.0" ResourceUrl="{Binding Favourite, Converter={StaticResource favouriteToIconConverter}}"/>
+ </View>
+</nui:RecycleItem>
<converters:FavouriteToIconConverter x:Key="favouriteToIconConverter"/>
</View.XamlResources>
<View.BindingContext>
- <vm:MainViewModel x:Name="mainViewModel">
- </vm:MainViewModel>
+ <vm:MainViewModel/>
</View.BindingContext>
<View.Layout>
<LinearLayout LinearOrientation="Vertical" LinearAlignment="Top"/>
</View.Layout>
- <View BindingContext="{x:Reference mainViewModel}" Margin="{views:ExtentsInUnits Start=16,End=16}" Weight="1.0" WidthResizePolicy="FillToParent" >
+ <View Margin="{views:ExtentsInUnits Start=16,End=16}" Weight="1.0" WidthResizePolicy="FillToParent" >
<View.Layout>
<LinearLayout LinearOrientation="Horizontal" LinearAlignment="End"/>
</View.Layout>
- <ImageView BindingContext="{Binding SelectedWorkout}" Weight="1.0" HeightResizePolicy="FillToParent" ResourceUrl="{Binding ThumbnailUrl}">
+ <ImageView BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" Weight="1.0" HeightResizePolicy="FillToParent" ResourceUrl="{Binding ThumbnailUrl}">
<ImageView.Layout>
<LinearLayout LinearOrientation="Vertical" LinearAlignment="Center"/>
</ImageView.Layout>
- <nui:Button BindingContext="{x:Reference mainViewModel}" BackgroundColor="Red" PositionUsesPivotPoint="true" ParentOrigin="0.5,0.5" PivotPoint="0.5,0.5" Text="Let's try!" Command="{Binding StartWorkout}" x:Name="button1" Size="{views:SizeInUnits Width=112,Height=24}"/>
- <nui:Button BindingContext="{x:Reference mainViewModel}" PositionUsesPivotPoint="true" ParentOrigin="0.5,0.5" PivotPoint="0.5,0.5" Text="Watch preview" Command="{Binding WatchPreview}" x:Name="button2" Size="{views:SizeInUnits Width=112,Height=24}"/>
+ <nui:Button BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" PositionUsesPivotPoint="true" ParentOrigin="0.5,0.5" PivotPoint="0.5,0.5" Text="Let's try!" Command="{Binding StartWorkout}" x:Name="button1" Size="{views:SizeInUnits Width=112,Height=24}"/>
+ <nui:Button BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" PositionUsesPivotPoint="true" ParentOrigin="0.5,0.5" PivotPoint="0.5,0.5" Text="Watch preview" Command="{Binding WatchPreview}" x:Name="button2" Size="{views:SizeInUnits Width=112,Height=24}"/>
</ImageView>
- <View Size="{views:SizeInUnits Width=107}" Margin="{views:ExtentsInUnits Start=8}" HeightResizePolicy="FillToParent" BindingContext="{x:Reference mainViewModel}">
- <View HeightResizePolicy="FillToParent" WidthResizePolicy="FillToParent" BindingContext="{x:Reference mainViewModel}">
+ <View Size="{views:SizeInUnits Width=107}" Margin="{views:ExtentsInUnits Start=8}" HeightResizePolicy="FillToParent">
+ <View HeightResizePolicy="FillToParent" WidthResizePolicy="FillToParent">
<View.Layout>
<LinearLayout LinearOrientation="Vertical" LinearAlignment="Begin"/>
</View.Layout>
- <View BindingContext="{x:Reference mainViewModel}">
+ <View>
<View.Layout>
<LinearLayout LinearOrientation="Horizontal" LinearAlignment="Begin"/>
</View.Layout>
- <TextLabel BindingContext="{Binding SelectedWorkout}" Text="{Binding Path=Title}" PointSize="40" VerticalAlignment="Center" TextColor="#000C2B"/>
- <ImageView BindingContext="{Binding SelectedWorkout}" Size="36,48" Margin="30,30,0,0" ResourceUrl="{Binding Difficulty, Converter={StaticResource difficultyLevelConverter}}"/>
+ <TextLabel BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" Text="{Binding Path=Title}" PointSize="40" VerticalAlignment="Center" TextColor="#000C2B"/>
+ <ImageView BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" Size="36,48" Margin="30,30,0,0" ResourceUrl="{Binding Difficulty, Converter={StaticResource difficultyLevelConverter}}"/>
</View>
- <View BindingContext="{x:Reference mainViewModel}">
+ <View>
<View.Layout>
<LinearLayout LinearOrientation="Horizontal" LinearAlignment="Begin"/>
</View.Layout>
<ImageView Size="28,28" ResourceUrl="*Resource*/layout/images/icon_time.png"/>
- <TextLabel BindingContext="{Binding SelectedWorkout}" Text="{Binding Duration,StringFormat=\{0:h\\:mm\\:ss\}}" PointSize="28" Margin="8,0,0,0" VerticalAlignment="Center" TextColor="#000C2B"/>
+ <TextLabel BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" Text="{Binding Duration,StringFormat=\{0:h\\:mm\\:ss\}}" PointSize="28" Margin="8,0,0,0" VerticalAlignment="Center" TextColor="#000C2B"/>
</View>
- <TextLabel BindingContext="{Binding SelectedWorkout}" Size="{views:SizeInUnits Width=107}" Text="{Binding Description}" PointSize="28" LineWrapMode="Word" Weight="1.0" VerticalAlignment="Bottom" Ellipsis="false" MultiLine="true" TextColor="#000C2B" EnableAutoScroll="true"/>
+ <TextLabel BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" Size="{views:SizeInUnits Width=107}" Text="{Binding Description}" PointSize="28" LineWrapMode="Word" Weight="1.0" VerticalAlignment="Bottom" Ellipsis="false" MultiLine="true" TextColor="#000C2B" EnableAutoScroll="true"/>
</View>
- <ImageView PositionUsesPivotPoint="true" PivotPoint="1.0,0.0" ParentOrigin="1.0, 0.0" Size="30,30" BindingContext="{Binding SelectedWorkout}" ResourceUrl="{Binding Favourite, Converter={StaticResource favouriteToIconConverter}}"/>
+ <ImageView PositionUsesPivotPoint="true" PivotPoint="1.0,0.0" ParentOrigin="1.0, 0.0" Size="30,30" BindingContext="{Binding Source={x:Reference scroller}, Path=SelectedItem}" ResourceUrl="{Binding Favourite, Converter={StaticResource favouriteToIconConverter}}"/>
</View>
</View>
- <View Size="{views:SizeInUnits Height=44}" Margin="{views:ExtentsInUnits Top=10, Bottom=10}" WidthResizePolicy="FillToParent">
- </View>
+ <ctrl:BindableRecyclerView Size="{views:SizeInUnits Height=44}" Margin="{views:ExtentsInUnits Top=10, Bottom=10}" WidthResizePolicy="FillToParent" ItemsSource="{Binding Workouts}" x:Name="scroller" Padding="{views:ExtentsInUnits Start=16, End=16}">
+ <ctrl:BindableRecyclerView.Adapter>
+ <views:FitnessItemViewRecycleAdapter/>
+ </ctrl:BindableRecyclerView.Adapter>
+ </ctrl:BindableRecyclerView>
</ctrl:Page>