[TimerView] Create extended entry control 72/116772/7
authorKamil Lipiszko <k.lipiszko@DIGITAL.local>
Thu, 23 Feb 2017 10:02:22 +0000 (11:02 +0100)
committerKamil Lipiszko <k.lipiszko@DIGITAL.local>
Mon, 6 Mar 2017 16:09:50 +0000 (17:09 +0100)
This patch creates extended entry and applies it into the
timer's view.

Change-Id: I37957d5e055d39b66bbbc563d99f2e147ad464c7

Clock/Clock.TizenMobile/Clock.TizenMobile.csproj
Clock/Clock.TizenMobile/Controls/ExtendedEntry.cs [new file with mode: 0644]
Clock/Clock.TizenMobile/Controls/ExtendedEntryRenderer.cs [new file with mode: 0644]
Clock/Clock.TizenMobile/Controls/FloatingButtonRenderer.cs
Clock/Clock.TizenMobile/Controls/TimePickerRenderer.cs
Clock/Clock.TizenMobile/Views/TimerView.xaml
Clock/Clock.TizenMobile/Views/TimerView.xaml.cs

index 32aaeb2..1ea8a69 100644 (file)
@@ -50,6 +50,8 @@
     <Compile Include="Clock.cs" />
     <Compile Include="Clock.TizenMobile.cs" />
     <Compile Include="Clock.Dependency.cs" />
+    <Compile Include="Controls\ExtendedEntry.cs" />
+    <Compile Include="Controls\ExtendedEntryRenderer.cs" />
     <Compile Include="Controls\FloatingButtonRenderer.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Controls\TimePickerRenderer.cs" />
       </FlavorProperties>
     </VisualStudio>
   </ProjectExtensions>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/Clock/Clock.TizenMobile/Controls/ExtendedEntry.cs b/Clock/Clock.TizenMobile/Controls/ExtendedEntry.cs
new file mode 100644 (file)
index 0000000..3506f0c
--- /dev/null
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+
+namespace Clock.TizenMobile.Controls
+{
+    public class ExtendedEntry : Entry
+    {
+        public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(Entry), default(bool), BindingMode.TwoWay);
+        public static readonly BindableProperty MaxValueProperty = BindableProperty.Create("MaxValue", typeof(int), typeof(Entry), default(int), BindingMode.TwoWay);
+
+        public const int MaxLenght = 2;
+
+        public ExtendedEntry NextFocus
+        {
+            get;
+            set;
+        }
+
+        public ExtendedEntry()
+        {
+            TextChanged += OnEntryChanged;
+
+            Unfocused += OnEntryUnfocus;
+            Focused += OnEntryFocus;
+        }
+
+        public static bool Validate(ExtendedEntry entry)
+        {
+            int n;
+            var isNumeric = int.TryParse(entry.Text, out n);
+
+            if (string.IsNullOrWhiteSpace(entry.Text) || !isNumeric || n < 0)
+            {
+                entry.Text = "00";
+                return false;
+            }
+
+            if (n > entry.MaxValue)
+            {
+                entry.Text = entry.MaxValue.ToString("D2");
+                return false;
+            }
+
+            return true;
+        }
+
+        public int MaxValue
+        {
+            get
+            {
+                return (int)GetValue(MaxValueProperty);
+            }
+            set
+            {
+                SetValue(MaxValueProperty, value);
+            }
+        }
+
+        public bool IsSelected
+        {
+            get
+            {
+                return (bool)GetValue(IsSelectedProperty);
+            }
+            set
+            {
+                SetValue(IsSelectedProperty, value);
+            }
+        }
+
+        public void Increase()
+        {
+            int n;
+
+            if(!int.TryParse(Text, out n))
+            {
+                return;
+            }
+            ++n;
+
+            if (n > MaxValue)
+            {
+                n = 0;
+            }
+
+            Text = n.ToString("D2");
+        }
+
+        public void Decrease()
+        {
+            int n;
+
+            if(!int.TryParse(Text, out n))
+            {
+                return;
+            }
+            --n;
+
+            if (n < 0)
+            {
+                n = MaxValue;
+            }
+
+            Text = n.ToString("D2");
+        }
+
+        private static void OnEntryTextChanged(object sender, EventArgs e)
+        {
+            var entry = sender as ExtendedEntry;
+
+            if (entry.Text.Length >= 2)
+            {
+                EntryFocusNext(entry);
+            }
+        }
+
+        private static void EntryFocusNext(ExtendedEntry entry)
+        {
+            if (entry.NextFocus != null)
+            {
+                entry.NextFocus.Focus();
+            }
+        }
+
+        private static void OnEntryFocus(object sender, EventArgs e)
+        {
+            var entry = sender as ExtendedEntry;
+
+            entry.IsSelected = !entry.IsSelected;
+        }
+
+        private static void OnEntryUnfocus(object sender, FocusEventArgs e)
+        {
+            var entry = sender as ExtendedEntry;
+
+            int n;
+            var isNumeric = int.TryParse(entry.Text, out n);
+            if (n < 10)
+            {
+                var output = n.ToString().PadLeft(2, '0');
+
+                if (entry.Text != output)
+                {
+                    entry.Text = output;
+                }
+
+                return;
+            }
+
+            entry.Text = n.ToString("D2");
+        }
+
+        private static void OnEntryChanged(object sender, TextChangedEventArgs e)
+        {
+            var entry = sender as ExtendedEntry;
+
+            if (!Validate(entry))
+            {
+                return;
+            }
+
+            int n;
+            var isNumeric = int.TryParse(entry.Text, out n);
+
+            if (entry.IsFocused && isNumeric && entry.Text.Length >= 2)
+            {
+                EntryFocusNext(entry);
+            }
+        }
+    }
+}
diff --git a/Clock/Clock.TizenMobile/Controls/ExtendedEntryRenderer.cs b/Clock/Clock.TizenMobile/Controls/ExtendedEntryRenderer.cs
new file mode 100644 (file)
index 0000000..fb7edce
--- /dev/null
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using TNative = Xamarin.Forms.Platform.Tizen;
+
+[assembly: TNative.ExportRenderer(typeof(Clock.TizenMobile.Controls.ExtendedEntry), typeof(CustomRenderer.ExtendedEntryRenderer))]
+namespace CustomRenderer
+{
+    public class ExtendedEntryRenderer : TNative.EntryRenderer
+    {
+
+        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+        {
+            if (e.PropertyName == Clock.TizenMobile.Controls.ExtendedEntry.IsSelectedProperty.PropertyName)
+            {
+                Tizen.Log.Debug("CLOCK", "Entry selected!");
+                base.Control.SelectAll();
+            }
+
+            base.OnElementPropertyChanged(sender, e);
+        }
+    }
+}
index fc5ed6b..8b718f5 100644 (file)
@@ -8,8 +8,8 @@ using Xamarin.Forms.Platform.Tizen;
 using Xamarin.Forms;
 using ElmSharp;
 
