public abstract class BaseTransition : ITransition
{
/// <summary>
- ///
+ /// Event triggered when animation has started.
/// </summary>
public event EventHandler TransitionStarted;
/// <summary>
- ///
+ /// Event triggered when animation has finished.
/// </summary>
public event EventHandler TransitionFinished;
/// <summary>
- ///
- /// </summary>
- public event EventHandler TransitionCancelled;
-
- /// <summary>
/// Transition duration (in milliseconds)
/// </summary>
public int Duration { get; set; }
/// <summary>
- ///
+ /// Start transition on target view.
/// </summary>
public virtual void Transit(View target)
{
}
+ public virtual void Dispose()
+ {
+ }
+
/// <summary>
/// Raises TransitionStarted event
/// </summary>
{
TransitionFinished?.Invoke(this, null);
}
-
- /// <summary>
- /// Raises TransitionCancelled event
- /// </summary>
- protected void RaiseTransitionCancelled()
- {
- TransitionCancelled?.Invoke(this, null);
- }
-
- public virtual void Dispose()
- {
- }
}
}
-
public static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
- Logger.Debug("");
var recycler = bindable as BindableRecyclerView;
if (recycler != null && recycler.Adapter != null)
{
- Logger.Debug("");
var enumerable = newValue as IEnumerable;
var enumerator = enumerable?.GetEnumerator();
var list = new List<object>();
while ((enumerator != null) && enumerator.MoveNext())
{
- Logger.Debug($"Item: {enumerator.Current.GetHashCode()}");
- if (enumerator.Current is WorkoutViewModel)
- {
- Logger.Debug($"enumerator.Current is WorkoutViewModel)");
- }
list.Add(enumerator.Current);
}
- Logger.Debug($"list.Count: {list.Count}");
recycler.Adapter.Data = list;
// Set selected item by default on first item
-using Tizen.NUI.Binding;
using Tizen.NUI.BaseComponents;
-
-using Fitness.Services;
+using Tizen.NUI.Binding;
namespace Fitness.Controls
{
/// Connected animation id, bindable property.
/// </summary>
public static readonly BindableProperty IdProperty =
- BindableProperty.CreateAttached("Id", typeof(string), typeof(View), null);
+ BindableProperty.CreateAttached("Id", typeof(string), typeof(View), null);
/// <summary>
/// Set connected animation id.
using Tizen.NUI;
using Tizen.NUI.BaseComponents;
-using Fitness.Services;
-
namespace Fitness.Controls
{
public class ConnectedAnimation : Animation
{
- private View Source { get; set; }
-
public ConnectedAnimation(View source)
: base()
{
Source = source;
}
- public void AnimateFromSourceTo(View view, string propertyName, object to, Interpolation interpolation = Interpolation.Linear, AlphaFunction alphaFunction = null)
- {
- PropertyValue sourceValue, toValue;
+ private View Source { get; set; }
- int idx = Source.GetPropertyIndex(propertyName);
+ public void AnimateFromSourceTo(View view, string propertyName, object to, Interpolation interpolation = Interpolation.Linear, AlphaFunction alphaFunction = null)
+ {
+ PropertyValue sourceValue, toValue;
- switch (propertyName)
- {
- case "Position":
- sourceValue = PropertyValue.CreateFromObject(GetWorldPosition(Source) - GetWorldPosition(view));
- break;
- case "PositionX":
- sourceValue = PropertyValue.CreateFromObject((GetWorldPosition(Source) - GetWorldPosition(view)).X);
- break;
- case "PositionY":
- sourceValue = PropertyValue.CreateFromObject((GetWorldPosition(Source) - GetWorldPosition(view)).Y);
- break;
- case "PositionZ":
- sourceValue = PropertyValue.CreateFromObject((GetWorldPosition(Source) - GetWorldPosition(view)).Z);
- break;
- default:
- sourceValue = Source.GetProperty(idx);
- break;
- }
- toValue = PropertyValue.CreateFromObject(to);
+ int idx = Source.GetPropertyIndex(propertyName);
- AnimatePropertyBetween(view, propertyName, sourceValue, toValue, interpolation, alphaFunction);
- }
+ switch (propertyName)
+ {
+ case "Position":
+ sourceValue = PropertyValue.CreateFromObject(GetWorldPosition(Source) - GetWorldPosition(view));
+ break;
+ case "PositionX":
+ sourceValue = PropertyValue.CreateFromObject((GetWorldPosition(Source) - GetWorldPosition(view)).X);
+ break;
+ case "PositionY":
+ sourceValue = PropertyValue.CreateFromObject((GetWorldPosition(Source) - GetWorldPosition(view)).Y);
+ break;
+ case "PositionZ":
+ sourceValue = PropertyValue.CreateFromObject((GetWorldPosition(Source) - GetWorldPosition(view)).Z);
+ break;
+ default:
+ sourceValue = Source.GetProperty(idx);
+ break;
+ }
- private static Position GetWorldPosition(View view)
- {
- Position position = new Position();
+ toValue = PropertyValue.CreateFromObject(to);
- while (view != null)
- {
- position += view.Position;
- view = view.GetParent() as View;
- }
- return position;
- }
+ AnimatePropertyBetween(view, propertyName, sourceValue, toValue, interpolation, alphaFunction);
+ }
- private void AnimatePropertyBetween(View view, string propertyName, PropertyValue from, PropertyValue to, Interpolation interpolation, AlphaFunction alphaFunction)
- {
- var frames = new KeyFrames();
+ private static Position GetWorldPosition(View view)
+ {
+ Position position = new Position();
- frames.Add(0.0f, from);
- frames.Add(1.0f, to);
+ while (view != null)
+ {
+ position += view.Position;
+ view = view.GetParent() as View;
+ }
- AnimateBetween(view, propertyName, frames, interpolation, alphaFunction);
- }
+ return position;
+ }
+
+ private void AnimatePropertyBetween(View view, string propertyName, PropertyValue from, PropertyValue to, Interpolation interpolation, AlphaFunction alphaFunction)
+ {
+ var frames = new KeyFrames();
+
+ frames.Add(0.0f, from);
+ frames.Add(1.0f, to);
+
+ AnimateBetween(view, propertyName, frames, interpolation, alphaFunction);
+ }
}
}
namespace Fitness.Controls
{
/// <summary>
- ///
+ /// ConnectedAnimationsContext is a class that allows
+ /// creating animations between two unrelated parts of the
+ /// Application's UI.
+ ///
+ /// The class allows to create smooth animations across multiple Pages,
+ /// keeping Page implementations loosly-coupled to other Pages.
+ ///
+ /// ConnectedAnimationsContext performs two operations:
+ /// * Registering - at first View must register themself
+ /// as a source of ConnectedAnimation using predefined "AnimationId" string.
+ /// * ConnectedAnimation creating - after registering the View,
+ /// other part of the App can create ConnectedAnimation using
+ /// the same predefined "AnimationId"
/// </summary>
public sealed class ConnectedAnimationsContext
{
- private Dictionary<string, View> ViewMap;
-
+ /// <summary>
+ /// Creates new ConnectedAnimationsContext
+ /// </summary>
public ConnectedAnimationsContext()
{
ViewMap = new Dictionary<string, View>();
}
+ private Dictionary<string, View> ViewMap { get; set; }
+
/// <summary>
- ///
+ /// Registers object as a source of ConnectedAnimation
/// </summary>
public void RegisterConnectedView(string animationId, View view)
{
{
throw new InvalidOperationException($"ConnectedAnimationContext already contains View for animation id: {animationId}");
}
+
ViewMap[animationId] = view;
}
/// <summary>
- ///
+ /// Creates new ConnectedAnimation that is associated to View previously
+ /// registerd with RegisterConnectedView.
+ ///
+ /// If no View has been registered on specific key the function returns
+ /// null.
/// </summary>
public ConnectedAnimation GetConnectedAnimation(string animationId)
{
if (!ViewMap.ContainsKey(animationId))
{
- throw new InvalidOperationException($"ConnectedAnimationContext does not contain View for animation id: {animationId}");
+ return null;
}
-
+
return new ConnectedAnimation(ViewMap[animationId]);
}
}
using Tizen.NUI;
using Tizen.NUI.BaseComponents;
-using Fitness.Services;
-
namespace Fitness.Controls
{
+ /// <summary>
+ /// ConnectedTransition is a utility class that allows easy
+ /// creation and management of ConnectedAnimations.
+ /// </summary>
public class ConnectedTransition : BaseTransition
{
private ConnectedAnimation animation;
+ /// <summary>
+ /// AnimationId that will be used to create Transition
+ /// </summary>
public string AnimationId { get; set; }
- public View Target { get; set; }
-
- public ConnectedTransition()
- {
- }
+ /// <summary>
+ /// Overrides default Transit target
+ /// </summary>
+ public View TargetOverride { get; set; }
public override void Transit(View target)
{
animation?.Stop();
animation?.Dispose();
- // in case when Target is explicite set use Target property
- // instead of function argument
+ // FIXME
+ // Transit should generally use target argument only,
+ // however as Transitions can currently only be attached
+ // to Page object, but not any View, I need to add the "TargetOverride"
+ // property so the Transtion can be applied on specific object that we want
+ // to animate.
+ target = TargetOverride != null ? TargetOverride : target;
- var container = FindContainerForView(Target);
+ var container = FindContainerForView(target);
if (container == null)
{
throw new InvalidOperationException("Cannot run ConnectedTransition on Target which is not a descendant of IConnectedAnimationsContainer");
}
- animation = container.GetContext().GetConnectedAnimation(AnimationId);
- animation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOut);
+ animation = container.GetContext()?.GetConnectedAnimation(AnimationId);
+
+ if (animation == null)
+ {
+ Services.Logger.Warn($"Unable to find AnimationId: {AnimationId}, ConnectedTransition aborted");
+ return;
+ }
+ animation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOut);
animation.Duration = Duration;
if (animation == null)
return;
}
- animation.AnimateFromSourceTo(Target, "Position", Target.Position);
- animation.AnimateFromSourceTo(Target, "Size", Target.Size);
- animation.AnimateFromSourceTo(Target, "Opacity", Target.Opacity);
+ animation.AnimateFromSourceTo(target, "Position", target.Position);
+ animation.AnimateFromSourceTo(target, "Size", target.Size);
+ animation.AnimateFromSourceTo(target, "Opacity", target.Opacity);
animation.Finished += AnimationFinished;
animation.Play();
{
view = view.GetParent() as View;
}
+
return view as IConnectedAnimationsContainer;
}
namespace Fitness.Controls
{
- public class FadeInTransition : BaseTransition
+ /// <summary>
+ /// FaceTransition - animates opacity from StartOpacity to EndOpacity.
+ /// </summary>
+ public class FadeTransition : BaseTransition
{
private Animation animation;
+ public FadeTransition()
+ : base()
+ {
+ StartOpacity = 0.0f;
+ EndOpacity = 1.0f;
+ }
+
+ /// <summary>
+ /// Initial Opacity that will be set on object when Transit begins
+ /// </summary>
+ public float StartOpacity { get; set; }
+
+ /// <summary>
+ /// Initial Opacity that will be set on object when Transit ends
+ /// </summary>
+ public float EndOpacity { get; set; }
+
public override void Transit(View target)
{
animation?.Dispose();
animation = new Animation(Duration);
animation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOut);
- target.Opacity = 0.0f;
- animation.AnimateBy(target, "Opacity", 1.0f);
+ target.Opacity = StartOpacity;
+ animation.AnimateBy(target, "Opacity", EndOpacity);
animation.Finished += AnimationFinished;
animation.Play();
- Services.Logger.Debug($"TranstionStarted");
RaiseTransitionStarted();
}
private void AnimationFinished(object o, EventArgs args)
{
- Services.Logger.Debug($"AnimationFinished");
RaiseTransitionFinished();
}
}
{
public interface ITransition : IDisposable
{
- void Transit(View target);
-
event EventHandler TransitionStarted;
event EventHandler TransitionFinished;
- event EventHandler TransitionCancelled;
+ /// <summary>
+ /// Run transtion (animation) on target View
+ /// </summary>
+ void Transit(View target);
}
}
using Tizen.NUI.BaseComponents;
using Tizen.NUI.Components;
-using Fitness.Services;
-
namespace Fitness.Controls
{
/// <summary>
/// </summary>
public class Page : Control, IConnectedAnimationsContainer
{
- private View _content = null;
+ private View content = null;
public Page()
: base()
HeightResizePolicy = ResizePolicyType.FillToParent;
}
+ public PageTransitionCollection PageTransitions { get; set; }
+
public View Content
{
get
{
- return _content;
+ return content;
}
+
set
{
- if (_content != value)
+ if (content != value)
{
- if (_content)
+ if (content)
{
- Remove(_content);
+ Remove(content);
}
- _content = value;
- if (_content != null)
+
+ content = value;
+ if (content != null)
{
- _content.WidthResizePolicy = ResizePolicyType.FillToParent;
- _content.HeightResizePolicy = ResizePolicyType.FillToParent;
- Add(_content);
+ content.WidthResizePolicy = ResizePolicyType.FillToParent;
+ content.HeightResizePolicy = ResizePolicyType.FillToParent;
+ Add(content);
}
}
}
}
+ internal Page ConnectedPage { get; set; }
+
public ConnectedAnimationsContext GetContext()
{
return ConnectedPage?.BuildConnectedAnimationContext();
}
- internal Page ConnectedPage;
+ public virtual void OnTransitionStarted()
+ {
+ }
+
+ public virtual void OnTransitionEnded()
+ {
+ }
internal ConnectedAnimationsContext BuildConnectedAnimationContext()
{
children.AddRange(child.Children);
children.Remove(child);
}
+
return context;
}
- public PageTransitionCollection PageTransitions { get; set; }
-
internal void RunTransitions()
{
if (PageTransitions != null)
{
PageTransitions.TransitionFinished += TransitionsFinished;
+ PageTransitions.TransitionStarted += TransitionsStarted;
PageTransitions.Transit(this);
}
}
OnTransitionEnded();
}
- public virtual void OnTransitionStarted()
- {
- }
-
- public virtual void OnTransitionEnded()
+ private void TransitionsStarted(object o, EventArgs args)
{
+ PageTransitions.TransitionStarted -= TransitionsStarted;
+ OnTransitionStarted();
}
}
}
{
private int runningTransitionsCounter;
+ /// <summary>
+ /// Triggered when first TransitionStarted event is raised.
+ /// </summary>
public event EventHandler TransitionStarted;
+ /// <summary>
+ /// Triggered when last TransitionFinished event is raised.
+ /// </summary>
public event EventHandler TransitionFinished;
- public event EventHandler TransitionCancelled;
-
+ /// <summary>
+ /// Start all Transitions in the collection.
+ /// </summary>
public void Transit(View target)
{
runningTransitionsCounter = Count;
foreach (var transition in this)
{
- transition.TransitionCancelled += CheckFinishCondition;
transition.TransitionFinished += CheckFinishCondition;
+ transition.TransitionStarted += CheckStartedCondition;
transition.Transit(target);
}
+ }
+
+ public void Dispose()
+ {
+ foreach (var transition in this)
+ {
+ transition.Dispose();
+ }
+ }
+
+ private void CheckStartedCondition(object o, EventArgs args)
+ {
+ foreach (var transition in this)
+ {
+ transition.TransitionStarted -= CheckStartedCondition;
+ }
TransitionStarted?.Invoke(this, null);
}
- public void CheckFinishCondition(object o, EventArgs args)
+ private void CheckFinishCondition(object o, EventArgs args)
{
if (o is ITransition t)
{
t.TransitionFinished -= CheckFinishCondition;
- t.TransitionCancelled -= CheckFinishCondition;
runningTransitionsCounter--;
}
}
}
-
- public void Dispose()
- {
- foreach (var transition in this)
- {
- transition.Dispose();
- }
- }
}
}
{
public partial class ExercisePreviewView : Fitness.Controls.Page
{
- static private bool done = false;
-
public ExercisePreviewView()
{
InitializeComponent();
public override void OnTransitionEnded()
{
- Services.Logger.Debug("OnTransitionEnded");
CreateVideoUrlBinding();
this.player.Show();
this.nextButton.Clicked += ReplyVideo;
this.previousButton.Clicked += ReplyVideo;
this.player.Hide();
- this.temp.Relayout += (obj, args) =>
- {
- if (done)
- return;
-
- done = true;
+ this.temp.Relayout += RunPageTransitions;
+ }
- // this should'nt be here however currently not better place to
- // put it.
- this.RunTransitions();
- };
+ private void RunPageTransitions(object o, EventArgs args)
+ {
+ this.temp.Relayout -= RunPageTransitions;
+ RunTransitions();
}
private void CreateVideoUrlBinding()
{
- Logger.Debug("Create BindingContext for VideoView");
var binding = new Binding("CurrentWorkout");
+
binding.Source = this.context;
this.player.SetBinding(BindableObject.BindingContextProperty, binding);
public override RecycleItem CreateRecycleItem()
{
- Fitness.Services.Logger.Debug("CreateRecycleItem");
var it = new FitnessItemView();
it.BackgroundColor = Color.Red;
return it;
public override void BindData(RecycleItem item)
{
- Fitness.Services.Logger.Debug("BindData");
item.BindingContext = Data[item.DataIndex];
if (item is FitnessItemView fitnessItem)
{
- Fitness.Services.Logger.Debug("item is FitnessItemView fitnessItem");
fitnessItem.image.BindingContext = item.BindingContext;
fitnessItem.label.BindingContext = item.BindingContext;
fitnessItem.favourite.BindingContext = item.BindingContext;
using Tizen.NUI.BaseComponents;
using Tizen.NUI.Components;
-using Fitness.Services;
-
namespace Fitness.Views
{
public partial class MainView : Fitness.Controls.Page
this.button1.ApplyStyle(Styles.Buttons.Inverse);
this.button2.ApplyStyle(Styles.Buttons.Regular);
this.scroller.ScrollingDirection = ScrollableBase.Direction.Horizontal;
-
- Logger.Debug("MainView constructor end");
}
}
}
</ctrl:Page.BindingContext>
<ctrl:Page.PageTransitions>
<ctrl:PageTransitionCollection>
- <ctrl:ConnectedTransition AnimationId="preview" Target="{x:Reference temp}" Duration="500"/>
- <ctrl:FadeInTransition Duration="500" />
+ <ctrl:ConnectedTransition AnimationId="preview" TargetOverride="{x:Reference temp}" Duration="500"/>
+ <ctrl:FadeTransition Duration="500" StartOpacity="0.0" EndOpacity="1.0" />
</ctrl:PageTransitionCollection>
</ctrl:Page.PageTransitions>
<ctrl:Page.Content>