-[assembly: ExportRenderer(typeof(Clock.TizenMobile.Controls.FloatingButton), typeof(CustomRenderer.Tizen.FloatingButtonRenderer))]
-namespace CustomRenderer.Tizen
+[assembly: ExportRenderer(typeof(Clock.TizenMobile.Controls.FloatingButton), typeof(CustomRenderer.FloatingButtonRenderer))]
+namespace CustomRenderer
 {
     public class FloatingButtonRenderer : ViewRenderer<Clock.TizenMobile.Controls.FloatingButton, ElmSharp.FloatingButton>
     {
index 9c5e217..efaad76 100644 (file)
@@ -7,8 +7,8 @@ using System.Threading.Tasks;
 using Xamarin.Forms;
 using Xamarin.Forms.Platform.Tizen;
 
-[assembly: ExportRenderer(typeof(Clock.TizenMobile.Controls.TimePicker), typeof(CustomRenderer.Tizen.TimePickerRenderer))]
-namespace CustomRenderer.Tizen {
+[assembly: ExportRenderer(typeof(Clock.TizenMobile.Controls.TimePicker), typeof(CustomRenderer.TimePickerRenderer))]
+namespace CustomRenderer {
     class TimePickerRenderer : ViewRenderer<Xamarin.Forms.TimePicker, Xamarin.Forms.Platform.Tizen.Native.TimePicker>{
 
         protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e) {
index e9c4bdf..865cb35 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             xmlns:controls="clr-namespace:Clock.TizenMobile.Controls;assembly=Clock.TizenMobile"
              x:Class="Clock.TizenMobile.Views.TimerView">
 
   <ContentPage.Content>
@@ -8,33 +9,33 @@
         <StackLayout Orientation="Horizontal" AbsoluteLayout.LayoutBounds=".5, .3, 620, 426" AbsoluteLayout.LayoutFlags="PositionProportional" >
           <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
             <Label Text="Hours" AbsoluteLayout.LayoutBounds=".235, .0, .2, .09" AbsoluteLayout.LayoutFlags="All" VerticalTextAlignment="End" HorizontalTextAlignment="Center" TextColor="White" />
-            <Button BackgroundColor="Transparent" Image="images/alarm_picker_arrow_up.png" />
-            <Entry x:Name="EntryHours" Text="00" TextChanged="OnEntryChanged" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" TextColor="White"/>
-            <Button BackgroundColor="Transparent" Image="images/alarm_picker_arrow_down.png" />
+            <Button x:Name="ButtonHourIncrease" BackgroundColor="Transparent" Clicked="OnTimeButtonClicked" Image="images/alarm_picker_arrow_up.png" />
+            <controls:ExtendedEntry x:Name="EntryHours" Text="00" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" TextColor="White" MaxValue="99"/>
+            <Button x:Name="ButtonHourDecrease" BackgroundColor="Transparent" Clicked="OnTimeButtonClicked" Image="images/alarm_picker_arrow_down.png" />
           </StackLayout>
-          <Label Text=":" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" VerticalTextAlignment="Center" TextColor="White"/>
+          <Label Text=":" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="Center" VerticalTextAlignment="Center" TextColor="White"/>
           <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
             <Label Text="Minutes" AbsoluteLayout.LayoutBounds=".5, .0, .2, .09" AbsoluteLayout.LayoutFlags="All" HorizontalTextAlignment="Center" TextColor="White" />
-            <Button BackgroundColor="Transparent" Image="images/alarm_picker_arrow_up.png" />
-            <Entry x:Name="EntryMinutes" Text="00" TextChanged="OnEntryChanged" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" TextColor="White"/>
-            <Button BackgroundColor="Transparent" Image="images/alarm_picker_arrow_down.png" />
+            <Button x:Name="ButtonMinuteIncrease" BackgroundColor="Transparent" Clicked="OnTimeButtonClicked" Image="images/alarm_picker_arrow_up.png" />
+            <controls:ExtendedEntry x:Name="EntryMinutes" Text="00" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" TextColor="White" MaxValue="59"/>
+            <Button x:Name="ButtonMinuteDecrease" BackgroundColor="Transparent" Clicked="OnTimeButtonClicked" Image="images/alarm_picker_arrow_down.png" />
           </StackLayout>
-          <Label Text=":" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" VerticalTextAlignment="Center" TextColor="White"/>
+          <Label Text=":" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="Center" VerticalTextAlignment="Center" TextColor="White"/>
           <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
             <Label Text="Seconds" AbsoluteLayout.LayoutBounds=".765, .0, .2, .09" AbsoluteLayout.LayoutFlags="All" HorizontalTextAlignment="Center" TextColor="White" />
-            <Button BackgroundColor="Transparent" Image="images/alarm_picker_arrow_up.png" />
-            <Entry x:Name="EntrySeconds" Text="00" TextChanged="OnEntryChanged" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" TextColor="White"/>
-            <Button BackgroundColor="Transparent" Image="images/alarm_picker_arrow_down.png" />
+            <Button x:Name="ButtonSecondIncrease" BackgroundColor="Transparent" Clicked="OnTimeButtonClicked" Image="images/alarm_picker_arrow_up.png" />
+            <controls:ExtendedEntry x:Name="EntrySeconds" Text="00" FontSize="80" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" TextColor="White" MaxValue="59"/>
+            <Button x:Name="ButtonSecondDecrease" BackgroundColor="Transparent" Clicked="OnTimeButtonClicked" Image="images/alarm_picker_arrow_down.png" />
           </StackLayout>
         </StackLayout>
 
         <AbsoluteLayout AbsoluteLayout.LayoutBounds=".5, 1, 720, 120" AbsoluteLayout.LayoutFlags="PositionProportional">
           <BoxView Color="White" AbsoluteLayout.LayoutBounds=".5, 1, 1, 1" AbsoluteLayout.LayoutFlags="All"/>
-          <Button x:Name="StartButton" Text="Start" AbsoluteLayout.LayoutBounds=".5, .5, 0.7, 0.7" AbsoluteLayout.LayoutFlags="All" IsVisible="True"/>
-          <Button x:Name="PauseButton" Text="Pause" AbsoluteLayout.LayoutBounds=".1, .5, 0.4, 0.7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
-          <Button x:Name="CancelButton" Text="Cancel" AbsoluteLayout.LayoutBounds=".9, .5, 0.4, 0.7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
-          <Button x:Name="ResumeButton" Text="Resume" AbsoluteLayout.LayoutBounds=".1, .5, 0.4, 0.7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
-          <Button x:Name="ResetButton" Text="Reset" AbsoluteLayout.LayoutBounds=".9, .5, 0.4, 0.7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
+          <Button x:Name="StartButton" Text="Start" AbsoluteLayout.LayoutBounds=".5, .5, .7, .7" AbsoluteLayout.LayoutFlags="All" IsVisible="True"/>
+          <Button x:Name="PauseButton" Text="Pause" AbsoluteLayout.LayoutBounds=".1, .5, .4, .7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
+          <Button x:Name="CancelButton" Text="Cancel" AbsoluteLayout.LayoutBounds=".9, .5, .4, .7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
+          <Button x:Name="ResumeButton" Text="Resume" AbsoluteLayout.LayoutBounds=".1, .5, .4, .7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
+          <Button x:Name="ResetButton" Text="Reset" AbsoluteLayout.LayoutBounds=".9, .5, .4, .7" AbsoluteLayout.LayoutFlags="All" IsVisible="False"/>
         </AbsoluteLayout>
 
     </AbsoluteLayout>
index 861bac9..a72e3a6 100644 (file)
@@ -5,19 +5,111 @@ using System.Text;
 using System.Threading.Tasks;
 
 using Xamarin.Forms;
+using Clock.TizenMobile.Controls;
+using System.Windows.Input;
 
 namespace Clock.TizenMobile.Views
 {
     public partial class TimerView : ContentPage
     {
+        enum ButtonDirection {
+            INCREASE,
+            DECREASE,
+        }
+
+        enum ButtonType
+        {
+            HOUR,
+            MINUTE,
+            SECOND
+        }
+
         public TimerView()
         {
             InitializeComponent();
+
+            EntryHours.NextFocus = EntryMinutes;
+            EntryMinutes.NextFocus = EntrySeconds;
+            EntrySeconds.NextFocus = EntryHours;
         }
 
-        private void OnEntryChanged(object sender, EventArgs e)
+        private void OnTimeButtonClicked(object sender, EventArgs e)
         {
+            var button = sender as Button;
+            ButtonType bType = ButtonType.HOUR;
+            ButtonDirection bDirection = ButtonDirection.INCREASE;
+
+            if (button.Equals(ButtonHourIncrease))
+            {
+                bType = ButtonType.HOUR;
+                bDirection = ButtonDirection.INCREASE;
+            }
+            else if (button.Equals(ButtonHourDecrease))
+            {
+                bType = ButtonType.HOUR;
+                bDirection = ButtonDirection.DECREASE;
+            }
+            else if (button.Equals(ButtonMinuteIncrease))
+            {
+                bType = ButtonType.MINUTE;
+                bDirection = ButtonDirection.INCREASE;
+            }
+            else if (button.Equals(ButtonMinuteDecrease))
+            {
+                bType = ButtonType.MINUTE;
+                bDirection = ButtonDirection.DECREASE;
+            }
+            else if (button.Equals(ButtonSecondIncrease))
+            {
+                bType = ButtonType.SECOND;
+                bDirection = ButtonDirection.INCREASE;
+            }
+            else if (button.Equals(ButtonSecondDecrease))
+            {
+                bType = ButtonType.SECOND;
+                bDirection = ButtonDirection.DECREASE;
+            }
 
+            EntryUpdate(bType, bDirection);
+        }
+
+        private void EntryUpdate(ButtonType type, ButtonDirection direction)
+        {
+            switch (type)
+            {
+                case ButtonType.HOUR:
+                    if (direction == ButtonDirection.INCREASE)
+                    {
+                        EntryHours.Increase();
+                    }
+                    else
+                    {
+                        EntryHours.Decrease();
+                    }
+                    break;
+                case ButtonType.MINUTE:
+                    if (direction == ButtonDirection.INCREASE)
+                    {
+                        EntryMinutes.Increase();
+                    }
+                    else
+                    {
+                        EntryMinutes.Decrease();
+                    }
+                    break;
+                case ButtonType.SECOND:
+                    if (direction == ButtonDirection.INCREASE)
+                    {
+                        EntrySeconds.Increase();
+                    }
+                    else
+                    {
+                        EntrySeconds.Decrease();
+                    }
+                    break;
+                default:
+                    return;
+            }
         }
     }
 }