Revert "Remove Controls" (#152)
author유리나/Common Platform Lab(SR)/Staff Engineer/삼성전자 <rina6350.you@samsung.com>
Wed, 18 Mar 2020 07:25:18 +0000 (16:25 +0900)
committer윤정현/Common Platform Lab(SR)/Staff Engineer/삼성전자 <jh0506.yun@samsung.com>
Wed, 18 Mar 2020 07:25:18 +0000 (16:25 +0900)
* Revert "Remove the TargetIdiom and Profile (#137)"

This reverts commit 7461c01c17e3bad6edefa4f904f33547cfee0141.

* Revert "Remove MasterDetialPage (#136)"

This reverts commit 810091904c2491b6c3b7f0610aacd71eee4c72a8.

* Revert "Remove the unused code in NavigationPage (#134)"

This reverts commit 2c3e047eafc060585233a78a0a360d8b4e0d9a2b.

* Revert "Remove SearchBar (#131)"

This reverts commit 4044c3dc779c3c2532b7b7375223f6aa841cf5ff.

* Revert "Remove Picker,DatePicker,TimePicker (#130)"

This reverts commit 9ac5e590b496e33a3fa70c4816e085d1d3686d30.

* Revert "Remove TabbedPage (#129)"

This reverts commit 1ee705f6fef0623d2fa71c564d59806893e37d77.

* Revert "Remove CheckBox (#125)"

This reverts commit 08f37db3a156e3cd15adcd50a7ee0eb160e7e9d3.

* Revert "Remove the unused properties (#121)"

This reverts commit 49cac3c31f396932b4066ebb1338d74edd0d449e.

59 files changed:
Xamarin.Forms/Xamarin.Forms.Core/Button.cs
Xamarin.Forms/Xamarin.Forms.Core/CheckBox.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/DatePicker.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/Editor.cs
Xamarin.Forms/Xamarin.Forms.Core/Entry.cs
Xamarin.Forms/Xamarin.Forms.Core/Frame.cs
Xamarin.Forms/Xamarin.Forms.Core/IMasterDetailPageController.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/ISearchBarController.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/ImageButton.cs
Xamarin.Forms/Xamarin.Forms.Core/InputView.cs
Xamarin.Forms/Xamarin.Forms.Core/Internals/ToolbarTracker.cs
Xamarin.Forms/Xamarin.Forms.Core/Label.cs
Xamarin.Forms/Xamarin.Forms.Core/Layout.cs
Xamarin.Forms/Xamarin.Forms.Core/ListView.cs
Xamarin.Forms/Xamarin.Forms.Core/MasterBehavior.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/MasterDetailPage.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/NavigationPage.cs
Xamarin.Forms/Xamarin.Forms.Core/Picker.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/PlatformConfiguration/TizenSpecific/NavigationPage.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/PlatformConfiguration/TizenSpecific/StyleValues.cs
Xamarin.Forms/Xamarin.Forms.Core/Properties/AssemblyInfo.cs [changed mode: 0644->0755]
Xamarin.Forms/Xamarin.Forms.Core/RefreshView.cs
Xamarin.Forms/Xamarin.Forms.Core/SearchBar.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/Slider.cs
Xamarin.Forms/Xamarin.Forms.Core/Switch.cs
Xamarin.Forms/Xamarin.Forms.Core/TabbedPage.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Core/TimePicker.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Cells/ImageCellRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Cells/SwitchCellRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Cells/TextCellRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Forms.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateChangedEventArgs.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateTimePicker.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateTimePickerDialog.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/Dialog.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/IDateTimeDialog.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/Watch/WatchDataTimePickerDialog.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/Watch/WatchDateTimePicker.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Platform.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/ButtonRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/CheckBoxRenderer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/CustomFocusManager.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/DatePickerRenderer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/EditorRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailContainer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/PickerRenderer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/SearchBarRenderer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/SwitchRenderer.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/TimePickerRenderer.cs [new file with mode: 0644]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Shell/ShellNavBar.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/StaticRegistrar.cs
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/TizenPlatformServices.cs
Xamarin.Forms/Xamarin.Forms.Platform/Xamarin.Forms.Platform.cs

index 70b3c3a..74ef701 100644 (file)
@@ -37,6 +37,18 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty FontAttributesProperty = FontElement.FontAttributesProperty;
 
+               public static readonly BindableProperty BorderWidthProperty = BindableProperty.Create("BorderWidth", typeof(double), typeof(Button), -1d);
+
+               public static readonly BindableProperty BorderColorProperty = BorderElement.BorderColorProperty;
+
+               [Obsolete("BorderRadiusProperty is obsolete as of 2.5.0. Please use CornerRadius instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty BorderRadiusProperty = BindableProperty.Create("BorderRadius", typeof(int), typeof(Button), defaultValue: DefaultBorderRadius,
+                       propertyChanged: BorderRadiusPropertyChanged);
+
+               public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(int), typeof(Button), defaultValue: BorderElement.DefaultCornerRadius,
+                       propertyChanged: CornerRadiusPropertyChanged);
+
                public static readonly BindableProperty ImageSourceProperty = ImageElement.ImageProperty;
 
                [Obsolete("ImageProperty is obsolete as of 4.0.0. Please use ImageSourceProperty instead.")]
@@ -61,13 +73,38 @@ namespace Xamarin.Forms
                        InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
                }
 
+
+               internal static readonly BindablePropertyKey IsPressedPropertyKey = BindableProperty.CreateReadOnly(nameof(IsPressed), typeof(bool), typeof(Button), default(bool));
+               public static readonly BindableProperty IsPressedProperty = IsPressedPropertyKey.BindableProperty;
+
+
                readonly Lazy<PlatformConfigurationRegistry<Button>> _platformConfigurationRegistry;
 
-               public Color BorderColor { get; set; }
+               public Color BorderColor
+               {
+                       get { return (Color)GetValue(BorderElement.BorderColorProperty); }
+                       set { SetValue(BorderElement.BorderColorProperty, value); }
+               }
+
+               [Obsolete("BorderRadius is obsolete as of 2.5.0. Please use CornerRadius instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public int BorderRadius
+               {
+                       get { return (int)GetValue(BorderRadiusProperty); }
+                       set { SetValue(BorderRadiusProperty, value); }
+               }
 
-               public int CornerRadius { get; set; }
+               public int CornerRadius
+               {
+                       get { return (int)GetValue(CornerRadiusProperty); }
+                       set { SetValue(CornerRadiusProperty, value); }
+               }
 
-               public double BorderWidth { get; set; }
+               public double BorderWidth
+               {
+                       get { return (double)GetValue(BorderWidthProperty); }
+                       set { SetValue(BorderWidthProperty, value); }
+               }
 
                public ButtonContentLayout ContentLayout
                {
@@ -133,10 +170,10 @@ namespace Xamarin.Forms
                [EditorBrowsable(EditorBrowsableState.Never)]
                public void SendClicked() => ButtonElement.ElementClicked(this, this);
 
-               public bool IsPressed => false;
+               public bool IsPressed => (bool)GetValue(IsPressedProperty);
 
                [EditorBrowsable(EditorBrowsableState.Never)]
-               void IButtonElement.SetIsPressed(bool isPressed) { }
+               void IButtonElement.SetIsPressed(bool isPressed) => SetValue(IsPressedPropertyKey, isPressed);
 
                [EditorBrowsable(EditorBrowsableState.Never)]
                public void SendPressed() => ButtonElement.ElementPressed(this, this);
@@ -227,13 +264,67 @@ namespace Xamarin.Forms
                ImageSource IImageElement.Source => ImageSource;
                bool IImageElement.IsOpaque => false;
 
+
                void IImageElement.RaiseImageSourcePropertyChanged() => OnPropertyChanged(ImageSourceProperty.PropertyName);
 
-               int IBorderElement.CornerRadiusDefaultValue => (int)BorderElement.DefaultCornerRadius;
+               int IBorderElement.CornerRadiusDefaultValue => (int)CornerRadiusProperty.DefaultValue;
+
+               Color IBorderElement.BorderColorDefaultValue => (Color)BorderColorProperty.DefaultValue;
+
+               double IBorderElement.BorderWidthDefaultValue => (double)BorderWidthProperty.DefaultValue;
+
+
+               /// <summary>
+               /// Flag to prevent overwriting the value of CornerRadius
+               /// </summary>
+               bool cornerOrBorderRadiusSetting = false;
+
+               static void BorderRadiusPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
+               {
+                       if (newvalue == oldvalue)
+                               return;
+
+                       var button = (Button)bindable;
+                       var val = (int)newvalue;
+                       if (val == DefaultBorderRadius && !button.cornerOrBorderRadiusSetting)
+                               val = BorderElement.DefaultCornerRadius;
 
-               Color IBorderElement.BorderColorDefaultValue => (Color)BorderElement.BorderColorProperty.DefaultValue;
+                       var oldVal = (int)bindable.GetValue(Button.CornerRadiusProperty);
 
-               double IBorderElement.BorderWidthDefaultValue => (double)-1d;
+                       if (oldVal == val)
+                               return;
+
+                       if (button.cornerOrBorderRadiusSetting) // retain until BorderRadiusProperty removed
+                               return;
+
+                       button.cornerOrBorderRadiusSetting = true;
+                       bindable.SetValue(Button.CornerRadiusProperty, val);
+                       button.cornerOrBorderRadiusSetting = false;
+               }
+
+               static void CornerRadiusPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
+               {
+                       if (newvalue == oldvalue)
+                               return;
+
+                       var button = (Button)bindable;
+                       var val = (int)newvalue;
+                       if (val == BorderElement.DefaultCornerRadius && !button.cornerOrBorderRadiusSetting)
+                               val = DefaultBorderRadius;
+
+#pragma warning disable 0618 // retain until BorderRadiusProperty removed
+                       var oldVal = (int)bindable.GetValue(Button.BorderRadiusProperty);
+#pragma warning restore
+
+                       if (oldVal == val)
+                               return;
+
+#pragma warning disable 0618 // retain until BorderRadiusProperty removed
+                       button.cornerOrBorderRadiusSetting = true;
+                       bindable.SetValue(Button.BorderRadiusProperty, val);
+                       button.cornerOrBorderRadiusSetting = false;
+#pragma warning restore
+               }
 
                void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
                {
@@ -241,12 +332,15 @@ namespace Xamarin.Forms
 
                void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
                {
+                       InvalidateMeasure();
                }
 
+
                void IBorderElement.OnBorderColorPropertyChanged(Color oldValue, Color newValue)
                {
                }
 
+
                bool IImageController.GetLoadAsAnimation() => false;
                bool IImageElement.IsLoading => false;
 
@@ -262,10 +356,10 @@ namespace Xamarin.Forms
                {
                }
 
-               bool IBorderElement.IsCornerRadiusSet() => false;
-               bool IBorderElement.IsBackgroundColorSet() => false;
-               bool IBorderElement.IsBorderColorSet() => false;
-               bool IBorderElement.IsBorderWidthSet() => false;
+               bool IBorderElement.IsCornerRadiusSet() => IsSet(CornerRadiusProperty);
+               bool IBorderElement.IsBackgroundColorSet() => IsSet(BackgroundColorProperty);
+               bool IBorderElement.IsBorderColorSet() => IsSet(BorderColorProperty);
+               bool IBorderElement.IsBorderWidthSet() => IsSet(BorderWidthProperty);
 
 
                [DebuggerDisplay("Image Position = {Position}, Spacing = {Spacing}")]
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/CheckBox.cs b/Xamarin.Forms/Xamarin.Forms.Core/CheckBox.cs
new file mode 100644 (file)
index 0000000..adae2c5
--- /dev/null
@@ -0,0 +1,66 @@
+using System;
+using Xamarin.Forms.Platform;
+
+namespace Xamarin.Forms
+{
+       [RenderWith(typeof(_CheckBoxRenderer))]
+       public class CheckBox : View, IElementConfiguration<CheckBox>, IBorderElement, IColorElement
+       {
+               readonly Lazy<PlatformConfigurationRegistry<CheckBox>> _platformConfigurationRegistry;
+               public const string IsCheckedVisualState = "IsChecked";
+
+               public static readonly BindableProperty IsCheckedProperty =
+                       BindableProperty.Create(nameof(IsChecked), typeof(bool), typeof(CheckBox), false,
+                               propertyChanged: (bindable, oldValue, newValue) => {
+                       ((CheckBox)bindable).CheckedChanged?.Invoke(bindable, new CheckedChangedEventArgs((bool)newValue));
+                       ((CheckBox)bindable).ChangeVisualState();
+               }, defaultBindingMode: BindingMode.TwoWay);
+
+               public static readonly BindableProperty ColorProperty = ColorElement.ColorProperty;
+
+               public Color Color
+               {
+                       get => (Color)GetValue(ColorProperty);
+                       set => SetValue(ColorProperty, value);
+               }
+
+
+               public CheckBox() => _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<CheckBox>>(() => new PlatformConfigurationRegistry<CheckBox>(this));
+
+               public bool IsChecked
+               {
+                       get => (bool)GetValue(IsCheckedProperty);
+                       set => SetValue(IsCheckedProperty, value);
+               }
+
+               protected internal override void ChangeVisualState()
+               {
+                       if (IsEnabled && IsChecked)
+                               VisualStateManager.GoToState(this, IsCheckedVisualState);
+                       else
+                               base.ChangeVisualState();
+               }
+
+               public event EventHandler<CheckedChangedEventArgs> CheckedChanged;
+
+               public IPlatformElementConfiguration<T, CheckBox> On<T>() where T : IConfigPlatform
+               {
+                       return _platformConfigurationRegistry.Value.On<T>();
+               }
+
+               void IBorderElement.OnBorderColorPropertyChanged(Color oldValue, Color newValue)
+               {
+               }
+
+               Color IBorderElement.BorderColor => Color.Transparent;
+               int IBorderElement.CornerRadius => 0;
+               double IBorderElement.BorderWidth => 0;
+               int IBorderElement.CornerRadiusDefaultValue => 0;
+               Color IBorderElement.BorderColorDefaultValue => Color.Transparent;
+               double IBorderElement.BorderWidthDefaultValue => 0;
+               bool IBorderElement.IsCornerRadiusSet() => false;
+               bool IBorderElement.IsBackgroundColorSet() => IsSet(BackgroundColorProperty);
+               bool IBorderElement.IsBorderColorSet() => false;
+               bool IBorderElement.IsBorderWidthSet() => false;
+       }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/DatePicker.cs b/Xamarin.Forms/Xamarin.Forms.Core/DatePicker.cs
new file mode 100644 (file)
index 0000000..1bd150a
--- /dev/null
@@ -0,0 +1,180 @@
+using System;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Platform;
+
+namespace Xamarin.Forms
+{
+       [RenderWith(typeof(_DatePickerRenderer))]
+       public class DatePicker : View, IFontElement, ITextElement, IElementConfiguration<DatePicker>
+       {
+               public static readonly BindableProperty FormatProperty = BindableProperty.Create(nameof(Format), typeof(string), typeof(DatePicker), "d");
+
+               public static readonly BindableProperty DateProperty = BindableProperty.Create(nameof(Date), typeof(DateTime), typeof(DatePicker), default(DateTime), BindingMode.TwoWay,
+                       coerceValue: CoerceDate,
+                       propertyChanged: DatePropertyChanged,
+                       defaultValueCreator: (bindable) => DateTime.Today);
+
+               public static readonly BindableProperty MinimumDateProperty = BindableProperty.Create(nameof(MinimumDate), typeof(DateTime), typeof(DatePicker), new DateTime(1900, 1, 1),
+                       validateValue: ValidateMinimumDate, coerceValue: CoerceMinimumDate);
+
+               public static readonly BindableProperty MaximumDateProperty = BindableProperty.Create(nameof(MaximumDate), typeof(DateTime), typeof(DatePicker), new DateTime(2100, 12, 31),
+                       validateValue: ValidateMaximumDate, coerceValue: CoerceMaximumDate);
+
+               public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+
+               public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
+               public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;
+
+               public static readonly BindableProperty FontSizeProperty = FontElement.FontSizeProperty;
+
+               public static readonly BindableProperty FontAttributesProperty = FontElement.FontAttributesProperty;
+
+               readonly Lazy<PlatformConfigurationRegistry<DatePicker>> _platformConfigurationRegistry;
+
+               public DatePicker()
+               {
+                       _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<DatePicker>>(() => new PlatformConfigurationRegistry<DatePicker>(this));
+               }
+
+               public DateTime Date
+               {
+                       get { return (DateTime)GetValue(DateProperty); }
+                       set { SetValue(DateProperty, value); }
+               }
+
+               public string Format
+               {
+                       get { return (string)GetValue(FormatProperty); }
+                       set { SetValue(FormatProperty, value); }
+               }
+
+               public DateTime MaximumDate
+               {
+                       get { return (DateTime)GetValue(MaximumDateProperty); }
+                       set { SetValue(MaximumDateProperty, value); }
+               }
+
+               public DateTime MinimumDate
+               {
+                       get { return (DateTime)GetValue(MinimumDateProperty); }
+                       set { SetValue(MinimumDateProperty, value); }
+               }
+
+               public Color TextColor
+               {
+                       get { return (Color)GetValue(TextElement.TextColorProperty); }
+                       set { SetValue(TextElement.TextColorProperty, value); }
+               }
+
+               public double CharacterSpacing
+               {
+                       get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+                       set { SetValue(TextElement.CharacterSpacingProperty, value); }
+               }
+
+               public FontAttributes FontAttributes
+               {
+                       get { return (FontAttributes)GetValue(FontAttributesProperty); }
+                       set { SetValue(FontAttributesProperty, value); }
+               }
+
+               public string FontFamily
+               {
+                       get { return (string)GetValue(FontFamilyProperty); }
+                       set { SetValue(FontFamilyProperty, value); }
+               }
+
+               [TypeConverter(typeof(FontSizeConverter))]
+               public double FontSize
+               {
+                       get { return (double)GetValue(FontSizeProperty); }
+                       set { SetValue(FontSizeProperty, value); }
+               }
+
+               void IFontElement.OnFontFamilyChanged(string oldValue, string newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               void IFontElement.OnFontSizeChanged(double oldValue, double newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               void IFontElement.OnFontChanged(Font oldValue, Font newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               double IFontElement.FontSizeDefaultValueCreator() =>
+                       Device.GetNamedSize(NamedSize.Default, (DatePicker)this);
+
+               void IFontElement.OnFontAttributesChanged(FontAttributes oldValue, FontAttributes newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               public event EventHandler<DateChangedEventArgs> DateSelected;
+
+               static object CoerceDate(BindableObject bindable, object value)
+               {
+                       var picker = (DatePicker)bindable;
+                       DateTime dateValue = ((DateTime)value).Date;
+
+                       if (dateValue > picker.MaximumDate)
+                               dateValue = picker.MaximumDate;
+
+                       if (dateValue < picker.MinimumDate)
+                               dateValue = picker.MinimumDate;
+
+                       return dateValue;
+               }
+
+               static object CoerceMaximumDate(BindableObject bindable, object value)
+               {
+                       DateTime dateValue = ((DateTime)value).Date;
+                       var picker = (DatePicker)bindable;
+                       if (picker.Date > dateValue)
+                               picker.Date = dateValue;
+
+                       return dateValue;
+               }
+
+               static object CoerceMinimumDate(BindableObject bindable, object value)
+               {
+                       DateTime dateValue = ((DateTime)value).Date;
+                       var picker = (DatePicker)bindable;
+                       if (picker.Date < dateValue)
+                               picker.Date = dateValue;
+
+                       return dateValue;
+               }
+
+               static void DatePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+               {
+                       var datePicker = (DatePicker)bindable;
+                       EventHandler<DateChangedEventArgs> selected = datePicker.DateSelected;
+
+                       if (selected != null)
+                               selected(datePicker, new DateChangedEventArgs((DateTime)oldValue, (DateTime)newValue));
+               }
+
+               static bool ValidateMaximumDate(BindableObject bindable, object value)
+               {
+                       return ((DateTime)value).Date >= ((DatePicker)bindable).MinimumDate.Date;
+               }
+
+               static bool ValidateMinimumDate(BindableObject bindable, object value)
+               {
+                       return ((DateTime)value).Date <= ((DatePicker)bindable).MaximumDate.Date;
+               }
+
+               public IPlatformElementConfiguration<T, DatePicker> On<T>() where T : IConfigPlatform
+               {
+                       return _platformConfigurationRegistry.Value.On<T>();
+               }
+
+               void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
+               {
+               }
+
+               void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+               {
+                       InvalidateMeasure();
+               }
+
+       }
+}
\ No newline at end of file
index 2b77978..74e6f61 100644 (file)
@@ -18,10 +18,14 @@ namespace Xamarin.Forms
 
                public new static readonly BindableProperty TextColorProperty = InputView.TextColorProperty;
 
+               public new static readonly BindableProperty CharacterSpacingProperty = InputView.CharacterSpacingProperty;
+
                public new static readonly BindableProperty PlaceholderProperty = InputView.PlaceholderProperty;
 
                public new static readonly BindableProperty PlaceholderColorProperty = InputView.PlaceholderColorProperty;
 
+               public static readonly BindableProperty IsTextPredictionEnabledProperty = BindableProperty.Create(nameof(IsTextPredictionEnabled), typeof(bool), typeof(Editor), true, BindingMode.Default);
+
                public static readonly BindableProperty AutoSizeProperty = BindableProperty.Create(nameof(AutoSize), typeof(EditorAutoSizeOption), typeof(Editor), defaultValue: EditorAutoSizeOption.Disabled, propertyChanged: (bindable, oldValue, newValue)
                        => ((Editor)bindable)?.InvalidateMeasure());
 
@@ -39,7 +43,11 @@ namespace Xamarin.Forms
                        set { SetValue(FontAttributesProperty, value); }
                }
 
-               public bool IsTextPredictionEnabled { get; set; }
+               public bool IsTextPredictionEnabled
+               {
+                       get { return (bool)GetValue(IsTextPredictionEnabledProperty); }
+                       set { SetValue(IsTextPredictionEnabledProperty, value); }
+               }
 
                public string FontFamily
                {
index b52a5ae..0cc8499 100644 (file)
@@ -25,6 +25,8 @@ namespace Xamarin.Forms
 
                public new static readonly BindableProperty TextColorProperty = InputView.TextColorProperty;
 
+               public new static readonly BindableProperty CharacterSpacingProperty = InputView.CharacterSpacingProperty;
+
                public static readonly BindableProperty HorizontalTextAlignmentProperty = TextAlignmentElement.HorizontalTextAlignmentProperty;
 
                public static readonly BindableProperty VerticalTextAlignmentProperty = TextAlignmentElement.VerticalTextAlignmentProperty;
index 714b30b..63bfe09 100644 (file)
@@ -8,6 +8,10 @@ namespace Xamarin.Forms
        [RenderWith(typeof(_FrameRenderer))]
        public class Frame : ContentView, IElementConfiguration<Frame>, IPaddingElement, IBorderElement
        {
+               [Obsolete("OutlineColorProperty is obsolete as of version 3.0.0. Please use BorderColorProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty OutlineColorProperty = BorderElement.BorderColorProperty;
+
                public static readonly BindableProperty BorderColorProperty = BorderElement.BorderColorProperty;
 
                public static readonly BindableProperty HasShadowProperty = BindableProperty.Create("HasShadow", typeof(bool), typeof(Frame), true);
@@ -33,6 +37,14 @@ namespace Xamarin.Forms
                        set { SetValue(HasShadowProperty, value); }
                }
 
+               [Obsolete("OutlineColor is obsolete as of version 3.0.0. Please use BorderColor instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public Color OutlineColor
+               {
+                       get { return (Color)GetValue(OutlineColorProperty); }
+                       set { SetValue(OutlineColorProperty, value); }
+               }
+
                public Color BorderColor
                {
                        get { return (Color)GetValue(BorderElement.BorderColorProperty); }
@@ -63,6 +75,9 @@ namespace Xamarin.Forms
 
                void IBorderElement.OnBorderColorPropertyChanged(Color oldValue, Color newValue)
                {
+#pragma warning disable 0618 // retain until OutlineColor removed
+                       OnPropertyChanged(nameof(OutlineColor));
+#pragma warning restore
                }
 
                bool IBorderElement.IsCornerRadiusSet() => IsSet(CornerRadiusProperty);
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/IMasterDetailPageController.cs b/Xamarin.Forms/Xamarin.Forms.Core/IMasterDetailPageController.cs
new file mode 100644 (file)
index 0000000..1aa019c
--- /dev/null
@@ -0,0 +1,19 @@
+using System;
+
+namespace Xamarin.Forms
+{
+       public interface IMasterDetailPageController
+       {
+               bool CanChangeIsPresented { get; set; }
+
+               Rectangle DetailBounds { get; set; }
+
+               Rectangle MasterBounds { get; set; }
+
+               bool ShouldShowSplitMode { get; }
+
+               void UpdateMasterBehavior();
+
+               event EventHandler<BackButtonPressedEventArgs> BackButtonPressed;
+       }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/ISearchBarController.cs b/Xamarin.Forms/Xamarin.Forms.Core/ISearchBarController.cs
new file mode 100644 (file)
index 0000000..8efe97b
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Xamarin.Forms
+{
+       public interface ISearchBarController
+       {
+               void OnSearchButtonPressed();
+       }
+}
\ No newline at end of file
index 32ceb6e..1e73dba 100644 (file)
@@ -33,6 +33,10 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty IsLoadingProperty = IsLoadingPropertyKey.BindableProperty;
 
+               internal static readonly BindablePropertyKey IsPressedPropertyKey = BindableProperty.CreateReadOnly(nameof(IsPressed), typeof(bool), typeof(ImageButton), default(bool));
+
+               public static readonly BindableProperty IsPressedProperty = IsPressedPropertyKey.BindableProperty;
+
                public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
 
                public event EventHandler Clicked;
@@ -73,7 +77,7 @@ namespace Xamarin.Forms
 
                public bool IsLoading => (bool)GetValue(IsLoadingProperty);
 
-               public bool IsPressed => false;
+               public bool IsPressed => (bool)GetValue(IsPressedProperty);
 
                public bool IsOpaque
                {
@@ -143,7 +147,9 @@ namespace Xamarin.Forms
                [EditorBrowsable(EditorBrowsableState.Never)]
                public void SetIsLoading(bool isLoading) => SetValue(IsLoadingPropertyKey, isLoading);
 
-               public void SetIsPressed(bool isPressed) { }
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public void SetIsPressed(bool isPressed) =>
+                       SetValue(IsPressedPropertyKey, isPressed);
 
                [EditorBrowsable(EditorBrowsableState.Never)]
                public void SendClicked() =>
index 8e4d853..f7490cb 100644 (file)
@@ -95,6 +95,7 @@ namespace Xamarin.Forms
 
                void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
                {
+                       InvalidateMeasure();
                }
        }
 
index e1ea841..4b95d37 100644 (file)
@@ -10,10 +10,18 @@ namespace Xamarin.Forms.Internals
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class ToolbarTracker
        {
+               int _masterDetails;
                Page _target;
 
                public IEnumerable<Page> AdditionalTargets { get; set; }
 
+               public bool HaveMasterDetail
+               {
+                       get { return _masterDetails > 0; }
+               }
+
+               public bool SeparateMasterDetail { get; set; }
+
                public Page Target
                {
                        get { return _target; }
@@ -55,7 +63,31 @@ namespace Xamarin.Forms.Internals
                        var result = new List<ToolbarItem>();
                        result.AddRange(page.ToolbarItems);
 
-                       if (page is IPageContainer<Page>)
+                       if (page is MasterDetailPage)
+                       {
+                               var masterDetail = (MasterDetailPage)page;
+                               if (SeparateMasterDetail)
+                               {
+                                       if (masterDetail.IsPresented)
+                                       {
+                                               if (masterDetail.Master != null)
+                                                       result.AddRange(GetCurrentToolbarItems(masterDetail.Master));
+                                       }
+                                       else
+                                       {
+                                               if (masterDetail.Detail != null)
+                                                       result.AddRange(GetCurrentToolbarItems(masterDetail.Detail));
+                                       }
+                               }
+                               else
+                               {
+                                       if (masterDetail.Master != null)
+                                               result.AddRange(GetCurrentToolbarItems(masterDetail.Master));
+                                       if (masterDetail.Detail != null)
+                                               result.AddRange(GetCurrentToolbarItems(masterDetail.Detail));
+                               }
+                       }
+                       else if (page is IPageContainer<Page>)
                        {
                                var container = (IPageContainer<Page>)page;
                                if (container.CurrentPage != null)
@@ -90,7 +122,8 @@ namespace Xamarin.Forms.Internals
 
                void OnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
                {
-                       if (propertyChangedEventArgs.PropertyName == NavigationPage.CurrentPageProperty.PropertyName)
+                       if (propertyChangedEventArgs.PropertyName == NavigationPage.CurrentPageProperty.PropertyName || propertyChangedEventArgs.PropertyName == MasterDetailPage.IsPresentedProperty.PropertyName ||
+                               propertyChangedEventArgs.PropertyName == "Detail" || propertyChangedEventArgs.PropertyName == "Master")
                        {
                                EmitCollectionChanged();
                        }
@@ -98,6 +131,9 @@ namespace Xamarin.Forms.Internals
 
                void RegisterChildPage(Page page)
                {
+                       if (page is MasterDetailPage)
+                               _masterDetails++;
+
                        ((ObservableCollection<ToolbarItem>)page.ToolbarItems).CollectionChanged += OnCollectionChanged;
                        page.PropertyChanged += OnPropertyChanged;
                }
@@ -107,6 +143,9 @@ namespace Xamarin.Forms.Internals
                        if (page == null)
                                return;
 
+                       if (page is MasterDetailPage)
+                               _masterDetails++;
+
                        ((ObservableCollection<ToolbarItem>)page.ToolbarItems).CollectionChanged += OnCollectionChanged;
                        page.Descendants().OfType<Page>().ForEach(RegisterChildPage);
 
@@ -117,6 +156,9 @@ namespace Xamarin.Forms.Internals
 
                void UnregisterChildPage(Page page)
                {
+                       if (page is MasterDetailPage)
+                               _masterDetails--;
+
                        ((ObservableCollection<ToolbarItem>)page.ToolbarItems).CollectionChanged -= OnCollectionChanged;
                        page.PropertyChanged -= OnPropertyChanged;
                }
@@ -126,6 +168,9 @@ namespace Xamarin.Forms.Internals
                        if (page == null)
                                return;
 
+                       if (page is MasterDetailPage)
+                               _masterDetails--;
+
                        ((ObservableCollection<ToolbarItem>)page.ToolbarItems).CollectionChanged -= OnCollectionChanged;
                        page.Descendants().OfType<Page>().ForEach(UnregisterChildPage);
 
index 2b852f5..9126181 100644 (file)
@@ -15,9 +15,17 @@ namespace Xamarin.Forms
        {
                public static readonly BindableProperty HorizontalTextAlignmentProperty = TextAlignmentElement.HorizontalTextAlignmentProperty;
 
+               [Obsolete("XAlignProperty is obsolete as of version 2.0.0. Please use HorizontalTextAlignmentProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty XAlignProperty = HorizontalTextAlignmentProperty;
+
                public static readonly BindableProperty VerticalTextAlignmentProperty = BindableProperty.Create("VerticalTextAlignment", typeof(TextAlignment), typeof(Label), TextAlignment.Start,
                        propertyChanged: OnVerticalTextAlignmentPropertyChanged);
 
+               [Obsolete("YAlignProperty is obsolete as of version 2.0.0. Please use VerticalTextAlignmentProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty YAlignProperty = VerticalTextAlignmentProperty;
+
                public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
 
                public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
@@ -72,6 +80,14 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty LineHeightProperty = LineHeightElement.LineHeightProperty;
 
+               public static readonly BindableProperty MaxLinesProperty = BindableProperty.Create(nameof(MaxLines), typeof(int), typeof(Label), -1, propertyChanged: (bindable, oldvalue, newvalue) =>
+                       {
+                               if (bindable != null)
+                               {
+                                       ((Label)bindable).InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+                               }
+                       });
+
                public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
                
                public static readonly BindableProperty TextTypeProperty = BindableProperty.Create(nameof(TextType), typeof(TextType), typeof(Label), TextType.Text,
@@ -141,6 +157,22 @@ namespace Xamarin.Forms
                        set { SetValue(VerticalTextAlignmentProperty, value); }
                }
 
+               [Obsolete("XAlign is obsolete as of version 2.0.0. Please use HorizontalTextAlignment instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public TextAlignment XAlign
+               {
+                       get { return (TextAlignment)GetValue(XAlignProperty); }
+                       set { SetValue(XAlignProperty, value); }
+               }
+
+               [Obsolete("YAlign is obsolete as of version 2.0.0. Please use VerticalTextAlignment instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public TextAlignment YAlign
+               {
+                       get { return (TextAlignment)GetValue(YAlignProperty); }
+                       set { SetValue(YAlignProperty, value); }
+               }
+
                public FontAttributes FontAttributes
                {
                        get { return (FontAttributes)GetValue(FontAttributesProperty); }
@@ -172,6 +204,12 @@ namespace Xamarin.Forms
                        set { SetValue(LineHeightProperty, value); }
                }
 
+               public int MaxLines
+               {
+                       get => (int)GetValue(MaxLinesProperty);
+                       set => SetValue(MaxLinesProperty, value);
+               }
+
                public Thickness Padding
                {
                        get { return (Thickness)GetValue(PaddingProperty); }
@@ -289,6 +327,9 @@ namespace Xamarin.Forms
 
                void ITextAlignmentElement.OnHorizontalTextAlignmentPropertyChanged(TextAlignment oldValue, TextAlignment newValue)
                {
+#pragma warning disable 0618 // retain until XAlign removed
+                       OnPropertyChanged(nameof(XAlign));
+#pragma warning restore
                }
 
                static void OnTextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
@@ -305,6 +346,10 @@ namespace Xamarin.Forms
 
                static void OnVerticalTextAlignmentPropertyChanged(BindableObject bindable, object oldValue, object newValue)
                {
+                       var label = (Label)bindable;
+#pragma warning disable 0618 // retain until YAlign removed
+                       label.OnPropertyChanged(nameof(YAlign));
+#pragma warning restore 0618
                }
 
                public IPlatformElementConfiguration<T, Label> On<T>() where T : IConfigPlatform
@@ -318,8 +363,10 @@ namespace Xamarin.Forms
 
                void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
                {
+                       InvalidateMeasure();
                }
 
+
                public override IList<GestureElement> GetChildElements(Point point)
                {
                        if (FormattedText?.Spans == null || FormattedText?.Spans.Count == 0)
index 98badd4..64e7d5b 100644 (file)
@@ -52,6 +52,8 @@ namespace Xamarin.Forms
 
        public abstract class Layout : View, ILayout, ILayoutController, IPaddingElement
        {
+               public static readonly BindableProperty IsClippedToBoundsProperty = BindableProperty.Create("IsClippedToBounds", typeof(bool), typeof(Layout), false);
+
                public static readonly BindableProperty CascadeInputTransparentProperty = BindableProperty.Create(
                        nameof(CascadeInputTransparent), typeof(bool), typeof(Layout), true);
 
@@ -75,6 +77,12 @@ namespace Xamarin.Forms
                        InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged;
                }
 
+               public bool IsClippedToBounds
+               {
+                       get { return (bool)GetValue(IsClippedToBoundsProperty); }
+                       set { SetValue(IsClippedToBoundsProperty, value); }
+               }
+
                public Thickness Padding
                {
                        get { return (Thickness)GetValue(PaddingElement.PaddingProperty); }
index 03cc6c1..cd8ecd6 100644 (file)
@@ -12,6 +12,10 @@ namespace Xamarin.Forms
        [RenderWith(typeof(_ListViewRenderer))]
        public class ListView : ItemsView<Cell>, IListViewController, IElementConfiguration<ListView>
        {
+               public static readonly BindableProperty IsPullToRefreshEnabledProperty = BindableProperty.Create("IsPullToRefreshEnabled", typeof(bool), typeof(ListView), false);
+
+               public static readonly BindableProperty IsRefreshingProperty = BindableProperty.Create("IsRefreshing", typeof(bool), typeof(ListView), false, BindingMode.TwoWay);
+
                public static readonly BindableProperty RefreshCommandProperty = BindableProperty.Create("RefreshCommand", typeof(ICommand), typeof(ListView), null, propertyChanged: OnRefreshCommandChanged);
 
                public static readonly BindableProperty HeaderProperty = BindableProperty.Create("Header", typeof(object), typeof(ListView), null, propertyChanged: OnHeaderChanged);
@@ -40,6 +44,14 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty SeparatorVisibilityProperty = BindableProperty.Create("SeparatorVisibility", typeof(SeparatorVisibility), typeof(ListView), SeparatorVisibility.Default);
 
+               public static readonly BindableProperty SeparatorColorProperty = BindableProperty.Create("SeparatorColor", typeof(Color), typeof(ListView), Color.Default);
+
+               public static readonly BindableProperty RefreshControlColorProperty = BindableProperty.Create(nameof(RefreshControlColor), typeof(Color), typeof(ListView), Color.Default);
+       
+               public static readonly BindableProperty HorizontalScrollBarVisibilityProperty = BindableProperty.Create(nameof(HorizontalScrollBarVisibility), typeof(ScrollBarVisibility), typeof(ListView), ScrollBarVisibility.Default);
+
+               public static readonly BindableProperty VerticalScrollBarVisibilityProperty = BindableProperty.Create(nameof(VerticalScrollBarVisibility), typeof(ScrollBarVisibility), typeof(ListView), ScrollBarVisibility.Default);
+
                static readonly ToStringValueConverter _toStringValueConverter = new ToStringValueConverter();
 
                readonly Lazy<PlatformConfigurationRegistry<ListView>> _platformConfigurationRegistry;
@@ -171,6 +183,18 @@ namespace Xamarin.Forms
                        set { SetValue(IsGroupingEnabledProperty, value); }
                }
 
+               public bool IsPullToRefreshEnabled
+               {
+                       get { return (bool)GetValue(IsPullToRefreshEnabledProperty); }
+                       set { SetValue(IsPullToRefreshEnabledProperty, value); }
+               }
+
+               public bool IsRefreshing
+               {
+                       get { return (bool)GetValue(IsRefreshingProperty); }
+                       set { SetValue(IsRefreshingProperty, value); }
+               }
+
                public ICommand RefreshCommand
                {
                        get { return (ICommand)GetValue(RefreshCommandProperty); }
@@ -195,12 +219,35 @@ namespace Xamarin.Forms
                        set { SetValue(SelectionModeProperty, value); }
                }
 
+               public Color SeparatorColor
+               {
+                       get { return (Color)GetValue(SeparatorColorProperty); }
+                       set { SetValue(SeparatorColorProperty, value); }
+               }
+
+               public Color RefreshControlColor
+               {
+                       get { return (Color)GetValue(RefreshControlColorProperty); }
+                       set { SetValue(RefreshControlColorProperty, value); }
+               }
+
                public SeparatorVisibility SeparatorVisibility
                {
                        get { return (SeparatorVisibility)GetValue(SeparatorVisibilityProperty); }
                        set { SetValue(SeparatorVisibilityProperty, value); }
                }
 
+               public ScrollBarVisibility HorizontalScrollBarVisibility
+               {
+                       get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); }
+                       set { SetValue(HorizontalScrollBarVisibilityProperty, value); }
+               }
+               public ScrollBarVisibility VerticalScrollBarVisibility
+               {
+                       get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); }
+                       set { SetValue(VerticalScrollBarVisibilityProperty, value); }
+               }
+
                public ListViewCachingStrategy CachingStrategy { get; private set; }
 
                [EditorBrowsable(EditorBrowsableState.Never)]
@@ -252,6 +299,7 @@ namespace Xamarin.Forms
                        if (!RefreshAllowed)
                                return;
 
+                       SetValueCore(IsRefreshingProperty, true);
                        OnRefreshing(EventArgs.Empty);
 
                        ICommand command = RefreshCommand;
@@ -261,6 +309,7 @@ namespace Xamarin.Forms
 
                public void EndRefresh()
                {
+                       SetValueCore(IsRefreshingProperty, false);
                }
 
                public event EventHandler<ItemVisibilityEventArgs> ItemAppearing;
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/MasterBehavior.cs b/Xamarin.Forms/Xamarin.Forms.Core/MasterBehavior.cs
new file mode 100644 (file)
index 0000000..cd2dae2
--- /dev/null
@@ -0,0 +1,11 @@
+namespace Xamarin.Forms
+{
+       public enum MasterBehavior
+       {
+               Default = 0,
+               SplitOnLandscape = 1,
+               Split = 2,
+               Popover = 3,
+               SplitOnPortrait = 4
+       }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/MasterDetailPage.cs b/Xamarin.Forms/Xamarin.Forms.Core/MasterDetailPage.cs
new file mode 100644 (file)
index 0000000..fd3669e
--- /dev/null
@@ -0,0 +1,255 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Platform;
+
+namespace Xamarin.Forms
+{
+       [RenderWith(typeof(_MasterDetailPageRenderer))]
+       public class MasterDetailPage : Page, IMasterDetailPageController, IElementConfiguration<MasterDetailPage>
+       {
+               public static readonly BindableProperty IsGestureEnabledProperty = BindableProperty.Create("IsGestureEnabled", typeof(bool), typeof(MasterDetailPage), true);
+
+               public static readonly BindableProperty IsPresentedProperty = BindableProperty.Create("IsPresented", typeof(bool), typeof(MasterDetailPage),default(bool),
+                       propertyChanged: OnIsPresentedPropertyChanged, propertyChanging: OnIsPresentedPropertyChanging, defaultValueCreator : GetDefaultValue);
+
+               public static readonly BindableProperty MasterBehaviorProperty = BindableProperty.Create("MasterBehavior", typeof(MasterBehavior), typeof(MasterDetailPage), default(MasterBehavior),
+                       propertyChanged: OnMasterBehaviorPropertyChanged);
+
+               Page _detail;
+
+               Rectangle _detailBounds;
+
+               Page _master;
+
+               Rectangle _masterBounds;
+
+               public Page Detail
+               {
+                       get { return _detail; }
+                       set
+                       {
+                               if (_detail != null && value == null)
+                                       throw new ArgumentNullException("value", "Detail cannot be set to null once a value is set.");
+
+                               if (_detail == value)
+                                       return;
+
+                               if (value.RealParent != null)
+                                       throw new InvalidOperationException("Detail must not already have a parent.");
+
+                               OnPropertyChanging();
+                               if (_detail != null)
+                                       InternalChildren.Remove(_detail);
+                               _detail = value;
+                               InternalChildren.Add(_detail);
+                               OnPropertyChanged();
+                       }
+               }
+
+               public bool IsGestureEnabled
+               {
+                       get { return (bool)GetValue(IsGestureEnabledProperty); }
+                       set { SetValue(IsGestureEnabledProperty, value); }
+               }
+
+               public bool IsPresented
+               {
+                       get { return (bool)GetValue(IsPresentedProperty); }
+                       set { SetValue(IsPresentedProperty, value); }
+               }
+
+               public Page Master
+               {
+                       get { return _master; }
+                       set
+                       {
+                               if (_master != null && value == null)
+                                       throw new ArgumentNullException("value", "Master cannot be set to null once a value is set");
+
+                               if (string.IsNullOrEmpty(value.Title))
+                                       throw new InvalidOperationException("Title property must be set on Master page");
+
+                               if (_master == value)
+                                       return;
+
+                               if (value.RealParent != null)
+                                       throw new InvalidOperationException("Master must not already have a parent.");
+
+                               OnPropertyChanging();
+                               if (_master != null)
+                                       InternalChildren.Remove(_master);
+                               _master = value;
+                               InternalChildren.Add(_master);
+                               OnPropertyChanged();
+                       }
+               }
+
+               public MasterBehavior MasterBehavior
+               {
+                       get { return (MasterBehavior)GetValue(MasterBehaviorProperty); }
+                       set { SetValue(MasterBehaviorProperty, value); }
+               }
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public bool CanChangeIsPresented { get; set; } = true;
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public Rectangle DetailBounds
+               {
+                       get { return _detailBounds; }
+                       set
+                       {
+                               _detailBounds = value;
+                               if (_detail == null)
+                                       throw new InvalidOperationException("Detail must be set before using a MasterDetailPage");
+                               _detail.Layout(value);
+                       }
+               }
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public Rectangle MasterBounds
+               {
+                       get { return _masterBounds; }
+                       set
+                       {
+                               _masterBounds = value;
+                               if (_master == null)
+                                       throw new InvalidOperationException("Master must be set before using a MasterDetailPage");
+                               _master.Layout(value);
+                       }
+               }
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public bool ShouldShowSplitMode
+               {
+                       get
+                       {
+                               if (Device.Idiom == TargetIdiom.Phone)
+                                       return false;
+
+                               MasterBehavior behavior = MasterBehavior;
+                               DeviceOrientation orientation = Device.Info.CurrentOrientation;
+
+                               bool isSplitOnLandscape = (behavior == MasterBehavior.SplitOnLandscape || behavior == MasterBehavior.Default) && orientation.IsLandscape();
+                               bool isSplitOnPortrait = behavior == MasterBehavior.SplitOnPortrait && orientation.IsPortrait();
+                               return behavior == MasterBehavior.Split || isSplitOnLandscape || isSplitOnPortrait;
+                       }
+               }
+
+               public event EventHandler IsPresentedChanged;
+
+               public virtual bool ShouldShowToolbarButton()
+               {
+                       if (Device.Idiom == TargetIdiom.Phone)
+                               return true;
+
+                       MasterBehavior behavior = MasterBehavior;
+                       DeviceOrientation orientation = Device.Info.CurrentOrientation;
+
+                       bool isSplitOnLandscape = (behavior == MasterBehavior.SplitOnLandscape || behavior == MasterBehavior.Default) && orientation.IsLandscape();
+                       bool isSplitOnPortrait = behavior == MasterBehavior.SplitOnPortrait && orientation.IsPortrait();
+                       return behavior != MasterBehavior.Split && !isSplitOnLandscape && !isSplitOnPortrait;
+               }
+
+               protected override void LayoutChildren(double x, double y, double width, double height)
+               {
+                       if (Master == null || Detail == null)
+                               throw new InvalidOperationException("Master and Detail must be set before using a MasterDetailPage");
+                       _master.Layout(_masterBounds);
+                       _detail.Layout(_detailBounds);
+               }
+
+               protected override void OnAppearing()
+               {
+                       CanChangeIsPresented = true;
+                       UpdateMasterBehavior(this);
+                       base.OnAppearing();
+               }
+
+               protected override bool OnBackButtonPressed()
+               {
+                       if (IsPresented)
+                       {
+                               if (Master.SendBackButtonPressed())
+                                       return true;
+                       }
+
+                       EventHandler<BackButtonPressedEventArgs> handler = BackButtonPressed;
+                       if (handler != null)
+                       {
+                               var args = new BackButtonPressedEventArgs();
+                               handler(this, args);
+                               if (args.Handled)
+                                       return true;
+                       }
+
+                       if (Detail.SendBackButtonPressed())
+                       {
+                               return true;
+                       }
+
+                       return base.OnBackButtonPressed();
+               }
+
+               protected override void OnParentSet()
+               {
+                       if (RealParent != null && (Master == null || Detail == null))
+                               throw new InvalidOperationException("Master and Detail must be set before adding MasterDetailPage to a container");
+                       base.OnParentSet();
+               }
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public event EventHandler<BackButtonPressedEventArgs> BackButtonPressed;
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public void UpdateMasterBehavior()
+               {
+                       UpdateMasterBehavior(this);
+               }
+
+               internal static void UpdateMasterBehavior(MasterDetailPage page)
+               {
+                       if (page.ShouldShowSplitMode)
+                       {
+                               page.SetValueCore(IsPresentedProperty, true);
+                               if (page.MasterBehavior != MasterBehavior.Default)
+                                       page.CanChangeIsPresented = false;
+                       }
+               }
+
+               static void OnIsPresentedPropertyChanged(BindableObject sender, object oldValue, object newValue)
+                       => ((MasterDetailPage)sender).IsPresentedChanged?.Invoke(sender, EventArgs.Empty);
+
+               static void OnIsPresentedPropertyChanging(BindableObject sender, object oldValue, object newValue)
+               {
+                       var page = (MasterDetailPage)sender;
+                       if (!page.CanChangeIsPresented)
+                               throw new InvalidOperationException(string.Format("Can't change IsPresented when setting {0}", page.MasterBehavior));
+               }
+
+               static void OnMasterBehaviorPropertyChanged(BindableObject sender, object oldValue, object newValue)
+               {
+                       var page = (MasterDetailPage)sender;
+                       UpdateMasterBehavior(page);
+               }
+
+               static object GetDefaultValue(BindableObject bindable)
+               {
+                       return Device.RuntimePlatform == Device.macOS;
+               }
+
+               public MasterDetailPage()
+               {
+                       _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<MasterDetailPage>>(() => new PlatformConfigurationRegistry<MasterDetailPage>(this));
+               }
+
+               readonly Lazy<PlatformConfigurationRegistry<MasterDetailPage>> _platformConfigurationRegistry;
+
+               public new IPlatformElementConfiguration<T, MasterDetailPage> On<T>() where T : IConfigPlatform
+               {
+                       return _platformConfigurationRegistry.Value.On<T>();
+               }
+       }
+}
\ No newline at end of file
index aaac21a..28a68cc 100644 (file)
@@ -12,12 +12,26 @@ namespace Xamarin.Forms
        [RenderWith(typeof(_NavigationPageRenderer))]
        public class NavigationPage : Page, IPageContainer<Page>, IBarElement, INavigationPageController, IElementConfiguration<NavigationPage> 
        {
+               public static readonly BindableProperty BackButtonTitleProperty = BindableProperty.CreateAttached("BackButtonTitle", typeof(string), typeof(Page), null);
+
                public static readonly BindableProperty HasNavigationBarProperty = BindableProperty.CreateAttached("HasNavigationBar", typeof(bool), typeof(Page), true);
 
+               public static readonly BindableProperty HasBackButtonProperty = BindableProperty.CreateAttached("HasBackButton", typeof(bool), typeof(NavigationPage), true);
+
+               [Obsolete("TintProperty is obsolete as of version 1.2.0. Please use BarBackgroundColorProperty and BarTextColorProperty to change NavigationPage bar color properties.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty TintProperty = BindableProperty.Create("Tint", typeof(Color), typeof(NavigationPage), Color.Default);
+
                public static readonly BindableProperty BarBackgroundColorProperty = BarElement.BarBackgroundColorProperty;
 
                public static readonly BindableProperty BarTextColorProperty = BarElement.BarTextColorProperty;
 
+               public static readonly BindableProperty TitleIconImageSourceProperty = BindableProperty.CreateAttached("TitleIconImageSource", typeof(ImageSource), typeof(NavigationPage), default(ImageSource));
+
+               [Obsolete("TitleIconProperty is obsolete as of 4.0.0. Please use TitleIconImageSourceProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty TitleIconProperty = TitleIconImageSourceProperty;
+
                public static readonly BindableProperty TitleViewProperty = BindableProperty.CreateAttached("TitleView", typeof(View), typeof(NavigationPage), null, propertyChanging: TitleViewPropertyChanging);
 
                static readonly BindablePropertyKey CurrentPagePropertyKey = BindableProperty.CreateReadOnly("CurrentPage", typeof(Page), typeof(NavigationPage), null);
@@ -48,6 +62,14 @@ namespace Xamarin.Forms
                        set => SetValue(BarElement.BarTextColorProperty, value);
                }
 
+               [Obsolete("Tint is obsolete as of version 1.2.0. Please use BarBackgroundColor and BarTextColor to change NavigationPage bar color properties.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public Color Tint
+               {
+                       get { return (Color)GetValue(TintProperty); }
+                       set { SetValue(TintProperty, value); }
+               }
+
                internal Task CurrentNavigationTask { get; set; }
 
                [EditorBrowsable(EditorBrowsableState.Never)]
@@ -103,11 +125,35 @@ namespace Xamarin.Forms
                        }
                }
 
+               public static string GetBackButtonTitle(BindableObject page)
+               {
+                       return (string)page.GetValue(BackButtonTitleProperty);
+               }
+
+               public static bool GetHasBackButton(Page page)
+               {
+                       if (page == null)
+                               throw new ArgumentNullException("page");
+                       return (bool)page.GetValue(HasBackButtonProperty);
+               }
+
                public static bool GetHasNavigationBar(BindableObject page)
                {
                        return (bool)page.GetValue(HasNavigationBarProperty);
                }
 
+               [Obsolete("GetTitleIcon is obsolete as of 4.0.0. Please use GetTitleIconImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static FileImageSource GetTitleIcon(BindableObject bindable)
+               {
+                       return bindable.GetValue(TitleIconImageSourceProperty) as FileImageSource;
+               }
+
+               public static ImageSource GetTitleIconImageSource(BindableObject bindable)
+               {
+                       return (ImageSource)bindable.GetValue(TitleIconImageSourceProperty);
+               }
+
                public static View GetTitleView(BindableObject bindable)
                {
                        return (View)bindable.GetValue(TitleViewProperty);
@@ -198,11 +244,35 @@ namespace Xamarin.Forms
 
                public event EventHandler<NavigationEventArgs> Pushed;
 
+               public static void SetBackButtonTitle(BindableObject page, string value)
+               {
+                       page.SetValue(BackButtonTitleProperty, value);
+               }
+
+               public static void SetHasBackButton(Page page, bool value)
+               {
+                       if (page == null)
+                               throw new ArgumentNullException("page");
+                       page.SetValue(HasBackButtonProperty, value);
+               }
+
                public static void SetHasNavigationBar(BindableObject page, bool value)
                {
                        page.SetValue(HasNavigationBarProperty, value);
                }
 
+               [Obsolete("SetTitleIcon is obsolete as of 4.0.0. Please use SetTitleIconImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static void SetTitleIcon(BindableObject bindable, FileImageSource value)
+               {
+                       bindable.SetValue(TitleIconImageSourceProperty, value);
+               }
+
+               public static void SetTitleIconImageSource(BindableObject bindable, ImageSource value)
+               {
+                       bindable.SetValue(TitleIconImageSourceProperty, value);
+               }
+
                public static void SetTitleView(BindableObject bindable, View value)
                {
                        bindable.SetValue(TitleViewProperty, value);
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/Picker.cs b/Xamarin.Forms/Xamarin.Forms.Core/Picker.cs
new file mode 100644 (file)
index 0000000..56f10fd
--- /dev/null
@@ -0,0 +1,294 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Platform;
+
+namespace Xamarin.Forms
+{
+       [RenderWith(typeof(_PickerRenderer))]
+       public class Picker : View, IFontElement, ITextElement, IElementConfiguration<Picker>
+       {
+               public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+
+               public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
+               public static readonly BindableProperty TitleProperty =
+                       BindableProperty.Create(nameof(Title), typeof(string), typeof(Picker), default(string));
+
+               public static readonly BindableProperty TitleColorProperty =
+                       BindableProperty.Create(nameof(TitleColor), typeof(Color), typeof(Picker), default(Color));
+
+               public static readonly BindableProperty SelectedIndexProperty =
+                       BindableProperty.Create(nameof(SelectedIndex), typeof(int), typeof(Picker), -1, BindingMode.TwoWay,
+                                                                       propertyChanged: OnSelectedIndexChanged, coerceValue: CoerceSelectedIndex);
+
+               public static readonly BindableProperty ItemsSourceProperty =
+                       BindableProperty.Create(nameof(ItemsSource), typeof(IList), typeof(Picker), default(IList),
+                                                                       propertyChanged: OnItemsSourceChanged);
+
+               public static readonly BindableProperty SelectedItemProperty =
+                       BindableProperty.Create(nameof(SelectedItem), typeof(object), typeof(Picker), null, BindingMode.TwoWay,
+                                                                       propertyChanged: OnSelectedItemChanged);
+
+               public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;
+
+               public static readonly BindableProperty FontSizeProperty = FontElement.FontSizeProperty;
+
+               public static readonly BindableProperty FontAttributesProperty = FontElement.FontAttributesProperty;
+               
+               readonly Lazy<PlatformConfigurationRegistry<Picker>> _platformConfigurationRegistry;
+
+               public Picker()
+               {
+                       ((INotifyCollectionChanged)Items).CollectionChanged += OnItemsCollectionChanged;
+                       _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Picker>>(() => new PlatformConfigurationRegistry<Picker>(this));
+               }
+               public FontAttributes FontAttributes
+               {
+                       get { return (FontAttributes)GetValue(FontAttributesProperty); }
+                       set { SetValue(FontAttributesProperty, value); }
+               }
+
+               public string FontFamily
+               {
+                       get { return (string)GetValue(FontFamilyProperty); }
+                       set { SetValue(FontFamilyProperty, value); }
+               }
+
+               [TypeConverter(typeof(FontSizeConverter))]
+               public double FontSize
+               {
+                       get { return (double)GetValue(FontSizeProperty); }
+                       set { SetValue(FontSizeProperty, value); }
+               }
+
+               void IFontElement.OnFontFamilyChanged(string oldValue, string newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               void IFontElement.OnFontSizeChanged(double oldValue, double newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               void IFontElement.OnFontChanged(Font oldValue, Font newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               double IFontElement.FontSizeDefaultValueCreator() =>
+                       Device.GetNamedSize(NamedSize.Default, (Picker)this);
+
+               void IFontElement.OnFontAttributesChanged(FontAttributes oldValue, FontAttributes newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               public IList<string> Items { get; } = new LockableObservableListWrapper();
+
+               public IList ItemsSource
+               {
+                       get { return (IList)GetValue(ItemsSourceProperty); }
+                       set { SetValue(ItemsSourceProperty, value); }
+               }
+
+               public int SelectedIndex
+               {
+                       get { return (int)GetValue(SelectedIndexProperty); }
+                       set { SetValue(SelectedIndexProperty, value); }
+               }
+
+               public object SelectedItem
+               {
+                       get { return GetValue(SelectedItemProperty); }
+                       set { SetValue(SelectedItemProperty, value); }
+               }
+
+               public Color TextColor
+               {
+                       get { return (Color)GetValue(TextElement.TextColorProperty); }
+                       set { SetValue(TextElement.TextColorProperty, value); }
+               }
+
+               public double CharacterSpacing
+               {
+                       get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+                       set { SetValue(TextElement.CharacterSpacingProperty, value); }
+               }
+
+               public string Title
+               {
+                       get { return (string)GetValue(TitleProperty); }
+                       set { SetValue(TitleProperty, value); }
+               }
+
+               public Color TitleColor
+               {
+                       get { return (Color)GetValue(TitleColorProperty); }
+                       set { SetValue(TitleColorProperty, value); }
+               }
+
+               BindingBase _itemDisplayBinding;
+               public BindingBase ItemDisplayBinding {
+                       get { return _itemDisplayBinding; }
+                       set {
+                               if (_itemDisplayBinding == value)
+                                       return;
+
+                               OnPropertyChanging();
+                               var oldValue = value;
+                               _itemDisplayBinding = value;
+                               OnItemDisplayBindingChanged(oldValue, _itemDisplayBinding);
+                               OnPropertyChanged();
+                       }
+               }
+
+               public event EventHandler SelectedIndexChanged;
+
+               static readonly BindableProperty s_displayProperty =
+                       BindableProperty.Create("Display", typeof(string), typeof(Picker), default(string));
+
+               string GetDisplayMember(object item)
+               {
+                       if (ItemDisplayBinding == null)
+                               return item.ToString();
+
+                       ItemDisplayBinding.Apply(item, this, s_displayProperty);
+                       ItemDisplayBinding.Unapply();
+                       return (string)GetValue(s_displayProperty);
+               }
+
+               static object CoerceSelectedIndex(BindableObject bindable, object value)
+               {
+                       var picker = (Picker)bindable;
+                       return picker.Items == null ? -1 : ((int)value).Clamp(-1, picker.Items.Count - 1);
+               }
+
+               void OnItemDisplayBindingChanged(BindingBase oldValue, BindingBase newValue)
+               {
+                       ResetItems();
+               }
+
+               void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+               {
+                       var oldIndex = SelectedIndex;
+                       var newIndex = SelectedIndex = SelectedIndex.Clamp(-1, Items.Count - 1);
+                       // If the index has not changed, still need to change the selected item
+                       if (newIndex == oldIndex)
+                               UpdateSelectedItem(newIndex);
+               }
+
+               static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
+               {
+                       ((Picker)bindable).OnItemsSourceChanged((IList)oldValue, (IList)newValue);
+               }
+
+               void OnItemsSourceChanged(IList oldValue, IList newValue)
+               { 
+                       var oldObservable = oldValue as INotifyCollectionChanged;
+                       if (oldObservable != null)
+                               oldObservable.CollectionChanged -= CollectionChanged;
+
+                       var newObservable = newValue as INotifyCollectionChanged;
+                       if (newObservable != null) {
+                               newObservable.CollectionChanged += CollectionChanged;
+                       }
+
+                       if (newValue != null) {
+                               ((LockableObservableListWrapper)Items).IsLocked = true;
+                               ResetItems();
+                       } else {
+                               ((LockableObservableListWrapper)Items).InternalClear();
+                               ((LockableObservableListWrapper)Items).IsLocked = false;
+                       }
+               }
+
+               void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+               {
+                       switch (e.Action) {
+                       case NotifyCollectionChangedAction.Add:
+                               AddItems(e);
+                               break;
+                       case NotifyCollectionChangedAction.Remove:
+                               RemoveItems(e);
+                               break;
+                       default: //Move, Replace, Reset
+                               ResetItems();
+                               break;
+                       }
+               }
+               void AddItems(NotifyCollectionChangedEventArgs e)
+               {
+                       int index = e.NewStartingIndex < 0 ? Items.Count : e.NewStartingIndex;
+                       foreach (object newItem in e.NewItems)
+                               ((LockableObservableListWrapper)Items).InternalInsert(index++, GetDisplayMember(newItem));
+               }
+
+               void RemoveItems(NotifyCollectionChangedEventArgs e)
+               {
+                       int index = e.OldStartingIndex < Items.Count ? e.OldStartingIndex : Items.Count;
+                       foreach (object _ in e.OldItems)
+                               ((LockableObservableListWrapper)Items).InternalRemoveAt(index--);
+               }
+
+               void ResetItems()
+               {
+                       if (ItemsSource == null)
+                               return;
+                       ((LockableObservableListWrapper)Items).InternalClear();
+                       foreach (object item in ItemsSource)
+                               ((LockableObservableListWrapper)Items).InternalAdd(GetDisplayMember(item));
+                       UpdateSelectedItem(SelectedIndex);
+               }
+
+               static void OnSelectedIndexChanged(object bindable, object oldValue, object newValue)
+               {
+                       var picker = (Picker)bindable;
+                       picker.UpdateSelectedItem(picker.SelectedIndex);
+                       picker.SelectedIndexChanged?.Invoke(bindable, EventArgs.Empty);
+               }
+
+               static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
+               {
+                       var picker = (Picker)bindable;
+                       picker.UpdateSelectedIndex(newValue);
+               }
+
+               void UpdateSelectedIndex(object selectedItem)
+               {
+                       if (ItemsSource != null) {
+                               SelectedIndex = ItemsSource.IndexOf(selectedItem);
+                               return;
+                       }
+                       SelectedIndex = Items.IndexOf(selectedItem);
+               }
+
+               void UpdateSelectedItem(int index)
+               {
+                       if (index == -1) {
+                               SelectedItem = null;
+                               return;
+                       }
+
+                       if (ItemsSource != null) {
+                               SelectedItem = ItemsSource [index];
+                               return;
+                       }
+
+                       SelectedItem = Items [index];
+               }
+
+               public IPlatformElementConfiguration<T, Picker> On<T>() where T : IConfigPlatform
+               {
+                       return _platformConfigurationRegistry.Value.On<T>();
+               }
+
+               void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
+               {
+               }
+
+               void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+               {
+                       InvalidateMeasure();
+               }
+
+       }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/PlatformConfiguration/TizenSpecific/NavigationPage.cs b/Xamarin.Forms/Xamarin.Forms.Core/PlatformConfiguration/TizenSpecific/NavigationPage.cs
new file mode 100644 (file)
index 0000000..3522239
--- /dev/null
@@ -0,0 +1,33 @@
+namespace Xamarin.Forms.PlatformConfiguration.TizenSpecific
+{
+       using FormsElement = Forms.NavigationPage;
+
+       public static class NavigationPage
+       {
+               #region HasBreadCrumbsBar
+               public static readonly BindableProperty HasBreadCrumbsBarProperty
+                       = BindableProperty.CreateAttached("HasBreadCrumbsBar", typeof(bool), typeof(FormsElement), false);
+
+               public static bool GetHasBreadCrumbsBar(BindableObject element)
+               {
+                       return (bool)element.GetValue(HasBreadCrumbsBarProperty);
+               }
+
+               public static void SetHasBreadCrumbsBar(BindableObject element, bool value)
+               {
+                       element.SetValue(HasBreadCrumbsBarProperty, value);
+               }
+
+               public static bool HasBreadCrumbsBar(this IPlatformElementConfiguration<Tizen, FormsElement> config)
+               {
+                       return GetHasBreadCrumbsBar(config.Element);
+               }
+
+               public static IPlatformElementConfiguration<Tizen, FormsElement> SetHasBreadCrumbsBar(this IPlatformElementConfiguration<Tizen, FormsElement> config, bool value)
+               {
+                       SetHasBreadCrumbsBar(config.Element, value);
+                       return config;
+               }
+               #endregion
+       }
+}
index ed5f8a1..3932215 100644 (file)
@@ -21,4 +21,11 @@ namespace Xamarin.Forms.PlatformConfiguration.TizenSpecific
                public const string Default = "default";
                public const string Pending = "pending";
        }
+
+       public static class TabbedPageStyle
+       {
+               public const string Default = "default";
+               public const string Tabbar = "tabbar";
+               public const string TabbarWithTitle = "tabbar_with_title";
+       }
 }
old mode 100644 (file)
new mode 100755 (executable)
index 88b325d..0196c39
@@ -43,6 +43,7 @@ using Xamarin.Forms.StyleSheets;
 [assembly: StyleProperty("background-image", typeof(Page), nameof(Page.BackgroundImageSourceProperty))]
 [assembly: StyleProperty("border-color", typeof(IBorderElement), nameof(BorderElement.BorderColorProperty))]
 [assembly: StyleProperty("border-radius", typeof(ICornerElement), nameof(CornerElement.CornerRadiusProperty))]
+[assembly: StyleProperty("border-radius", typeof(Button), nameof(Button.CornerRadiusProperty))]
 [assembly: StyleProperty("border-radius", typeof(Frame), nameof(Frame.CornerRadiusProperty))]
 [assembly: StyleProperty("border-radius", typeof(ImageButton), nameof(BorderElement.CornerRadiusProperty))]
 [assembly: StyleProperty("border-width", typeof(IBorderElement), nameof(BorderElement.BorderWidthProperty))]
@@ -61,6 +62,7 @@ using Xamarin.Forms.StyleSheets;
 [assembly: StyleProperty("margin-top", typeof(View), nameof(View.MarginTopProperty))]
 [assembly: StyleProperty("margin-right", typeof(View), nameof(View.MarginRightProperty))]
 [assembly: StyleProperty("margin-bottom", typeof(View), nameof(View.MarginBottomProperty))]
+[assembly: StyleProperty("max-lines", typeof(Label), nameof(Label.MaxLinesProperty))]
 [assembly: StyleProperty("min-height", typeof(VisualElement), nameof(VisualElement.MinimumHeightRequestProperty))]
 [assembly: StyleProperty("min-width", typeof(VisualElement), nameof(VisualElement.MinimumWidthRequestProperty))]
 [assembly: StyleProperty("opacity", typeof(VisualElement), nameof(VisualElement.OpacityProperty))]
@@ -109,6 +111,7 @@ using Xamarin.Forms.StyleSheets;
 [assembly: StyleProperty("-xf-orientation", typeof(StackLayout), nameof(StackLayout.OrientationProperty))]
 [assembly: StyleProperty("-xf-visual", typeof(VisualElement), nameof(VisualElement.VisualProperty))]
 [assembly: StyleProperty("-xf-vertical-text-alignment", typeof(Label), nameof(TextAlignmentElement.VerticalTextAlignmentProperty))]
+[assembly: StyleProperty("-xf-thumb-color", typeof(Switch), nameof(Switch.ThumbColorProperty))]
 
 //shell
 [assembly: StyleProperty("-xf-flyout-background", typeof(Shell), nameof(Shell.FlyoutBackgroundColorProperty))]
index 554b1a7..0550c81 100644 (file)
@@ -14,6 +14,7 @@ namespace Xamarin.Forms
 
                public RefreshView()
                {
+                       IsClippedToBounds = true;
                        VerticalOptions = LayoutOptions.FillAndExpand;
                        HorizontalOptions = LayoutOptions.FillAndExpand;
 
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/SearchBar.cs b/Xamarin.Forms/Xamarin.Forms.Core/SearchBar.cs
new file mode 100644 (file)
index 0000000..43dcad8
--- /dev/null
@@ -0,0 +1,170 @@
+using System;
+using System.ComponentModel;
+using System.Windows.Input;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Platform;
+
+namespace Xamarin.Forms
+{
+       [RenderWith(typeof(_SearchBarRenderer))]
+       public class SearchBar : InputView, IFontElement, ITextAlignmentElement, ISearchBarController, IElementConfiguration<SearchBar>
+       {
+               public static readonly BindableProperty SearchCommandProperty = BindableProperty.Create("SearchCommand", typeof(ICommand), typeof(SearchBar), null, propertyChanged: OnCommandChanged);
+
+               public static readonly BindableProperty SearchCommandParameterProperty = BindableProperty.Create("SearchCommandParameter", typeof(object), typeof(SearchBar), null);
+
+               public new static readonly BindableProperty TextProperty = InputView.TextProperty;
+
+               public static readonly BindableProperty CancelButtonColorProperty = BindableProperty.Create("CancelButtonColor", typeof(Color), typeof(SearchBar), default(Color));
+
+               public new static readonly BindableProperty PlaceholderProperty = InputView.PlaceholderProperty;
+
+               public new static readonly BindableProperty PlaceholderColorProperty = InputView.PlaceholderColorProperty;
+
+               public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;
+
+               public static readonly BindableProperty FontSizeProperty = FontElement.FontSizeProperty;
+
+               public static readonly BindableProperty FontAttributesProperty = FontElement.FontAttributesProperty;
+
+               public static readonly BindableProperty HorizontalTextAlignmentProperty = TextAlignmentElement.HorizontalTextAlignmentProperty;
+
+               public static readonly BindableProperty VerticalTextAlignmentProperty = TextAlignmentElement.VerticalTextAlignmentProperty;
+
+               public new static readonly BindableProperty TextColorProperty = InputView.TextColorProperty;
+
+               public new static readonly BindableProperty CharacterSpacingProperty = InputView.CharacterSpacingProperty;
+
+               readonly Lazy<PlatformConfigurationRegistry<SearchBar>> _platformConfigurationRegistry;
+
+               public Color CancelButtonColor
+               {
+                       get { return (Color)GetValue(CancelButtonColorProperty); }
+                       set { SetValue(CancelButtonColorProperty, value); }
+               }
+
+               public TextAlignment HorizontalTextAlignment
+               {
+                       get { return (TextAlignment)GetValue(TextAlignmentElement.HorizontalTextAlignmentProperty); }
+                       set { SetValue(TextAlignmentElement.HorizontalTextAlignmentProperty, value); }
+               }
+
+               public TextAlignment VerticalTextAlignment
+               {
+                       get { return (TextAlignment)GetValue(TextAlignmentElement.VerticalTextAlignmentProperty); }
+                       set { SetValue(TextAlignmentElement.VerticalTextAlignmentProperty, value); }
+               }
+
+               public ICommand SearchCommand
+               {
+                       get { return (ICommand)GetValue(SearchCommandProperty); }
+                       set { SetValue(SearchCommandProperty, value); }
+               }
+
+               public object SearchCommandParameter
+               {
+                       get { return GetValue(SearchCommandParameterProperty); }
+                       set { SetValue(SearchCommandParameterProperty, value); }
+               }
+
+               bool IsEnabledCore
+               {
+                       set { SetValueCore(IsEnabledProperty, value); }
+               }
+
+               public FontAttributes FontAttributes
+               {
+                       get { return (FontAttributes)GetValue(FontAttributesProperty); }
+                       set { SetValue(FontAttributesProperty, value); }
+               }
+
+               public string FontFamily
+               {
+                       get { return (string)GetValue(FontFamilyProperty); }
+                       set { SetValue(FontFamilyProperty, value); }
+               }
+
+               [TypeConverter(typeof(FontSizeConverter))]
+               public double FontSize
+               {
+                       get { return (double)GetValue(FontSizeProperty); }
+                       set { SetValue(FontSizeProperty, value); }
+               }
+
+               void IFontElement.OnFontFamilyChanged(string oldValue, string newValue)
+               {
+               }
+
+               void IFontElement.OnFontSizeChanged(double oldValue, double newValue)
+               {
+               }
+
+               double IFontElement.FontSizeDefaultValueCreator() =>
+                       Device.GetNamedSize(NamedSize.Default, (SearchBar)this);
+
+               void IFontElement.OnFontAttributesChanged(FontAttributes oldValue, FontAttributes newValue)
+               {
+               }
+
+               void IFontElement.OnFontChanged(Font oldValue, Font newValue)
+               {
+               }
+
+               public event EventHandler SearchButtonPressed;
+
+               public SearchBar()
+               {
+                       _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<SearchBar>>(() => new PlatformConfigurationRegistry<SearchBar>(this));
+               }
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public void OnSearchButtonPressed()
+               {
+                       ICommand cmd = SearchCommand;
+
+                       if (cmd != null && !cmd.CanExecute(SearchCommandParameter))
+                               return;
+
+                       cmd?.Execute(SearchCommandParameter);
+                       SearchButtonPressed?.Invoke(this, EventArgs.Empty);
+               }
+
+               void CommandCanExecuteChanged(object sender, EventArgs eventArgs)
+               {
+                       ICommand cmd = SearchCommand;
+                       if (cmd != null)
+                               IsEnabledCore = cmd.CanExecute(SearchCommandParameter);
+               }
+
+               static void OnCommandChanged(BindableObject bindable, object oldValue, object newValue)
+               {
+                       var self = (SearchBar)bindable;
+                       var newCommand = (ICommand)newValue;
+                       var oldCommand = (ICommand)oldValue;
+
+                       if (oldCommand != null)
+                       {
+                               oldCommand.CanExecuteChanged -= self.CommandCanExecuteChanged;
+                       }
+
+                       if (newCommand != null)
+                       {
+                               newCommand.CanExecuteChanged += self.CommandCanExecuteChanged;
+                               self.CommandCanExecuteChanged(self, EventArgs.Empty);
+                       }
+                       else
+                       {
+                               self.IsEnabledCore = true;
+                       }
+               }
+
+               public IPlatformElementConfiguration<T, SearchBar> On<T>() where T : IConfigPlatform
+               {
+                       return _platformConfigurationRegistry.Value.On<T>();
+               }
+
+               void ITextAlignmentElement.OnHorizontalTextAlignmentPropertyChanged(TextAlignment oldValue, TextAlignment newValue)
+               {
+               }
+       }
+}
\ No newline at end of file
index e9faf22..0ef7ae2 100644 (file)
@@ -47,6 +47,12 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(Slider), Color.Default);
 
+               public static readonly BindableProperty ThumbImageSourceProperty = BindableProperty.Create(nameof(ThumbImageSource), typeof(ImageSource), typeof(Slider), default(ImageSource));
+
+               [Obsolete("ThumbImageProperty is obsolete as of 4.0.0. Please use ThumbImageSourceProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty ThumbImageProperty = ThumbImageSourceProperty;
+
                public static readonly BindableProperty DragStartedCommandProperty = BindableProperty.Create(nameof(DragStartedCommand), typeof(ICommand), typeof(Slider), default(ICommand));
 
                public static readonly BindableProperty DragCompletedCommandProperty = BindableProperty.Create(nameof(DragCompletedCommand), typeof(ICommand), typeof(Slider), default(ICommand));
@@ -94,6 +100,20 @@ namespace Xamarin.Forms
                        set { SetValue(ThumbColorProperty, value); }
                }
 
+               public ImageSource ThumbImageSource
+               {
+                       get { return (ImageSource)GetValue(ThumbImageSourceProperty); }
+                       set { SetValue(ThumbImageSourceProperty, value); }
+               }
+
+               [Obsolete("ThumbImage is obsolete as of 4.0.0. Please use ThumbImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public FileImageSource ThumbImage
+               {
+                       get { return GetValue(ThumbImageProperty) as FileImageSource; }
+                       set { SetValue(ThumbImageProperty, value); }
+               }
+
                public ICommand DragStartedCommand
                {
                        get { return (ICommand)GetValue(DragStartedCommandProperty); }
index 3008deb..3eee876 100644 (file)
@@ -15,12 +15,20 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty OnColorProperty = BindableProperty.Create(nameof(OnColor), typeof(Color), typeof(Switch), Color.Default);
 
+               public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(Switch), Color.Default);
+
                public Color OnColor
                {
                        get { return (Color)GetValue(OnColorProperty); }
                        set { SetValue(OnColorProperty, value); }
                }
 
+               public Color ThumbColor
+               {
+                       get { return (Color)GetValue(ThumbColorProperty); }
+                       set { SetValue(ThumbColorProperty, value); }
+               }
+
                readonly Lazy<PlatformConfigurationRegistry<Switch>> _platformConfigurationRegistry;
 
                public Switch()
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/TabbedPage.cs b/Xamarin.Forms/Xamarin.Forms.Core/TabbedPage.cs
new file mode 100644 (file)
index 0000000..393d47d
--- /dev/null
@@ -0,0 +1,59 @@
+using System;
+using Xamarin.Forms.Platform;
+
+namespace Xamarin.Forms
+{
+       [RenderWith(typeof(_TabbedPageRenderer))]
+       public class TabbedPage : MultiPage<Page>, IBarElement, IElementConfiguration<TabbedPage>
+       {
+               public static readonly BindableProperty BarBackgroundColorProperty = BarElement.BarBackgroundColorProperty;
+
+               public static readonly BindableProperty BarTextColorProperty = BarElement.BarTextColorProperty;
+
+               public static readonly BindableProperty UnselectedTabColorProperty = BindableProperty.Create(nameof(UnselectedTabColor), typeof(Color), typeof(TabbedPage), default(Color));
+
+               public static readonly BindableProperty SelectedTabColorProperty = BindableProperty.Create(nameof(SelectedTabColor), typeof(Color),     typeof(TabbedPage), default(Color));
+
+               readonly Lazy<PlatformConfigurationRegistry<TabbedPage>> _platformConfigurationRegistry;
+
+               public Color BarBackgroundColor {
+                       get => (Color)GetValue(BarElement.BarBackgroundColorProperty);
+                       set => SetValue(BarElement.BarBackgroundColorProperty, value);
+               }
+
+               public Color BarTextColor {
+                       get => (Color)GetValue(BarElement.BarTextColorProperty);
+                       set => SetValue(BarElement.BarTextColorProperty, value);
+               }
+
+               public Color UnselectedTabColor
+               {
+                       get => (Color)GetValue(UnselectedTabColorProperty);
+                       set => SetValue(UnselectedTabColorProperty, value);
+               }
+               public Color SelectedTabColor
+               {
+                       get => (Color)GetValue(SelectedTabColorProperty);
+                       set => SetValue(SelectedTabColorProperty, value);
+               }
+
+               protected override Page CreateDefault(object item)
+               {
+                       var page = new Page();
+                       if (item != null)
+                               page.Title = item.ToString();
+
+                       return page;
+               }
+
+               public TabbedPage()
+               {
+                       _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<TabbedPage>>(() => new PlatformConfigurationRegistry<TabbedPage>(this));
+               }
+
+               public new IPlatformElementConfiguration<T, TabbedPage> On<T>() where T : IConfigPlatform
+               {
+                       return _platformConfigurationRegistry.Value.On<T>();
+               }
+       }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms/Xamarin.Forms.Core/TimePicker.cs b/Xamarin.Forms/Xamarin.Forms.Core/TimePicker.cs
new file mode 100644 (file)
index 0000000..108b7fd
--- /dev/null
@@ -0,0 +1,108 @@
+using System;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Platform;
+
+namespace Xamarin.Forms
+{
+       [RenderWith(typeof(_TimePickerRenderer))]
+       public class TimePicker : View, IFontElement, ITextElement, IElementConfiguration<TimePicker>
+       {
+               public static readonly BindableProperty FormatProperty = BindableProperty.Create(nameof(Format), typeof(string), typeof(TimePicker), "t");
+
+               public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+
+               public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
+               public static readonly BindableProperty TimeProperty = BindableProperty.Create(nameof(Time), typeof(TimeSpan), typeof(TimePicker), new TimeSpan(0), BindingMode.TwoWay, (bindable, value) =>
+               {
+                       var time = (TimeSpan)value;
+                       return time.TotalHours < 24 && time.TotalMilliseconds >= 0;
+               });
+
+               public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;
+
+               public static readonly BindableProperty FontSizeProperty = FontElement.FontSizeProperty;
+
+               public static readonly BindableProperty FontAttributesProperty = FontElement.FontAttributesProperty;
+
+               readonly Lazy<PlatformConfigurationRegistry<TimePicker>> _platformConfigurationRegistry;
+
+               public TimePicker()
+               {
+                       _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<TimePicker>>(() => new PlatformConfigurationRegistry<TimePicker>(this));
+               }
+
+               public string Format
+               {
+                       get { return (string)GetValue(FormatProperty); }
+                       set { SetValue(FormatProperty, value); }
+               }
+
+               public Color TextColor
+               {
+                       get { return (Color)GetValue(TextElement.TextColorProperty); }
+                       set { SetValue(TextElement.TextColorProperty, value); }
+               }
+
+               public double CharacterSpacing
+               {
+                       get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+                       set { SetValue(TextElement.CharacterSpacingProperty, value); }
+               }
+
+               public TimeSpan Time
+               {
+                       get { return (TimeSpan)GetValue(TimeProperty); }
+                       set { SetValue(TimeProperty, value); }
+               }
+
+               public FontAttributes FontAttributes
+               {
+                       get { return (FontAttributes)GetValue(FontAttributesProperty); }
+                       set { SetValue(FontAttributesProperty, value); }
+               }
+
+               public string FontFamily
+               {
+                       get { return (string)GetValue(FontFamilyProperty); }
+                       set { SetValue(FontFamilyProperty, value); }
+               }
+
+               [TypeConverter(typeof(FontSizeConverter))]
+               public double FontSize
+               {
+                       get { return (double)GetValue(FontSizeProperty); }
+                       set { SetValue(FontSizeProperty, value); }
+               }
+
+               void IFontElement.OnFontFamilyChanged(string oldValue, string newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               void IFontElement.OnFontSizeChanged(double oldValue, double newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               void IFontElement.OnFontChanged(Font oldValue, Font newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               double IFontElement.FontSizeDefaultValueCreator() =>
+                       Device.GetNamedSize(NamedSize.Default, (TimePicker)this);
+
+               void IFontElement.OnFontAttributesChanged(FontAttributes oldValue, FontAttributes newValue) =>
+                       InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+
+               public IPlatformElementConfiguration<T, TimePicker> On<T>() where T : IConfigPlatform
+               {
+                       return _platformConfigurationRegistry.Value.On<T>();
+               }
+
+               void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
+               {
+               }
+
+               void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+               {
+                       InvalidateMeasure();
+               }
+
+       }
+}
\ No newline at end of file
index 707f23d..36fee0d 100644 (file)
@@ -7,7 +7,7 @@ namespace Xamarin.Forms.Platform.Tizen
        {
                const int _defaultHeight = 55;
 
-               public ImageCellRenderer() : this("1icon_2text")
+               public ImageCellRenderer() : this(Device.Idiom == TargetIdiom.Watch ? "1icon_2text" : (Device.Idiom == TargetIdiom.Phone ? "double_label" : "default"))
                {
                        ImagePart = "elm.swallow.icon";
                }
index 4089f4c..3bc6c3d 100644 (file)
@@ -45,9 +45,20 @@ namespace Xamarin.Forms.Platform.Tizen
                                toggle.SetBinding(Switch.OnColorProperty, new Binding(SwitchCell.OnColorProperty.PropertyName));
                                var nativeView = Platform.GetOrCreateRenderer(toggle).NativeView;
 
-                               nativeView.MinimumWidth += 8;
-                               nativeView.PropagateEvents = false;
-                               
+                               if (Device.Idiom == TargetIdiom.Watch)
+                               {
+                                       nativeView.MinimumWidth += 8;
+                               }
+
+                               //It is a temporary way to prevent that the check of the Cell gets focus until the UX about views in the Cell for TV is defined.
+                               if (Device.Idiom == TargetIdiom.TV)
+                               {
+                                       ((Check)nativeView).AllowFocus(false);
+                               }
+                               else
+                               {
+                                       nativeView.PropagateEvents = false;
+                               }
                                return nativeView;
                        }
                        return null;
index fc9f091..998844f 100644 (file)
@@ -6,8 +6,8 @@ namespace Xamarin.Forms.Platform.Tizen
        public class TextCellRenderer : CellRenderer
        {
                bool _groupMode = false;
-               
-               public TextCellRenderer() : this("double_label") { }
+               // TextCell.Detail property is not supported on TV profile due to UX limitation.
+               public TextCellRenderer() : this(Device.Idiom == TargetIdiom.Phone || Device.Idiom == TargetIdiom.Watch ? "double_label" : "default") { }
 
                protected TextCellRenderer(string style) : base(style)
                {
@@ -33,7 +33,7 @@ namespace Xamarin.Forms.Platform.Tizen
                        else
                        {
                                Class = null;
-                               Style = "default";
+                               Style = Device.Idiom == TargetIdiom.Phone ? "double_label" : "default";
                                DetailPart = "elm.text.sub";
                        }
                }
index 25cc744..10cae9a 100644 (file)
@@ -103,9 +103,20 @@ namespace Xamarin.Forms
 
        public static class Forms
        {
+               static Lazy<string> s_profile = new Lazy<string>(() =>
+               {
+                       //TODO : Fix me if elm_config_profile_get() unavailable
+                       return Elementary.GetProfile();
+               });
+
                static Lazy<int> s_dpi = new Lazy<int>(() =>
                {
                        int dpi = 0;
+                       if (s_profile.Value == "tv")
+                       {
+                               // Use fixed DPI value (72) if TV profile
+                               return 72;
+                       }
                        TSystemInfo.TryGetValue<int>("http://tizen.org/feature/screen.dpi", out dpi);
                        return dpi;
                });
@@ -124,6 +135,8 @@ namespace Xamarin.Forms
 
                        readonly double scalingFactor;
 
+                       readonly string profile;
+
                        public override Size PixelScreenSize
                        {
                                get
@@ -148,6 +161,14 @@ namespace Xamarin.Forms
                                }
                        }
 
+                       public string Profile
+                       {
+                               get
+                               {
+                                       return this.profile;
+                               }
+                       }
+
                        public TizenDeviceInfo() : this(getScreenWidth(), getScreenHeight())
                        {
                        }
@@ -185,6 +206,7 @@ namespace Xamarin.Forms
                                }
 
                                scaledScreenSize = new Size(width / scalingFactor, height / scalingFactor);
+                               profile = s_profile.Value;
                        }
 
                        public TizenDeviceInfo RefreshByDIP()
@@ -514,13 +536,55 @@ namespace Xamarin.Forms
 
                        if (!Forms.IsInitialized)
                        {
-                               Device.SetIdiom(TargetIdiom.Watch);
-                               Color.SetAccent(Color.FromRgba(10, 27, 41, 255)); // Theme A (Default) 1st HSB: 207 75 16
+                               string profile = ((TizenDeviceInfo)Device.Info).Profile;
+                               if (profile == "mobile")
+                               {
+                                       Device.SetIdiom(TargetIdiom.Phone);
+                               }
+                               else if (profile == "tv")
+                               {
+                                       Device.SetIdiom(TargetIdiom.TV);
+                               }
+                               else if (profile == "desktop")
+                               {
+                                       Device.SetIdiom(TargetIdiom.Desktop);
+                               }
+                               else if (profile == "wearable")
+                               {
+                                       Device.SetIdiom(TargetIdiom.Watch);
+                               }
+                               else
+                               {
+                                       Device.SetIdiom(TargetIdiom.Unsupported);
+                               }
+                               Color.SetAccent(GetAccentColor(profile));
                                ExpressionSearch.Default = new TizenExpressionSearch();
                                IsInitialized = true;
                        }
                }
 
+               static Color GetAccentColor(string profile)
+               {
+                       // On Windows Phone, this is the complementary color chosen by the user.
+                       // Good Windows Phone applications use this as part of their styling to provide a native look and feel.
+                       // On iOS and Android this instance is set to a contrasting color that is visible on the default
+                       // background but is not the same as the default text color.
+
+                       switch (profile)
+                       {
+                               case "mobile":
+                                       // [Tizen_3.0]Basic_Interaction_GUI_[REF].xlsx Theme 001 (Default) 1st HSB: 188 70 80
+                                       return Color.FromRgba(61, 185, 204, 255);
+                               case "tv":
+                                       return Color.FromRgba(15, 15, 15, 230);
+                               case "wearable":
+                                       // Theme A (Default) 1st HSB: 207 75 16
+                                       return Color.FromRgba(10, 27, 41, 255);
+                               default:
+                                       return Color.Black;
+                       }
+               }
+
                /// <summary>
                /// Converts the dp into pixel considering current DPI value.
                /// </summary>
@@ -594,6 +658,15 @@ namespace Xamarin.Forms
                        return eflPt / s_elmScale.Value;
                }
 
+               /// <summary>
+               /// Get the EFL's profile
+               /// </summary>
+               /// <returns></returns>
+               public static string GetProfile()
+               {
+                       return s_profile.Value;
+               }
+
                // for internal use only
                [EditorBrowsable(EditorBrowsableState.Never)]
                public static EvasObject Preload()
@@ -646,9 +719,12 @@ namespace Xamarin.Forms
                                typeof(BoxView),
                                typeof(Button),
                                typeof(ImageButton),
+                               typeof(CheckBox),
                                typeof(Slider),
                                typeof(Stepper),
                                typeof(Switch),
+                               typeof(DatePicker),
+                               typeof(TimePicker),
                                typeof(Entry),
                                typeof(Editor),
                                typeof(ActivityIndicator),
@@ -656,6 +732,7 @@ namespace Xamarin.Forms
                                typeof(CarouselView),
                                typeof(CollectionView),
                                typeof(ListView),
+                               typeof(Picker),
                                typeof(TableView),
                                typeof(TextCell),
                                typeof(ImageCell),
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateChangedEventArgs.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateChangedEventArgs.cs
new file mode 100644 (file)
index 0000000..6144a7d
--- /dev/null
@@ -0,0 +1,25 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Event arguments for <see cref="DatePicker.DateChanged"/> event.
+       /// </summary>
+       public class DateChangedEventArgs : EventArgs
+       {
+               /// <summary>
+               /// The date that the user entered.
+               /// </summary>
+               public DateTime NewDate { get; }
+
+               /// <summary>
+               /// Creates a new <see cref="DateChangedEventArgs"/> object that represents a change from <paramref name="oldDate"/> to <paramref name="newDate"/>.
+               /// </summary>
+               /// <param name="oldDate">Old date of <see cref="DatePicker"/>.</param>
+               /// <param name="newDate">Current date of <see cref="DatePicker"/>.</param>
+               public DateChangedEventArgs(DateTime newDate)
+               {
+                       NewDate = newDate;
+               }
+       }
+}
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateTimePicker.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateTimePicker.cs
new file mode 100644 (file)
index 0000000..c6c17ff
--- /dev/null
@@ -0,0 +1,71 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       public enum DateTimePickerMode
+       {
+               Date,
+               Time
+       }
+
+       public class DateTimePicker : DateTimeSelector
+       {
+               const string TimeFormat = "%d/%b/%Y %I:%M %p";
+               const string TimeLayoutStyle = "time_layout";
+
+               const string DateFormat = "%d/%b/%Y";
+               const string DateLayoutStyle = "date_layout";
+
+               DateTimePickerMode _mode = DateTimePickerMode.Date;
+
+               public DateTimePicker(EvasObject parent) : base(parent)
+               {
+                       UpdateMode();
+               }
+
+               protected DateTimePicker() : base()
+               {
+               }
+
+               public DateTimePickerMode Mode
+               {
+                       get { return _mode; }
+                       set
+                       {
+                               if (_mode != value)
+                               {
+                                       _mode = value;
+                                       UpdateMode();
+                               }
+                       }
+               }
+
+               public TimeSpan Time
+               {
+                       get
+                       {
+                               return DateTime.TimeOfDay;
+                       }
+                       set
+                       {
+                               DateTime -= DateTime.TimeOfDay;
+                               DateTime += value;
+                       }
+               }
+
+               protected virtual void UpdateMode()
+               {
+                       if (Mode == DateTimePickerMode.Date)
+                       {
+                               Style = DateLayoutStyle;
+                               Format = DateFormat;
+                       }
+                       else
+                       {
+                               Style = TimeLayoutStyle;
+                               Format = TimeFormat;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateTimePickerDialog.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/DateTimePickerDialog.cs
new file mode 100644 (file)
index 0000000..befeed9
--- /dev/null
@@ -0,0 +1,79 @@
+using System;
+using ElmSharp;
+using EButton = ElmSharp.Button;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       public class DateTimePickerDialog : Dialog, IDateTimeDialog
+       {
+               EvasObject _parent;
+               /// <summary>
+               /// Creates a dialog window.
+               /// </summary>
+               public DateTimePickerDialog(EvasObject parent) : base(parent)
+               {
+                       _parent = parent;
+                       Initialize();
+               }
+
+               public DateTimePicker Picker { get; protected set; }
+
+               /// <summary>
+               /// Occurs when the date of this dialog has changed.
+               /// </summary>
+               public event EventHandler<DateChangedEventArgs> DateTimeChanged;
+
+               protected virtual DateTimePicker CreatePicker(EvasObject parent)
+               {
+                       return new DateTimePicker(parent);
+               }
+
+               void Initialize()
+               {
+                       Picker = CreatePicker(_parent);
+                       Picker.Show();
+                       Content = Picker;
+
+                       //TODO need to add internationalization support
+                       PositiveButton = new EButton(_parent) { Text = "Set" };
+                       PositiveButton.Clicked += (s, e) =>
+                       {
+                               Confirm();
+                       };
+
+                       //TODO need to add internationalization support
+                       NegativeButton = new EButton(_parent) { Text = "Cancel" };
+                       NegativeButton.Clicked += (s, e) =>
+                       {
+                               Hide();
+                       };
+                       BackButtonPressed += (object s, EventArgs e) =>
+                       {
+                               Hide();
+                       };
+
+                       // TODO This is Tizen TV Limitation.
+                       // UX is defined and the focus move processing is complete, it should be removed(After Tizen 5.0)
+                       if (Device.Idiom == TargetIdiom.TV)
+                       {
+                               KeyDown += (s, e) =>
+                               {
+                                       if (e.KeyName == "Return")
+                                       {
+                                               if (Picker != null && Picker.IsFocused)
+                                               {
+                                                       Confirm();
+                                                       e.Flags |= EvasEventFlag.OnHold;
+                                               }
+                                       }
+                               };
+                       }
+               }
+
+               void Confirm()
+               {
+                       DateTimeChanged?.Invoke(this, new DateChangedEventArgs(Picker.DateTime));
+                       Hide();
+               }
+       }
+}
index fd754f9..00fc747 100644 (file)
@@ -35,7 +35,14 @@ namespace Xamarin.Forms.Platform.Tizen.Native
                /// </summary>
                public static Dialog CreateDialog(EvasObject parent, bool hasAcceptButton = false)
                {
-                       return new Watch.WatchDialog(Forms.NativeParent, hasAcceptButton);
+                       if (Device.Idiom == TargetIdiom.Watch)
+                       {
+                               return new Watch.WatchDialog(Forms.NativeParent, hasAcceptButton);
+                       }
+                       else
+                       {
+                               return new Dialog(Forms.NativeParent);
+                       }
                }
 
                /// <summary>
@@ -234,7 +241,7 @@ namespace Xamarin.Forms.Platform.Tizen.Native
 
                protected virtual void ApplyTitleColor(EColor color)
                {
-                       SetPartColor("text_maintitle", color);
+                       SetPartColor(Device.Idiom == TargetIdiom.TV ? "text_title" : "text_maintitle", color);
                }
 
                /// <summary>
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/IDateTimeDialog.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/IDateTimeDialog.cs
new file mode 100644 (file)
index 0000000..0281f2b
--- /dev/null
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       public interface IDateTimeDialog
+       {
+               string Title { get; set; }
+               DateTimePicker Picker { get; }
+               event EventHandler<DateChangedEventArgs> DateTimeChanged;
+               void Show();
+               void Hide();
+               void Unrealize();
+       }
+}
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs
new file mode 100644 (file)
index 0000000..6ef690a
--- /dev/null
@@ -0,0 +1,509 @@
+using System;
+using ElmSharp;
+using Xamarin.Forms.Internals;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// The native widget which provides Xamarin.MasterDetailPage features.
+       /// </summary>
+       public class MasterDetailPage : Box
+       {
+               /// <summary>
+               /// The default master behavior (a.k.a mode).
+               /// </summary>
+               static readonly MasterBehavior s_defaultMasterBehavior = (Device.Idiom == TargetIdiom.Phone || Device.Idiom == TargetIdiom.Watch) ? MasterBehavior.Popover : MasterBehavior.SplitOnLandscape;
+
+               /// <summary>
+               /// The MasterPage native container.
+               /// </summary>
+               readonly Canvas _masterCanvas;
+
+               /// <summary>
+               /// The DetailPage native container.
+               /// </summary>
+               readonly Canvas _detailCanvas;
+
+               /// <summary>
+               /// The container for <c>_masterCanvas</c> and <c>_detailCanvas</c> used in split mode.
+               /// </summary>
+               readonly Panes _splitPane;
+
+               /// <summary>
+               /// The container for <c>_masterCanvas</c> used in popover mode.
+               /// </summary>
+               readonly Panel _drawer;
+
+               /// <summary>
+               /// The <see cref="MasterBehavior"/> property value.
+               /// </summary>
+               MasterBehavior _masterBehavior = s_defaultMasterBehavior;
+
+               /// <summary>
+               /// The actual MasterDetailPage mode - either split or popover. It depends on <c>_masterBehavior</c> and screen orientation.
+               /// </summary>
+               MasterBehavior _internalMasterBehavior = MasterBehavior.Popover;
+
+               /// <summary>
+               /// The <see cref="Master"/> property value.
+               /// </summary>
+               EvasObject _master;
+
+               /// <summary>
+               /// The <see cref="Detail"/> property value.
+               /// </summary>
+               EvasObject _detail;
+
+               /// <summary>
+               /// The main widget - either <see cref="_splitPlane"/> or <see cref="_detailPage"/>, depending on the mode.
+               /// </summary>
+               EvasObject _mainWidget;
+
+               /// <summary>
+               /// The <see cref="IsGestureEnabled"/> property value.
+               /// </summary>
+               bool _isGestureEnabled = true;
+
+               /// <summary>
+               /// The portion of the screen that the MasterPage takes in Split mode.
+               /// </summary>
+               double _splitRatio = 0.35;
+
+               /// <summary>
+               /// The portion of the screen that the MasterPage takes in Popover mode.
+               /// </summary>
+               double _popoverRatio = 0.8;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.MasterDetailPage"/> class.
+               /// </summary>
+               /// <param name="parent">Parent evas object.</param>
+               public MasterDetailPage(EvasObject parent) : base(parent)
+               {
+                       LayoutUpdated += (s, e) =>
+                       {
+                               UpdateChildCanvasGeometry();
+                       };
+
+                       // create the controls which will hold the master and detail pages
+                       _masterCanvas = new Canvas(this);
+                       _masterCanvas.SetAlignment(-1.0, -1.0);  // fill
+                       _masterCanvas.SetWeight(1.0, 1.0);  // expand
+                       _masterCanvas.LayoutUpdated += (sender, e) =>
+                       {
+                               UpdatePageGeometry(_master);
+                       };
+
+                       _detailCanvas = new Canvas(this);
+                       _detailCanvas.SetAlignment(-1.0, -1.0);  // fill
+                       _detailCanvas.SetWeight(1.0, 1.0);  // expand
+                       _detailCanvas.LayoutUpdated += (sender, e) =>
+                       {
+                               UpdatePageGeometry(_detail);
+                       };
+
+                       _splitPane = new Panes(this)
+                       {
+                               AlignmentX = -1,
+                               AlignmentY = -1,
+                               WeightX = 1,
+                               WeightY = 1,
+                               IsFixed = true,
+                               IsHorizontal = false,
+                               Proportion = _splitRatio,
+                       };
+
+                       _drawer = new Panel(Forms.NativeParent);
+                       _drawer.SetScrollable(_isGestureEnabled);
+                       _drawer.SetScrollableArea(1.0);
+                       _drawer.Direction = PanelDirection.Left;
+                       _drawer.Toggled += (object sender, EventArgs e) =>
+                       {
+                               UpdateFocusPolicy();
+                               IsPresentedChanged?.Invoke(this, new IsPresentedChangedEventArgs(_drawer.IsOpen));
+                       };
+
+                       ConfigureLayout();
+
+                       // in case of the screen rotation we may need to update the choice between split
+                       // and popover behaviors and reconfigure the layout
+                       Device.Info.PropertyChanged += (s, e) =>
+                       {
+                               if (e.PropertyName == nameof(Device.Info.CurrentOrientation))
+                               {
+                                       UpdateMasterBehavior();
+                               }
+                       };
+               }
+
+               /// <summary>
+               /// Occurs when the MasterPage is shown or hidden.
+               /// </summary>
+               public event EventHandler<IsPresentedChangedEventArgs> IsPresentedChanged;
+
+               /// <summary>
+               /// Occurs when the IsPresentChangeable was changed.
+               /// </summary>
+               public event EventHandler<UpdateIsPresentChangeableEventArgs> UpdateIsPresentChangeable;
+
+               /// <summary>
+               /// Gets or sets the MasterDetailPage behavior.
+               /// </summary>
+               /// <value>The behavior of the <c>MasterDetailPage</c> requested by the user.</value>
+               public MasterBehavior MasterBehavior
+               {
+                       get
+                       {
+                               return _masterBehavior;
+                       }
+
+                       set
+                       {
+                               _masterBehavior = value;
+                               UpdateMasterBehavior();
+                       }
+               }
+
+               /// <summary>
+               /// Gets the MasterDEtailPage was splited
+               /// </summary>
+               public bool IsSplit => _internalMasterBehavior == MasterBehavior.Split;
+
+               /// <summary>
+               /// Gets or sets the content of the MasterPage.
+               /// </summary>
+               /// <value>The MasterPage.</value>
+               public EvasObject Master
+               {
+                       get
+                       {
+                               return _master;
+                       }
+
+                       set
+                       {
+                               if (_master != value)
+                               {
+                                       _master = value;
+                                       UpdatePageGeometry(_master);
+                                       _masterCanvas.Children.Clear();
+                                       _masterCanvas.Children.Add(_master);
+                                       if (!IsSplit)
+                                               UpdateFocusPolicy();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the content of the DetailPage.
+               /// </summary>
+               /// <value>The DetailPage.</value>
+               public EvasObject Detail
+               {
+                       get
+                       {
+                               return _detail;
+                       }
+
+                       set
+                       {
+                               if (_detail != value)
+                               {
+                                       _detail = value;
+                                       UpdatePageGeometry(_detail);
+                                       _detailCanvas.Children.Clear();
+                                       _detailCanvas.Children.Add(_detail);
+                                       if (!IsSplit)
+                                               UpdateFocusPolicy();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets a value indicating whether the MasterPage is shown.
+               /// </summary>
+               /// <value><c>true</c> if the MasterPage is presented.</value>
+               public bool IsPresented
+               {
+                       get
+                       {
+                               return _drawer.IsOpen;
+                       }
+
+                       set
+                       {
+                               if (_drawer.IsOpen != value)
+                               {
+                                       _drawer.IsOpen = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets a value indicating whether a MasterDetailPage allows showing MasterPage with swipe gesture.
+               /// </summary>
+               /// <value><c>true</c> if the MasterPage can be revealed with a gesture.</value>
+               public bool IsGestureEnabled
+               {
+                       get
+                       {
+                               return _isGestureEnabled;
+                       }
+
+                       set
+                       {
+                               if (_isGestureEnabled != value)
+                               {
+                                       _isGestureEnabled = value;
+                                       // Fixme
+                                       // Elementary panel was not support to change scrollable property on runtime
+                                       // Please uncomment when EFL was updated
+                                       //_drawer.SetScrollable(_isGestureEnabled);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or Sets the portion of the screen that the MasterPage takes in split mode.
+               /// </summary>
+               /// <value>The portion.</value>
+               public double SplitRatio
+               {
+                       get
+                       {
+                               return _splitRatio;
+                       }
+                       set
+                       {
+                               if (_splitRatio != value)
+                               {
+                                       _splitRatio = value;
+                                       _splitPane.Proportion = _splitRatio;
+                               }
+                       }
+
+               }
+
+               /// <summary>
+               /// Gets or sets the portion of the screen that the MasterPage takes in Popover mode.
+               /// </summary>
+               /// <value>The portion.</value>
+               public double PopoverRatio
+               {
+                       get
+                       {
+                               return _popoverRatio;
+                       }
+                       set
+                       {
+                               if (_popoverRatio != value)
+                               {
+                                       _popoverRatio = value;
+                                       UpdateChildCanvasGeometry();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Provides destruction for native element and contained elements.
+               /// </summary>
+               protected override void OnUnrealize()
+               {
+                       // Views that are not belong to view tree should be unrealized.
+                       if (IsSplit)
+                       {
+                               _drawer.Unrealize();
+                       }
+                       else
+                       {
+                               _splitPane.Unrealize();
+                       }
+                       base.OnUnrealize();
+               }
+
+               /// <summary>
+               /// Updates the geometry of the selected page.
+               /// </summary>
+               /// <param name="page">Master or Detail page to be updated.</param>
+               void UpdatePageGeometry(EvasObject page)
+               {
+                       if (page != null)
+                       {
+                               if (_master == page)
+                               {
+                                       // update the geometry of the master page
+                                       page.Geometry = _masterCanvas.Geometry;
+                               }
+                               else if (_detail == page)
+                               {
+                                       // update the geometry of the detail page
+                                       page.Geometry = _detailCanvas.Geometry;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Updates <see cref="_internalMasterBehavior"/> according to <see cref="MasterDetailBehavior"/> set by the user and current screen orientation.
+               /// </summary>
+               void UpdateMasterBehavior()
+               {
+                       var behavior = (_masterBehavior == MasterBehavior.Default) ? s_defaultMasterBehavior : _masterBehavior;
+
+                       // Screen orientation affects those 2 behaviors
+                       if (behavior == MasterBehavior.SplitOnLandscape ||
+                               behavior == MasterBehavior.SplitOnPortrait)
+                       {
+                               var orientation = Device.Info.CurrentOrientation;
+
+                               if ((orientation.IsLandscape() && behavior == MasterBehavior.SplitOnLandscape) ||
+                                       (orientation.IsPortrait() && behavior == MasterBehavior.SplitOnPortrait))
+                               {
+                                       behavior = MasterBehavior.Split;
+                               }
+                               else
+                               {
+                                       behavior = MasterBehavior.Popover;
+                               }
+                       }
+
+                       if (behavior != _internalMasterBehavior)
+                       {
+                               _internalMasterBehavior = behavior;
+                               ConfigureLayout();
+                       }
+               }
+
+               /// <summary>
+               /// Composes the structure of all the necessary widgets.
+               /// </summary>
+               void ConfigureLayout()
+               {
+                       _drawer.SetContent(null, true);
+                       _drawer.Hide();
+
+                       _splitPane.SetPartContent("left", null, true);
+                       _splitPane.SetPartContent("right", null, true);
+                       _splitPane.Hide();
+
+                       UnPackAll();
+
+                       // the structure for split mode and for popover mode looks differently
+                       if (IsSplit)
+                       {
+                               _splitPane.SetPartContent("left", _masterCanvas, true);
+                               _splitPane.SetPartContent("right", _detailCanvas, true);
+                               _splitPane.Show();
+                               _mainWidget = _splitPane;
+                               PackEnd(_splitPane);
+
+                               IsPresented = true;
+                               UpdateIsPresentChangeable?.Invoke(this, new UpdateIsPresentChangeableEventArgs(false));
+                               UpdateFocusPolicy(true);
+                       }
+                       else
+                       {
+                               _drawer.SetContent(_masterCanvas, true);
+                               _drawer.Show();
+                               _mainWidget = _detailCanvas;
+                               PackEnd(_detailCanvas);
+                               PackEnd(_drawer);
+
+                               _drawer.IsOpen = IsPresented;
+                               UpdateIsPresentChangeable?.Invoke(this, new UpdateIsPresentChangeableEventArgs(true));
+                               UpdateFocusPolicy();
+                       }
+
+                       _masterCanvas.Show();
+                       _detailCanvas.Show();
+
+                       // even though child was changed, Layout callback was not called, so i manually call layout function.
+                       // Layout callback was filter out when geometry was not changed in Native.Box
+                       UpdateChildCanvasGeometry();
+               }
+
+               void UpdateChildCanvasGeometry()
+               {
+                       var bound = Geometry;
+                       // main widget should fill the area of the MasterDetailPage
+                       if (_mainWidget != null)
+                       {
+                               _mainWidget.Geometry = bound;
+                       }
+
+                       bound.Width = (int)((_popoverRatio * bound.Width));
+                       _drawer.Geometry = bound;
+                       // When a _drawer.IsOpen was false, Content of _drawer area is not allocated. So, need to manaully set the content area
+                       if (!IsSplit)
+                               _masterCanvas.Geometry = bound;
+               }
+
+               /// <summary>
+               /// Force update the focus management
+               /// </summary>
+               void UpdateFocusPolicy(bool forceAllowFocusAll=false)
+               {
+                       var master = _master as Widget;
+                       var detail = _detail as Widget;
+
+                       if(forceAllowFocusAll)
+                       {
+                               if (master != null)
+                                       master.AllowTreeFocus = true;
+                               if (detail != null)
+                                       detail.AllowTreeFocus = true;
+                               return;
+                       }
+
+                       if (_drawer.IsOpen)
+                       {
+                               if (detail != null)
+                               {
+                                       detail.AllowTreeFocus = false;
+                               }
+                               if (master != null)
+                               {
+                                       master.AllowTreeFocus = true;
+                                       master.SetFocus(true);
+                               }
+                       }
+                       else
+                       {
+                               if (master != null)
+                               {
+                                       master.AllowTreeFocus = false;
+                               }
+                               if (detail != null)
+                               {
+                                       detail.AllowTreeFocus = true;
+                                       detail.SetFocus(true);
+                               }
+                       }
+               }
+       }
+
+       public class IsPresentedChangedEventArgs : EventArgs
+       {
+               public IsPresentedChangedEventArgs (bool isPresent)
+               {
+                       IsPresent = isPresent;
+               }
+
+               /// <summary>
+               /// Value of IsPresent
+               /// </summary>
+               public bool IsPresent { get; private set; }
+       }
+
+       public class UpdateIsPresentChangeableEventArgs : EventArgs
+       {
+               public UpdateIsPresentChangeableEventArgs(bool canChange)
+               {
+                       CanChange = canChange;
+               }
+
+               /// <summary>
+               /// Value of changeable
+               /// </summary>
+               public bool CanChange { get; private set; }
+       }
+}
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/Watch/WatchDataTimePickerDialog.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/Watch/WatchDataTimePickerDialog.cs
new file mode 100644 (file)
index 0000000..cc4dc42
--- /dev/null
@@ -0,0 +1,95 @@
+using System;
+using ElmSharp;
+using ElmSharp.Wearable;
+using ELayout = ElmSharp.Layout;
+using EButton = ElmSharp.Button;
+
+namespace Xamarin.Forms.Platform.Tizen.Native.Watch
+{
+       public class WatchDataTimePickerDialog : Popup, IDateTimeDialog
+       {
+               ELayout _surfaceLayout;
+               ELayout _datetimeLayout;
+               CircleSurface _surface;
+               EButton _doneButton;
+               Box _container;
+               string _title;
+
+               public WatchDataTimePickerDialog(EvasObject parent) : base(parent)
+               {
+                       AlignmentX = -1;
+                       AlignmentY = -1;
+                       WeightX = 1.0;
+                       WeightY = 1.0;
+                       Style = "circle";
+
+                       _container = new Box(parent) { AlignmentX = -1, AlignmentY = -1, WeightX = 1, WeightY = 1 };
+                       _container.BackgroundColor = ElmSharp.Color.Blue;
+                       _container.SetLayoutCallback(OnContainerLayout);
+
+                       _datetimeLayout = new ELayout(parent);
+                       _surfaceLayout = new ELayout(parent);
+
+                       _container.PackEnd(_datetimeLayout);
+                       _container.PackEnd(_surfaceLayout);
+
+                       _datetimeLayout.SetTheme("layout", "circle", "datetime");
+                       _surface = new CircleSurface(_surfaceLayout);
+
+                       WatchPicker = new WatchDateTimePicker(parent, _surface);
+                       WatchPicker.Show();
+                       _datetimeLayout.SetContent(WatchPicker);
+
+                       _doneButton = new Button(parent)
+                       {
+                               Text = "Set",
+                               Style = "bottom",
+                       };
+                       _datetimeLayout.SetPartContent("elm.swallow.btn", _doneButton);
+                       _doneButton.Clicked += OnDoneClicked;
+
+                       ((IRotaryActionWidget)WatchPicker.CircleSelector).Activate();
+
+                       _datetimeLayout.Show();
+                       _surfaceLayout.Show();
+                       _container.Show();
+
+                       SetContent(_container);
+                       BackButtonPressed += OnBackButtonPressed;
+               }
+
+               public string Title
+               {
+                       get => _title;
+                       set
+                       {
+                               _title = value;
+                               _datetimeLayout.SetPartText("elm.text", _title);
+                       }
+               }
+
+               public DateTimePicker Picker => WatchPicker;
+               protected WatchDateTimePicker WatchPicker { get; }
+
+               public event EventHandler<DateChangedEventArgs> DateTimeChanged;
+
+               void OnContainerLayout()
+               {
+                       _surfaceLayout.Geometry = _container.Geometry;
+                       _datetimeLayout.Geometry = _container.Geometry;
+               }
+
+               void OnDoneClicked(object sender, EventArgs e)
+               {
+                       System.Console.WriteLine("Done clicked");
+                       System.Console.WriteLine("Picker.DateTime - {0} ", Picker.DateTime);
+                       DateTimeChanged?.Invoke(this, new DateChangedEventArgs(Picker.DateTime));
+                       Hide();
+               }
+
+               void OnBackButtonPressed(object sender, EventArgs e)
+               {
+                       Hide();
+               }
+       }
+}
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/Watch/WatchDateTimePicker.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Native/Watch/WatchDateTimePicker.cs
new file mode 100644 (file)
index 0000000..aa9f989
--- /dev/null
@@ -0,0 +1,41 @@
+using System;
+using ElmSharp;
+using ElmSharp.Wearable;
+
+namespace Xamarin.Forms.Platform.Tizen.Native.Watch
+{
+       public class WatchDateTimePicker : DateTimePicker
+       {
+               readonly CircleSurface _surface;
+               public WatchDateTimePicker(EvasObject parent, CircleSurface surface) : base()
+               {
+                       _surface = surface;
+                       Realize(parent);
+                       UpdateMode();
+               }
+
+               public CircleDateTimeSelector CircleSelector { get; private set; }
+
+               protected override void UpdateMode()
+               {
+                       if (Mode == DateTimePickerMode.Date)
+                       {
+                               Style = "datepicker/circle";
+                       }
+                       else
+                       {
+                               Style = "timepicker/circle";
+                       }
+               }
+
+               protected override IntPtr CreateHandle(EvasObject parent)
+               {
+                       CircleSelector = new CircleDateTimeSelector(parent, _surface);
+                       if (CircleSelector.RealHandle != CircleSelector.Handle)
+                       {
+                               RealHandle = CircleSelector.RealHandle;
+                       }
+                       return CircleSelector.Handle;
+               }
+       }
+}
index 882db45..76db94e 100644 (file)
@@ -414,7 +414,15 @@ namespace Xamarin.Forms.Platform.Tizen
                                        BackgroundColor = EColor.Transparent
                                };
 
-                               _pageBusyDialog.Style = "circle";
+                               if (Device.Idiom == TargetIdiom.Phone)
+                               {
+                                       _pageBusyDialog.SetPartColor("bg_title", EColor.Transparent);
+                                       _pageBusyDialog.SetPartColor("bg_content", EColor.Transparent);
+                               }
+                               else if (Device.Idiom == TargetIdiom.Watch)
+                               {
+                                       _pageBusyDialog.Style = "circle";
+                               }
 
                                var activity = new EProgressBar(_pageBusyDialog)
                                {
index eed21f5..668c6ee 100644 (file)
@@ -11,19 +11,26 @@ using Xamarin.Forms.Platform.Tizen;
 [assembly: ExportRenderer(typeof(CarouselPage), typeof(CarouselPageRenderer))]
 [assembly: ExportRenderer(typeof(Page), typeof(PageRenderer))]
 [assembly: ExportRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer))]
+[assembly: ExportRenderer(typeof(MasterDetailPage), typeof(MasterDetailPageRenderer))]
+[assembly: ExportRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer))]
 [assembly: ExportRenderer(typeof(Shell), typeof(ShellRenderer))]
 
 [assembly: ExportRenderer(typeof(Label), typeof(LabelRenderer))]
 [assembly: ExportRenderer(typeof(Button), typeof(ButtonRenderer))]
 [assembly: ExportRenderer(typeof(Image), typeof(ImageRenderer))]
 [assembly: ExportRenderer(typeof(Slider), typeof(SliderRenderer))]
+[assembly: ExportRenderer(typeof(Picker), typeof(PickerRenderer))]
 [assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
 [assembly: ExportRenderer(typeof(Stepper), typeof(StepperRenderer))]
+[assembly: ExportRenderer(typeof(DatePicker), typeof(DatePickerRenderer))]
+[assembly: ExportRenderer(typeof(TimePicker), typeof(TimePickerRenderer))]
 [assembly: ExportRenderer(typeof(ProgressBar), typeof(ProgressBarRenderer))]
 [assembly: ExportRenderer(typeof(Switch), typeof(SwitchRenderer))]
+[assembly: ExportRenderer(typeof(CheckBox), typeof(CheckBoxRenderer))]
 [assembly: ExportRenderer(typeof(ListView), typeof(ListViewRenderer))]
 [assembly: ExportRenderer(typeof(BoxView), typeof(BoxViewRenderer))]
 [assembly: ExportRenderer(typeof(ActivityIndicator), typeof(ActivityIndicatorRenderer))]
+[assembly: ExportRenderer(typeof(SearchBar), typeof(SearchBarRenderer))]
 [assembly: ExportRenderer(typeof(Entry), typeof(EntryRenderer))]
 [assembly: ExportRenderer(typeof(Editor), typeof(EditorRenderer))]
 [assembly: ExportRenderer(typeof(TableView), typeof(TableViewRenderer))]
index 184aff6..aee2845 100644 (file)
@@ -32,7 +32,10 @@ namespace Xamarin.Forms.Platform.Tizen
 
                protected virtual EButton CreateNativeControl()
                {
-                       return NativeFactory.GetNativeControl(typeof(Native.Watch.WatchButton)) as Native.Watch.WatchButton;
+                       if (Device.Idiom == TargetIdiom.Watch)
+                               return NativeFactory.GetNativeControl(typeof(Native.Watch.WatchButton)) as Native.Watch.WatchButton;
+                       else
+                               return NativeFactory.GetNativeControl(typeof(Native.Button)) as Native.Button;
                }
 
                protected override Size MinimumSize()
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/CheckBoxRenderer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/CheckBoxRenderer.cs
new file mode 100644 (file)
index 0000000..e13925d
--- /dev/null
@@ -0,0 +1,78 @@
+using System;
+using ElmSharp;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class CheckBoxRenderer : ViewRenderer<CheckBox, Check>
+       {
+               readonly string[] _onColorParts;
+               readonly string[] _onColorEdjeParts;
+
+               public CheckBoxRenderer()
+               {
+                       _onColorParts = Device.Idiom == TargetIdiom.Watch ? new string[] {"outer_bg_on", "outer_bg_on_pressed", "check_on", "check_on_pressed"} : new string[] {"bg_on", "stroke"};
+                       _onColorEdjeParts = new string[_onColorParts.Length];
+                       RegisterPropertyHandler(CheckBox.IsCheckedProperty, UpdateIsChecked);
+                       RegisterPropertyHandler(CheckBox.ColorProperty, UpdateOnColor);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<CheckBox> e)
+               {
+                       if (Control == null)
+                       {
+                               SetNativeControl(new Check(Forms.NativeParent));
+                               Control.StateChanged += OnStateChanged;
+                               for (int i=0; i<_onColorParts.Length; i++)
+                               {
+                                       _onColorEdjeParts[i] = Control.ClassName.ToLower().Replace("elm_", "") + "/" + _onColorParts[i];
+                               }
+                       }
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               if (Control != null)
+                               {
+                                       Control.StateChanged -= OnStateChanged;
+                               }
+                       }
+                       base.Dispose(disposing);
+               }
+
+               void OnStateChanged(object sender, EventArgs e)
+               {
+                       Element.SetValueFromRenderer(CheckBox.IsCheckedProperty, Control.IsChecked);
+               }
+
+               void UpdateIsChecked()
+               {
+                       Control.IsChecked = Element.IsChecked;
+               }
+
+               void UpdateOnColor(bool initialize)
+               {
+                       if (initialize && Element.Color.IsDefault)
+                               return;
+
+                       if (Element.Color.IsDefault)
+                       {
+                               foreach(string s in _onColorEdjeParts)
+                               {
+                                       Control.EdjeObject.DeleteColorClass(s);
+                               }
+                       }
+                       else
+                       {
+                               EColor color = Element.Color.ToNative();
+                               foreach (string s in _onColorParts)
+                               {
+                                       Control.SetPartColor(s, color);
+                               }
+                       }
+               }
+       }
+}
index f345ba1..dcf4002 100644 (file)
@@ -305,6 +305,10 @@ namespace Xamarin.Forms.Platform.Tizen
                        {
                                return false;
                        }
+                       if (parentPage is MasterDetailPage mdPage && mdPage.Master == parent && !mdPage.IsPresented)
+                       {
+                               return false;
+                       }
                        return PageIsVisible(parentPage);
                }
 
@@ -319,4 +323,4 @@ namespace Xamarin.Forms.Platform.Tizen
                        return ret;
                }
        }
-}
+}
\ No newline at end of file
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/DatePickerRenderer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/DatePickerRenderer.cs
new file mode 100644 (file)
index 0000000..b374c6d
--- /dev/null
@@ -0,0 +1,129 @@
+using System;
+using Xamarin.Forms.Platform.Tizen.Native;
+using WatchDataTimePickerDialog = Xamarin.Forms.Platform.Tizen.Native.Watch.WatchDataTimePickerDialog;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class DatePickerRenderer : ViewRenderer<DatePicker, EditfieldEntry>
+       {
+               //TODO need to add internationalization support
+               const string DialogTitle = "Choose Date";
+               Lazy<IDateTimeDialog> _lazyDialog;
+
+               public DatePickerRenderer()
+               {
+                       RegisterPropertyHandler(DatePicker.DateProperty, UpdateDate);
+                       RegisterPropertyHandler(DatePicker.FormatProperty, UpdateDate);
+                       RegisterPropertyHandler(DatePicker.TextColorProperty, UpdateTextColor);
+                       RegisterPropertyHandler(DatePicker.FontAttributesProperty, UpdateFontAttributes);
+                       RegisterPropertyHandler(DatePicker.FontFamilyProperty, UpdateFontFamily);
+                       RegisterPropertyHandler(DatePicker.FontSizeProperty, UpdateFontSize);
+               }
+
+               protected virtual IDateTimeDialog CreateDialog()
+               {
+                       if (Device.Idiom == TargetIdiom.Watch)
+                       {
+                               return new WatchDataTimePickerDialog(Forms.NativeParent);
+                       }
+                       else
+                       {
+                               return new DateTimePickerDialog(Forms.NativeParent);
+                       }
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
+               {
+                       if (Control == null)
+                       {
+                               var entry = new Native.EditfieldEntry(Forms.NativeParent)
+                               {
+                                       IsSingleLine = true,
+                                       HorizontalTextAlignment = Native.TextAlignment.Center,
+                                       InputPanelShowByOnDemand = true,
+                               };
+                               entry.SetVerticalTextAlignment("elm.text", 0.5);
+                               entry.TextBlockFocused += OnTextBlockFocused;
+                               SetNativeControl(entry);
+
+                               _lazyDialog = new Lazy<IDateTimeDialog>(() =>
+                               {
+                                       var dialog = CreateDialog();
+                                       dialog.Title = DialogTitle;
+                                       dialog.DateTimeChanged += OnDateTimeChanged;
+                                       return dialog;
+                               });
+                       }
+                       base.OnElementChanged(e);
+               }
+
+               protected override Size MinimumSize()
+               {
+                       return Control.Measure(Control.MinimumWidth, Control.MinimumHeight).ToDP();
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               if (Control != null)
+                               {
+                                       Control.TextBlockFocused -= OnTextBlockFocused;
+                               }
+                               if (_lazyDialog.IsValueCreated)
+                               {
+                                       _lazyDialog.Value.DateTimeChanged -= OnDateTimeChanged;
+                                       _lazyDialog.Value.Unrealize();
+                               }
+                       }
+                       base.Dispose(disposing);
+               }
+
+               void OnTextBlockFocused(object sender, EventArgs e)
+               {
+                       // For EFL Entry, the event will occur even if it is currently disabled.
+                       // If the problem is resolved, no conditional statement is required.
+                       if (Element.IsEnabled)
+                       {
+                               var dialog = _lazyDialog.Value;
+                               dialog.Picker.DateTime = Element.Date;
+                               dialog.Picker.MaximumDateTime = Element.MaximumDate;
+                               dialog.Picker.MinimumDateTime = Element.MinimumDate;
+                               // You need to call Show() after ui thread occupation because of EFL problem.
+                               // Otherwise, the content of the popup will not receive focus.
+                               Device.BeginInvokeOnMainThread(() => dialog.Show());
+                       }
+               }
+
+               void OnDateTimeChanged(object sender, Native.DateChangedEventArgs dcea)
+               {
+                       Element.Date = dcea.NewDate;
+                       Control.Text = dcea.NewDate.ToString(Element.Format);
+               }
+
+               void UpdateDate()
+               {
+                       Control.Text = Element.Date.ToString(Element.Format);
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.ToNative();
+               }
+
+               void UpdateFontSize()
+               {
+                       Control.FontSize = Element.FontSize;
+               }
+
+               void UpdateFontFamily()
+               {
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               void UpdateFontAttributes()
+               {
+                       Control.FontAttributes = Element.FontAttributes;
+               }
+       }
+}
index 98ad7a3..dd57006 100644 (file)
@@ -24,7 +24,7 @@ namespace Xamarin.Forms.Platform.Tizen
                        if (Control == null)
                        {
                                // Multiline EditField style is only available on Mobile and TV profile
-                               var entry = new Native.Entry(Forms.NativeParent)
+                               var entry = Device.Idiom == TargetIdiom.Phone || Device.Idiom == TargetIdiom.TV ? new Native.EditfieldEntry(Forms.NativeParent, "multiline") : new Native.Entry(Forms.NativeParent)
                                {
                                        IsSingleLine = false,
                                };
index fe7fea1..1db24c8 100644 (file)
@@ -9,7 +9,7 @@ namespace Xamarin.Forms.Platform.Tizen
                const int _shadow_shift = 2;
                const int _shadow_thickness = _thickness + 2;
 
-               static readonly EColor s_DefaultColor = EColor.Gray;
+               static readonly EColor s_DefaultColor = Device.Idiom == TargetIdiom.TV || Device.Idiom == TargetIdiom.Watch ? EColor.Gray : EColor.Black;
                static readonly EColor s_ShadowColor = EColor.FromRgba(80, 80, 80, 50);
 
                Polygon _shadow = null;
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailContainer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailContainer.cs
new file mode 100644 (file)
index 0000000..19ae542
--- /dev/null
@@ -0,0 +1,134 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen.Renderers
+{
+       public class MasterDetailContainer : ElmSharp.Box, IDisposable
+       {
+               readonly MasterDetailPage _parent;
+               readonly bool _isMaster;
+
+               VisualElement _childView;
+               bool _disposed;
+               bool _hasAppearedToParent;
+
+               IPageController PageController => ChildView as IPageController;
+               IMasterDetailPageController MasterDetailPageController => _parent as IMasterDetailPageController;
+
+               public MasterDetailContainer(MasterDetailPage parentElement, bool isMaster) : base(Forms.NativeParent)
+               {
+                       _parent = parentElement;
+                       _isMaster = isMaster;
+
+                       SetLayoutCallback(OnLayoutUpdated);
+                       Show();
+               }
+
+               ~MasterDetailContainer()
+               {
+                       Dispose(false);
+               }
+
+               public VisualElement ChildView
+               {
+                       get { return _childView; }
+                       set
+                       {
+                               if (_childView == value)
+                                       return;
+
+                               if (_childView != null)
+                               {
+                                       RemoveChildView();
+                               }
+
+                               _childView = value;
+
+                               if (_childView == null)
+                                       return;
+
+                               AddChildView(_childView);
+
+                               if (_hasAppearedToParent)
+                               {
+                                       Device.BeginInvokeOnMainThread(() =>
+                                       {
+                                               if (!_disposed && _hasAppearedToParent)
+                                                       PageController?.SendAppearing();
+                                       });
+                               }
+                       }
+               }
+
+               public void Dispose()
+               {
+                       Dispose(true);
+                       GC.SuppressFinalize(this);
+               }
+
+               protected void RemoveChildView()
+               {
+                       IVisualElementRenderer childRenderer = Platform.GetRenderer(_childView);
+                       if (childRenderer != null)
+                       {
+                               UnPack(childRenderer.NativeView);
+                               childRenderer.Dispose();
+                       }
+               }
+
+               protected void AddChildView(VisualElement childView)
+               {
+                       IVisualElementRenderer renderer = Platform.GetOrCreateRenderer(childView);
+                       this.PackEnd(renderer.NativeView);
+               }
+
+               protected virtual void Dispose(bool disposing)
+               {
+                       if (_disposed)
+                               return;
+
+                       if (disposing)
+                       {
+                               if (_childView != null)
+                               {
+                                       RemoveChildView();
+                               }
+                               SetLayoutCallback(null);
+                       }
+                       _disposed = true;
+               }
+
+               void OnLayoutUpdated()
+               {
+                       if (_childView != null)
+                       {
+                               if (_isMaster)
+                                       MasterDetailPageController.MasterBounds = this.Geometry.ToDP();
+                               else
+                                       MasterDetailPageController.DetailBounds = this.Geometry.ToDP();
+
+                               IVisualElementRenderer renderer = Platform.GetRenderer(_childView);
+                               renderer.NativeView.Geometry = this.Geometry;
+                       }
+               }
+
+               public void SendAppearing()
+               {
+                       if (_hasAppearedToParent)
+                               return;
+
+                       _hasAppearedToParent = true;
+
+                       PageController?.SendAppearing();
+               }
+
+               public void SendDisappearing()
+               {
+                       if (!_hasAppearedToParent)
+                               return;
+
+                       _hasAppearedToParent = false;
+
+                       PageController?.SendDisappearing();
+               }
+       }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs
new file mode 100644 (file)
index 0000000..c3b0d51
--- /dev/null
@@ -0,0 +1,157 @@
+using System;
+using Xamarin.Forms.Platform.Tizen.Renderers;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class MasterDetailPageRenderer : VisualElementRenderer<MasterDetailPage>
+       {
+               Native.MasterDetailPage _mdpage;
+               MasterDetailContainer _masterContainer = null;
+               MasterDetailContainer _detailContainer = null;
+
+               /// <summary>
+               /// Default constructor.
+               /// </summary>
+               public MasterDetailPageRenderer()
+               {
+                       RegisterPropertyHandler(nameof(Element.Master), UpdateMasterPage);
+                       RegisterPropertyHandler(nameof(Element.Detail), UpdateDetailPage);
+                       RegisterPropertyHandler(MasterDetailPage.IsPresentedProperty,
+                               UpdateIsPresented);
+                       RegisterPropertyHandler(MasterDetailPage.MasterBehaviorProperty,
+                               UpdateMasterBehavior);
+                       RegisterPropertyHandler(MasterDetailPage.IsGestureEnabledProperty,
+                               UpdateIsGestureEnabled);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<MasterDetailPage> e)
+               {
+                       if (_mdpage == null)
+                       {
+                               _mdpage = new Native.MasterDetailPage(Forms.NativeParent)
+                               {
+                                       IsPresented = e.NewElement.IsPresented,
+                                       Master = _masterContainer = new MasterDetailContainer(Element, true),
+                                       Detail = _detailContainer = new MasterDetailContainer(Element, false),
+                               };
+
+                               _mdpage.IsPresentedChanged += (sender, ev) =>
+                               {
+                                       Element.IsPresented = ev.IsPresent;
+                               };
+                               _mdpage.UpdateIsPresentChangeable += (sender, ev) =>
+                               {
+                                       (Element as IMasterDetailPageController).CanChangeIsPresented = ev.CanChange;
+                               };
+                               SetNativeView(_mdpage);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               (e.OldElement as IMasterDetailPageController).BackButtonPressed -= OnBackButtonPressed;
+                               e.OldElement.Appearing -= OnMasterDetailAppearing;
+                               e.OldElement.Disappearing -= OnMasterDetailDisappearing;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               (e.NewElement as IMasterDetailPageController).BackButtonPressed += OnBackButtonPressed;
+                               e.NewElement.Appearing += OnMasterDetailAppearing;
+                               e.NewElement.Disappearing += OnMasterDetailDisappearing;
+                       }
+
+                       UpdateMasterBehavior();
+                       base.OnElementChanged(e);
+               }
+
+               void OnMasterDetailDisappearing(object sender, EventArgs e)
+               {
+                       _masterContainer?.SendDisappearing();
+                       _detailContainer?.SendDisappearing();
+               }
+
+               void OnMasterDetailAppearing(object sender, EventArgs e)
+               {
+                       _masterContainer?.SendAppearing();
+                       _detailContainer?.SendAppearing();
+               }
+
+               protected override void OnElementReady()
+               {
+                       base.OnElementReady();
+                       UpdateMasterPage(false);
+                       UpdateDetailPage(false);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               if (_masterContainer != null)
+                               {
+                                       _masterContainer.Dispose();
+                                       _masterContainer = null;
+                               }
+
+                               if (_detailContainer != null)
+                               {
+                                       _detailContainer.Dispose();
+                                       _detailContainer = null;
+                               }
+
+                               if (Element != null)
+                               {
+                                       Element.Appearing -= OnMasterDetailAppearing;
+                                       Element.Disappearing -= OnMasterDetailDisappearing;
+                               }
+                       }
+
+                       base.Dispose(disposing);
+               }
+
+               protected void UpdateMasterPageRatio(double popoverRatio, double splitRatio)
+               {
+                       _mdpage.PopoverRatio = popoverRatio;
+                       _mdpage.SplitRatio = splitRatio;
+               }
+
+               void OnBackButtonPressed(object sender, BackButtonPressedEventArgs e)
+               {
+                       if ((Element != null) && Element.IsPresented && !_mdpage.IsSplit)
+                       {
+                               Element.IsPresented = false;
+                               e.Handled = true;
+                       }
+               }
+
+               void UpdateMasterBehavior()
+               {
+                       _mdpage.MasterBehavior = Element.MasterBehavior;
+               }
+
+               void UpdateMasterPage(bool isInit)
+               {
+                       if (!isInit)
+                               _masterContainer.ChildView = Element.Master;
+               }
+
+               void UpdateDetailPage(bool isInit)
+               {
+                       if (!isInit)
+                               _detailContainer.ChildView = Element.Detail;
+               }
+
+               void UpdateIsPresented()
+               {
+                       // To update TabIndex order
+                       CustomFocusManager.StartReorderTabIndex();
+
+                       _mdpage.IsPresented = Element.IsPresented;
+               }
+
+               void UpdateIsGestureEnabled()
+               {
+                       _mdpage.IsGestureEnabled = Element.IsGestureEnabled;
+               }
+       }
+}
index f04a1c6..bb0772d 100644 (file)
@@ -3,18 +3,37 @@ using System.Linq;
 using System.Threading.Tasks;
 using System.Collections.Generic;
 using Xamarin.Forms.Internals;
+using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
 using ElmSharp;
+using EButton = ElmSharp.Button;
+using EToolbar = ElmSharp.Toolbar;
+using EToolbarItem = ElmSharp.ToolbarItem;
+using Specific = Xamarin.Forms.PlatformConfiguration.TizenSpecific.NavigationPage;
+using SpecificPage = Xamarin.Forms.PlatformConfiguration.TizenSpecific.Page;
 
 namespace Xamarin.Forms.Platform.Tizen
 {
        public class NavigationPageRenderer : VisualElementRenderer<NavigationPage>
        {
+               enum ToolbarButtonPosition
+               {
+                       Left,
+                       Right
+               };
+
                const string PartTitle = "default";
+               const string PartBackButton = "elm.swallow.prev_btn";
+               const string PartLeftToolbar = "title_left_btn";
+               const string PartRightToolbar = "title_right_btn";
+               const string PartNavigationBar = "navigationbar";
+               const string StyleBackButton = "naviframe/back_btn/default";
+               const string StyleNavigationBar = "navigationbar";
 
                readonly List<Widget> _naviItemContentPartList = new List<Widget>();
                Naviframe _naviFrame = null;
                Page _previousPage = null;
                TaskCompletionSource<bool> _currentTaskSource = null;
+               ToolbarTracker _toolbarTracker = null;
                IDictionary<Page, NaviItem> _naviItemMap;
 
                Page CurrentPage => Element.CurrentPage;
@@ -30,6 +49,10 @@ namespace Xamarin.Forms.Platform.Tizen
                                {
                                        _naviFrame.AnimationFinished -= OnAnimationFinished;
                                }
+                               if (_toolbarTracker != null)
+                               {
+                                       _toolbarTracker.CollectionChanged -= OnToolbarCollectionChanged;
+                               }
                        }
                        base.Dispose(disposing);
                }
@@ -47,6 +70,12 @@ namespace Xamarin.Forms.Platform.Tizen
                                _naviItemMap = new Dictionary<Page, NaviItem>();
                        }
 
+                       if (_toolbarTracker == null)
+                       {
+                               _toolbarTracker = new ToolbarTracker();
+                               _toolbarTracker.CollectionChanged += OnToolbarCollectionChanged;
+                       }
+
                        if (e.OldElement != null)
                        {
                                var navigation = e.OldElement as INavigationPageController;
@@ -69,6 +98,7 @@ namespace Xamarin.Forms.Platform.Tizen
                                navigation.RemovePageRequested += OnRemovePageRequested;
                                navigation.InsertPageBeforeRequested += OnInsertPageBeforeRequested;
 
+                               _toolbarTracker.Target = e.NewElement;
                                _previousPage = e.NewElement.CurrentPage;
                        }
                        base.OnElementChanged(e);
@@ -107,6 +137,9 @@ namespace Xamarin.Forms.Platform.Tizen
                        // Tizen does not support 'Tint', but only 'BarBackgroundColor'
                        else if (e.PropertyName == NavigationPage.BarBackgroundColorProperty.PropertyName)
                                UpdateBarBackgroundColor(CurrentNaviItem);
+                       else if (e.PropertyName == Specific.HasBreadCrumbsBarProperty.PropertyName)
+                               UpdateBreadCrumbsBar(CurrentNaviItem);
+
                }
 
                void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
@@ -119,13 +152,23 @@ namespace Xamarin.Forms.Platform.Tizen
                                        page.PropertyChanged += NavigationBarPropertyChangedHandler;
                }
 
+               void OnToolbarCollectionChanged(object sender, EventArgs eventArgs)
+               {
+                       UpdateToolbarItem(Element.CurrentPage);
+               }
+
                void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
                {
                        // this handler is invoked only for child pages (contained on a navigation stack)
                        if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName)
                                UpdateHasNavigationBar(sender as Page);
+                       else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName ||
+                               e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName)
+                               UpdateHasBackButton(sender as Page);
                        else if (e.PropertyName == Page.TitleProperty.PropertyName)
                                UpdateTitle(sender as Page);
+                       else if (e.PropertyName == SpecificPage.BreadCrumbProperty.PropertyName)
+                               UpdateBreadCrumbsBar(GetNaviItemForPage(sender as Page));
                }
 
                void UpdateHasNavigationBar(Page page)
@@ -141,8 +184,45 @@ namespace Xamarin.Forms.Platform.Tizen
                                }
                                return;
                        }
+                       //According to TV UX Guideline, item style should be set to "tabbar" in case of TabbedPage only for TV profile.
+                       if (Device.Idiom == TargetIdiom.TV)
+                       {
+                               item.Style = page is TabbedPage ? "tabbar" : "default";
+                       }
                        item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty);
+                       UpdateToolbarItem(page, item);
                        UpdateBarBackgroundColor(item);
+                       UpdateBreadCrumbsBar(item);
+               }
+
+               void UpdateToolbarItem(Page page, NaviItem item = null)
+               {
+                       if (item == null)
+                               item = GetNaviItemForPage(page);
+
+                       if (_naviFrame.NavigationStack.Count == 0 || item == null || item != _naviFrame.NavigationStack.Last())
+                               return;
+
+                       Native.Button rightButton = GetToolbarButton(ToolbarButtonPosition.Right);
+                       item.SetPartContent(PartRightToolbar, rightButton);
+
+                       Native.Button leftButton = GetToolbarButton(ToolbarButtonPosition.Left);
+                       item.SetPartContent(PartLeftToolbar, leftButton);
+                       UpdateHasBackButton(page, item);
+               }
+
+               void UpdateHasBackButton(Page page, NaviItem item = null)
+               {
+                       if (item == null)
+                               item = GetNaviItemForPage(page);
+
+                       EButton button = null;
+
+                       if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && _naviFrame.NavigationStack.Count > 1)
+                       {
+                               button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty));
+                       }
+                       item.SetPartContent(PartBackButton, button);
                }
 
                void UpdateTitle(Page page, NaviItem item = null)
@@ -178,6 +258,37 @@ namespace Xamarin.Forms.Platform.Tizen
                        UpdateBarBackgroundColor(item);
                }
 
+               void UpdateBreadCrumbsBar(NaviItem item)
+               {
+                       if (Element.OnThisPlatform().HasBreadCrumbsBar())
+                       {
+                               item.Style = StyleNavigationBar;
+                               item.SetPartContent(PartNavigationBar, GetBreadCrumbsBar());
+                       }
+                       else
+                       {
+                               item.SetPartContent(PartNavigationBar, null, false);
+                       }
+               }
+
+               EButton CreateNavigationButton(string text)
+               {
+                       EButton button = new EButton(Forms.NativeParent);
+                       button.Clicked += (sender, e) =>
+                       {
+                               if (!Element.SendBackButtonPressed())
+                                       Forms.Context.Exit();
+                       };
+
+                       button.Style = StyleBackButton;
+                       button.Text = text;
+
+                       _naviItemContentPartList.Add(button);
+                       button.Deleted += NaviItemPartContentDeletedHandler;
+
+                       return button;
+               }
+
                void NaviItemPartContentDeletedHandler(object sender, EventArgs e)
                {
                        _naviItemContentPartList.Remove(sender as Widget);
@@ -193,6 +304,53 @@ namespace Xamarin.Forms.Platform.Tizen
                        return null;
                }
 
+               Native.Button GetToolbarButton(ToolbarButtonPosition position)
+               {
+                       ToolbarItem item = _toolbarTracker.ToolbarItems.Where(
+                               i => (position == ToolbarButtonPosition.Right && i.Order <= ToolbarItemOrder.Primary)
+                               || (position == ToolbarButtonPosition.Left && i.Order == ToolbarItemOrder.Secondary))
+                               .OrderBy(i => i.Priority).FirstOrDefault();
+
+                       if (item == default(ToolbarItem))
+                               return null;
+
+                       Native.ToolbarItemButton button = new Native.ToolbarItemButton(item);
+                       return button;
+               }
+
+               EToolbar GetBreadCrumbsBar()
+               {
+                       EToolbar toolbar = new EToolbar(Forms.NativeParent)
+                       {
+                               Style = StyleNavigationBar,
+                               ItemAlignment = 0,
+                               Homogeneous = false,
+                               ShrinkMode = ToolbarShrinkMode.Scroll
+                       };
+
+                       foreach (var p in Element.Navigation.NavigationStack)
+                       {
+                               string breadCrumb = p.OnThisPlatform().GetBreadCrumb();
+                               if (!string.IsNullOrEmpty(breadCrumb))
+                               {
+                                       EToolbarItem toolbarItem = toolbar.Append(breadCrumb);
+                                       toolbarItem.Selected += (s, e) =>
+                                       {
+                                               var copyOfStack = Element.Navigation.NavigationStack.Reverse().Skip(1);
+                                               foreach (var lp in copyOfStack)
+                                               {
+                                                       if (lp == p) break;
+                                                       Element.Navigation.RemovePage(lp);
+                                               }
+                                               if (Element.Navigation.NavigationStack.Last() != p)
+                                                       Element.Navigation.PopAsync();
+                                       };
+                               }
+                       }
+
+                       return toolbar;
+               }
+
                void OnPopRequested(object sender, NavigationRequestedEventArgs nre)
                {
                        if ((Element as IPageController).InternalChildren.Count == _naviFrame.NavigationStack.Count)
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/PickerRenderer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/PickerRenderer.cs
new file mode 100644 (file)
index 0000000..abfc0c2
--- /dev/null
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using Xamarin.Forms.Platform.Tizen.Native;
+using Xamarin.Forms.Platform.Tizen.Native.Watch;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class PickerRenderer : ViewRenderer<Picker, EditfieldEntry>
+       {
+               List _list;
+               Dialog _dialog;
+               Dictionary<ListItem, int> _itemToItemNumber = new Dictionary<ListItem, int>();
+
+               public PickerRenderer()
+               {
+                       RegisterPropertyHandler(Picker.SelectedIndexProperty, UpdateSelectedIndex);
+                       RegisterPropertyHandler(Picker.TextColorProperty, UpdateTextColor);
+                       RegisterPropertyHandler(Picker.FontSizeProperty, UpdateFontSize);
+                       RegisterPropertyHandler(Picker.FontFamilyProperty, UpdateFontFamily);
+                       RegisterPropertyHandler(Picker.FontAttributesProperty, UpdateFontAttributes);
+                       RegisterPropertyHandler(Picker.TitleProperty, UpdateTitle);
+                       RegisterPropertyHandler(Picker.TitleColorProperty, UpdateTitleColor);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               if (Control != null)
+                               {
+                                       Control.TextBlockFocused -= OnTextBlockFocused;
+                                       if (Device.Idiom == TargetIdiom.TV)
+                                       {
+                                               Control.LayoutFocused -= OnLayoutFocused;
+                                               Control.LayoutUnfocused -= OnLayoutUnfocused;
+                                       }
+                                       CleanView();
+                               }
+                       }
+                       base.Dispose(disposing);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
+               {
+                       if (Control == null)
+                       {
+                               var entry = new EditfieldEntry(Forms.NativeParent)
+                               {
+                                       IsSingleLine = true,
+                                       InputPanelShowByOnDemand = true,
+                               };
+                               entry.SetVerticalTextAlignment("elm.text", 0.5);
+                               entry.HorizontalTextAlignment = Native.TextAlignment.Center;
+                               entry.TextBlockFocused += OnTextBlockFocused;
+
+                               if (Device.Idiom == TargetIdiom.TV)
+                               {
+                                       entry.LayoutFocused += OnLayoutFocused;
+                                       entry.LayoutUnfocused += OnLayoutUnfocused;
+                               }
+
+                               SetNativeControl(entry);
+                       }
+                       base.OnElementChanged(e);
+               }
+
+               void UpdateSelectedIndex()
+               {
+                       Control.Text = (Element.SelectedIndex == -1 || Element.Items == null ?
+                               "" : Element.Items[Element.SelectedIndex]);
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.ToNative();
+               }
+
+               void UpdateFontSize()
+               {
+                       Control.FontSize = Element.FontSize;
+               }
+
+               void UpdateFontFamily()
+               {
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               void UpdateFontAttributes()
+               {
+                       Control.FontAttributes = Element.FontAttributes;
+               }
+
+               void UpdateTitle()
+               {
+                       Control.Placeholder = Element.Title;
+               }
+
+               void UpdateTitleColor()
+               {
+                       Control.PlaceholderColor = Element.TitleColor.ToNative();
+               }
+
+               void OnLayoutFocused(object sender, EventArgs e)
+               {
+                       Control.FontSize = Control.FontSize * 1.5;
+               }
+
+               void OnLayoutUnfocused(object sender, EventArgs e)
+               {
+                       Control.FontSize = Control.FontSize / 1.5;
+               }
+
+               void OnTextBlockFocused(object sender, EventArgs e)
+               {
+                       // For EFL Entry, the event will occur even if it is currently disabled.
+                       // If the problem is resolved, no conditional statement is required.
+                       if (Element.IsEnabled)
+                       {
+                               int i = 0;
+                               if (Device.Idiom == TargetIdiom.Watch)
+                               {
+                                       _dialog = new WatchDialog(Forms.NativeParent, false);
+                               }
+                               else
+                               {
+                                       _dialog = new Dialog(Forms.NativeParent);
+                               }
+                               _dialog.AlignmentX = -1;
+                               _dialog.AlignmentY = -1;
+                               _dialog.Title = Element.Title;
+                               _dialog.TitleColor = Element.TitleColor.ToNative();
+                               _dialog.Dismissed += OnDialogDismissed;
+                               _dialog.BackButtonPressed += (object senders, EventArgs es) =>
+                               {
+                                       _dialog.Dismiss();
+                               };
+
+                               _list = new List(_dialog);
+                               foreach (var s in Element.Items)
+                               {
+                                       ListItem item = _list.Append(s);
+                                       _itemToItemNumber[item] = i;
+                                       i++;
+                               }
+                               _list.ItemSelected += OnItemSelected;
+                               _dialog.Content = _list;
+
+                               // You need to call Show() after ui thread occupation because of EFL problem.
+                               // Otherwise, the content of the popup will not receive focus.
+                               Device.BeginInvokeOnMainThread(() =>
+                               {
+                                       _dialog.Show();
+                                       _list.Show();
+                               });
+                       }
+               }
+
+               void OnItemSelected(object senderObject, EventArgs ev)
+               {
+                       Element.SetValueFromRenderer(Picker.SelectedIndexProperty, _itemToItemNumber[(senderObject as List).SelectedItem]);
+                       _dialog.Dismiss();
+               }
+
+               void OnDialogDismissed(object sender, EventArgs e)
+               {
+                       CleanView();
+               }
+
+               void CleanView()
+               {
+                       if (null != _list)
+                       {
+                               _list.Unrealize();
+                               _itemToItemNumber.Clear();
+                               _list = null;
+                       }
+                       if (null != _dialog)
+                       {
+                               _dialog.Unrealize();
+                               _dialog = null;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/SearchBarRenderer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/SearchBarRenderer.cs
new file mode 100644 (file)
index 0000000..1fc450b
--- /dev/null
@@ -0,0 +1,212 @@
+using System;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class SearchBarRenderer : ViewRenderer<SearchBar, Native.SearchBar>
+       {
+
+               /// <summary>
+               /// Creates a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.SearchBarRenderer"/> class.
+               /// Registers handlers for various properties of the SearchBar widget.
+               /// </summary>
+               public SearchBarRenderer()
+               {
+                       RegisterPropertyHandler(SearchBar.CancelButtonColorProperty, CancelButtonColorPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.FontAttributesProperty, FontAttributesPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.FontFamilyProperty, FontFamilyPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.FontSizeProperty, FontSizePropertyHandler);
+                       RegisterPropertyHandler(SearchBar.HorizontalTextAlignmentProperty, HorizontalTextAlignmentPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.PlaceholderProperty, PlaceholderPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.PlaceholderColorProperty, PlaceholderColorPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.TextProperty, TextPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.TextColorProperty, TextColorPropertyHandler);
+                       RegisterPropertyHandler(InputView.KeyboardProperty, UpdateKeyboard);
+                       RegisterPropertyHandler(InputView.MaxLengthProperty, UpdateMaxLength);
+                       RegisterPropertyHandler(InputView.IsSpellCheckEnabledProperty, UpdateIsSpellCheckEnabled);
+                       RegisterPropertyHandler(InputView.IsReadOnlyProperty, UpdateIsReadOnly);
+               }
+
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               if (Control != null)
+                               {
+                                       Control.TextChanged -= OnTextChanged;
+                                       Control.Activated -= OnActivated;
+                               }
+                       }
+                       base.Dispose(disposing);
+               }
+
+               /// <summary>
+               /// A method called whenever the associated element has changed.
+               /// </summary>
+               protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
+               {
+                       if (Control == null)
+                       {
+                               SetNativeControl(new Native.SearchBar(Forms.NativeParent));
+                               Control.IsSingleLine = true;
+                               Control.SetInputPanelReturnKeyType(ElmSharp.InputPanelReturnKeyType.Search);
+
+                               Control.TextChanged += OnTextChanged;
+                               Control.Activated += OnActivated;
+                               Control.PrependMarkUpFilter(MaxLengthFilter);
+
+                       }
+                       base.OnElementChanged(e);
+               }
+
+               protected override Size MinimumSize()
+               {
+                       return Control.Measure(Control.MinimumWidth, Control.MinimumHeight).ToDP();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's cancel button color property.
+               /// Converts current Color to ElmSharp.Color instance and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native widget.
+               /// </summary>
+               void CancelButtonColorPropertyHandler(bool initialize)
+               {
+                       if (initialize && Element.CancelButtonColor.IsDefault)
+                               return;
+
+                       Control.SetClearButtonColor(Element.CancelButtonColor.ToNative());
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's font attributes property.
+               /// Converts current FontAttributes to ElmSharp.FontAttributes instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void FontAttributesPropertyHandler()
+               {
+                       Control.FontAttributes = Element.FontAttributes;
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's font family property.
+               /// Sets current value of FontFamily property to the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void FontFamilyPropertyHandler()
+               {
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's font size property.
+               /// Sets current value of FontSize property to the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void FontSizePropertyHandler()
+               {
+                       Control.FontSize = Element.FontSize;
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's horizontal text alignment property.
+               /// Converts current HorizontalTextAlignment property's value to Xamarin.Forms.Platform.Tizen.Native.TextAlignment instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void HorizontalTextAlignmentPropertyHandler()
+               {
+                       Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's placeholder color property.
+               /// Converts current PlaceholderColor property value to ElmSharp.Color instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void PlaceholderColorPropertyHandler(bool initialize)
+               {
+                       if (initialize && Element.TextColor.IsDefault)
+                               return;
+
+                       Control.PlaceholderColor = Element.PlaceholderColor.ToNative();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's placeholder text property.
+               /// </summary>
+               void PlaceholderPropertyHandler()
+               {
+                       Control.Placeholder = Element.Placeholder;
+               }
+
+               /// <summary>
+               /// Called on every change of underlying SearchBar's Text property.
+               /// Rewrites current underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar's Text contents to its Xamarin counterpart.
+               /// </summary>
+               /// <param name="sender">Sender.</param>
+               void OnTextChanged(object sender, EventArgs e)
+               {
+                       Element.SetValueFromRenderer(SearchBar.TextProperty, Control.Text);
+               }
+
+               /// <summary>
+               /// Called when the user clicks the Search button.
+               /// </summary>
+               /// <param name="sender">Sender.</param>
+               /// <param name="e">Event arguments.</param>
+               void OnActivated(object sender, EventArgs e)
+               {
+                       Control.HideInputPanel();
+                       (Element as ISearchBarController).OnSearchButtonPressed();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's text color property.
+               /// Converts current TextColor property value to ElmSharp.Color instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void TextColorPropertyHandler(bool initialize)
+               {
+                       if (initialize && Element.TextColor.IsDefault)
+                               return;
+
+                       Control.TextColor = Element.TextColor.ToNative();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's text property.
+               /// </summary>
+               void TextPropertyHandler()
+               {
+                       Control.Text = Element.Text;
+               }
+
+               void UpdateKeyboard(bool initialize)
+               {
+                       if (initialize && Element.Keyboard == Keyboard.Default)
+                               return;
+                       Control.UpdateKeyboard(Element.Keyboard, Element.IsSpellCheckEnabled, true);
+               }
+
+               void UpdateIsSpellCheckEnabled()
+               {
+                       Control.InputHint = Element.Keyboard.ToInputHints(Element.IsSpellCheckEnabled, true);
+               }
+
+               void UpdateMaxLength()
+               {
+                       if (Control.Text.Length > Element.MaxLength)
+                               Control.Text = Control.Text.Substring(0, Element.MaxLength);
+               }
+
+               string MaxLengthFilter(ElmSharp.Entry entry, string s)
+               {
+                       if (entry.Text.Length < Element.MaxLength)
+                               return s;
+
+                       return null;
+               }
+
+               void UpdateIsReadOnly()
+               {
+                       Control.IsEditable = !Element.IsReadOnly;
+               }
+       }
+}
index af9f131..14398f5 100644 (file)
@@ -9,11 +9,13 @@ namespace Xamarin.Forms.Platform.Tizen
        public class SwitchRenderer : ViewRenderer<Switch, Check>
        {
                readonly string _onColorPart;
+               readonly bool _isTV;
                string _onColorEdjePart;
 
                public SwitchRenderer()
                {
-                       _onColorPart = "outer_bg_on";
+                       _isTV = Device.Idiom == TargetIdiom.TV;
+                       _onColorPart = _isTV ? "slider_on" : Device.Idiom == TargetIdiom.Watch ? "outer_bg_on" : "bg_on";
                        RegisterPropertyHandler(Switch.IsToggledProperty, HandleToggled);
                        RegisterPropertyHandler(Switch.OnColorProperty, UpdateOnColor);
                }
@@ -83,11 +85,15 @@ namespace Xamarin.Forms.Platform.Tizen
                        if (Element.OnColor.IsDefault)
                        {
                                Control.EdjeObject.DeleteColorClass(_onColorEdjePart);
+                               if (_isTV)
+                                       Control.EdjeObject.DeleteColorClass(_onColorEdjePart.Replace(_onColorPart, "slider_focused_on"));
                        }
                        else
                        {
                                EColor color = Element.OnColor.ToNative();
                                Control.SetPartColor(_onColorPart, color);
+                               if (_isTV)
+                                       Control.SetPartColor("slider_focused_on", color);
                        }
                }
        }
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs
new file mode 100644 (file)
index 0000000..cb812e6
--- /dev/null
@@ -0,0 +1,557 @@
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Linq;
+using ElmSharp;
+using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
+using EColor = ElmSharp.Color;
+using EToolbarItem = ElmSharp.ToolbarItem;
+using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class TabbedPageRenderer : VisualElementRenderer<TabbedPage>
+       {
+               Box _outterLayout;
+               Box _innerBox;
+               Scroller _scroller;
+               Toolbar _toolbar;
+               Dictionary<EToolbarItem, Page> _itemToItemPage = new Dictionary<EToolbarItem, Page>();
+               List<EToolbarItem> _toolbarItemList = new List<EToolbarItem>();
+               bool _isResettingToolbarItems = false;
+               bool _isInitialized = false;
+               bool _isUpdateByToolbar = false;
+               bool _isUpdateByScroller = false;
+               bool _isUpdateByCurrentPage = false;
+
+               public TabbedPageRenderer()
+               {
+                       RegisterPropertyHandler(Page.TitleProperty, UpdateTitle);
+                       RegisterPropertyHandler(nameof(Element.CurrentPage), OnCurrentPageChanged);
+                       RegisterPropertyHandler(TabbedPage.BarBackgroundColorProperty, UpdateBarBackgroundColor);
+                       RegisterPropertyHandler(TabbedPage.BarTextColorProperty, UpdateBarTextColor);
+                       RegisterPropertyHandler(TabbedPage.SelectedTabColorProperty, UpdateSelectedTabColor);
+                       RegisterPropertyHandler(TabbedPage.UnselectedTabColorProperty, UpdateUnselectedTabColor);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
+               {
+                       if (_toolbar == null)
+                       {
+                               //Create box that holds toolbar and selected content
+                               _outterLayout = new Box(Forms.NativeParent)
+                               {
+                                       AlignmentX = -1,
+                                       AlignmentY = -1,
+                                       WeightX = 1,
+                                       WeightY = 1,
+                                       IsHorizontal = false,
+                               };
+                               _outterLayout.Show();
+
+                               //Create toolbar that is placed inside the _outterLayout
+                               _toolbar = new Toolbar(Forms.NativeParent)
+                               {
+                                       AlignmentX = -1,
+                                       WeightX = 1,
+                                       SelectionMode = ToolbarSelectionMode.Always,
+                               };
+
+                               if (Device.Idiom == TargetIdiom.Phone)
+                               {
+                                       //Set ShrinkMode to Expand as defauly only for Mobile profile
+                                       _toolbar.ShrinkMode = ToolbarShrinkMode.Expand;
+                               }
+                               else if (Device.Idiom == TargetIdiom.TV)
+                               {
+                                       //According to TV UX Guideline, toolbar style should be set to "tabbar_with_title" in case of TabbedPage only for TV profile.
+                                       _toolbar.Style = "tabbar_with_title";
+                               }
+
+                               _toolbar.Show();
+                               //Add callback for Toolbar item selection
+                               _toolbar.Selected += OnToolbarItemSelected;
+                               _outterLayout.PackEnd(_toolbar);
+
+                               _scroller = new Scroller(_outterLayout)
+                               {
+                                       AlignmentX = -1,
+                                       AlignmentY = -1,
+                                       WeightX = 1,
+                                       WeightY = 1,
+                                       HorizontalPageScrollLimit = 1,
+                                       ScrollBlock = ScrollBlock.Vertical,
+                                       HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible
+                               };
+                               _scroller.SetPageSize(1.0, 1.0);
+                               _scroller.PageScrolled += OnItemPageScrolled;
+
+                               _innerBox = new Box(Forms.NativeParent)
+                               {
+                                       AlignmentX = -1,
+                                       AlignmentY = -1,
+                                       WeightX = 1,
+                                       WeightY = 1,
+                                       IsHorizontal = true,
+                               };
+
+                               _innerBox.SetLayoutCallback(OnInnerLayoutUpdate);
+
+                               _scroller.SetContent(_innerBox);
+                               _scroller.Show();
+
+                               _outterLayout.PackEnd(_scroller);
+
+                               SetNativeView(_outterLayout);
+                               UpdateTitle();
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               e.OldElement.PagesChanged -= OnElementPagesChanged;
+                               _isInitialized = false;
+                       }
+                       if (e.NewElement != null)
+                       {
+                               e.NewElement.PagesChanged += OnElementPagesChanged;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               Element.PagesChanged -= OnElementPagesChanged;
+                               if (_outterLayout != null)
+                               {
+                                       _outterLayout.Unrealize();
+                                       _outterLayout = null;
+                               }
+                               if (_toolbar != null)
+                               {
+                                       _toolbar.Selected -= OnToolbarItemSelected;
+                                       _scroller.PageScrolled -= OnItemPageScrolled;
+                                       _toolbar.Unrealize();
+                                       _toolbar = null;
+                               }
+                       }
+                       base.Dispose(disposing);
+               }
+
+               protected override void OnElementReady()
+               {
+                       base.OnElementReady();
+                       _isInitialized = true;
+                       FillToolbarAndContents();
+                       Element.UpdateFocusTreePolicy();
+               }
+
+               protected override void UpdateThemeStyle()
+               {
+                       var style = Element.OnThisPlatform().GetStyle();
+                       if (!string.IsNullOrEmpty(style))
+                       {
+                               _toolbar.Style = style;
+                               ((IVisualElementController)Element).NativeSizeChanged();
+                       }
+               }
+
+               void OnInnerLayoutUpdate()
+               {
+                       if (!_isInitialized)
+                               return;
+
+                       int baseX = _innerBox.Geometry.X;
+                       Rect bound = _scroller.Geometry;
+                       int index = 0;
+                       foreach (var page in Element.Children)
+                       {
+                               var nativeView = Platform.GetRenderer(page).NativeView;
+                               bound.X = baseX + index * bound.Width;
+                               nativeView.Geometry = bound;
+                               index++;
+                       }
+                       _innerBox.MinimumWidth = Element.Children.Count * bound.Width;
+                       if (_toolbar.SelectedItem == null)
+                               return;
+                       int currentPage = MultiPage<Page>.GetIndex(_itemToItemPage[_toolbar.SelectedItem]);
+                       _scroller.ScrollTo(currentPage, 0, false);
+               }
+
+               void OnItemPageScrolled(object sender, System.EventArgs e)
+               {
+                       if (_isUpdateByToolbar || _isUpdateByCurrentPage)
+                               return;
+                       _isUpdateByScroller = true;
+
+                       var oldPage = Element.CurrentPage;
+                       var toBeSelectedItem = _toolbarItemList[_scroller.HorizontalPageIndex];
+                       var newPage = _itemToItemPage[toBeSelectedItem];
+
+                       if (oldPage != newPage)
+                       {
+                               oldPage?.SendDisappearing();
+                               newPage.SendAppearing();
+
+                               toBeSelectedItem.IsSelected = true;
+                               Element.CurrentPage = newPage;
+                               Element.UpdateFocusTreePolicy();
+                       }
+
+                       _isUpdateByScroller = false;
+               }
+
+               void UpdateBarBackgroundColor(bool initialize)
+               {
+                       if (initialize && Element.BarBackgroundColor.IsDefault)
+                               return;
+
+                       EColor bgColor = Element.BarBackgroundColor.ToNative();
+                       _toolbar.BackgroundColor = bgColor;
+                       foreach (EToolbarItem item in _itemToItemPage.Keys)
+                       {
+                               ApplyBarItemColors(item, BarItemColorType.Background, bgColor);
+                       }
+               }
+
+               void UpdateBarTextColor(bool initialize)
+               {
+                       if (initialize && Element.BarTextColor.IsDefault)
+                               return;
+
+                       foreach (EToolbarItem item in _itemToItemPage.Keys)
+                       {
+                               ApplyBarItemColors(item, BarItemColorType.Text, Element.BarTextColor.ToNative());
+                       }
+               }
+
+               void UpdateSelectedTabColor(bool initialize)
+               {
+                       if (initialize && Element.SelectedTabColor.IsDefault)
+                               return;
+
+                       foreach (EToolbarItem item in _itemToItemPage.Keys)
+                       {
+                               ApplyBarItemColors(item, BarItemColorType.SelectedTab, Element.SelectedTabColor.ToNative());
+                       }
+               }
+
+               void UpdateUnselectedTabColor(bool initialize)
+               {
+                       if (initialize && Element.UnselectedTabColor.IsDefault)
+                               return;
+
+                       foreach (EToolbarItem item in _itemToItemPage.Keys)
+                       {
+                               ApplyBarItemColors(item, BarItemColorType.UnselectedTab, Element.UnselectedTabColor.ToNative());
+                       }
+               }
+
+               void UpdateTitle()
+               {
+                       _toolbar.Text = Element.Title;
+               }
+
+               void UpdateTitle(Page page)
+               {
+                       if (_itemToItemPage.ContainsValue(page))
+                       {
+                               var pair = _itemToItemPage.FirstOrDefault(x => x.Value == page);
+                               pair.Key.SetPartText(null, pair.Value.Title);
+                       }
+               }
+
+               void OnPageTitleChanged(object sender, PropertyChangedEventArgs e)
+               {
+                       if (e.PropertyName == Page.TitleProperty.PropertyName)
+                       {
+                               UpdateTitle(sender as Page);
+                       }
+               }
+
+               void OnElementPagesChanged(object sender, NotifyCollectionChangedEventArgs e)
+               {
+                       switch (e.Action)
+                       {
+                               case NotifyCollectionChangedAction.Add:
+                                       AddToolbarItems(e);
+                                       break;
+                               case NotifyCollectionChangedAction.Remove:
+                                       RemoveToolbarItems(e);
+                                       break;
+                               default:
+                                       ResetToolbarItems();
+                                       break;
+                       }
+                       Element.UpdateFocusTreePolicy();
+               }
+
+               void AddToolbarItems(NotifyCollectionChangedEventArgs e)
+               {
+                       int index = e.NewStartingIndex < 0 ? _toolbar.ItemsCount : e.NewStartingIndex;
+                       foreach (Page item in e.NewItems)
+                       {
+                               AddToolbarItem(item, index++);
+                       }
+               }
+
+               EToolbarItem AddToolbarItem(Page newItem, int index)
+               {
+                       EToolbarItem toolbarItem;
+
+                       // TODO: investigate if we can use the other image source types: stream, font, uri
+
+                       var iconSource = newItem.IconImageSource as FileImageSource;
+                       var icon = iconSource.IsNullOrEmpty() ? null : ResourcePath.GetPath(iconSource);
+
+                       if (index == 0)
+                       {
+                               toolbarItem = _toolbar.Prepend(newItem.Title, icon);
+                       }
+                       else
+                       {
+                               toolbarItem = _toolbar.InsertAfter(_toolbarItemList[index - 1], newItem.Title, icon);
+                       }
+                       _toolbarItemList.Insert(index, toolbarItem);
+                       _itemToItemPage.Add(toolbarItem, newItem);
+
+                       ApplyBarItemColors(toolbarItem, BarItemColorType.Background, Element.BarBackgroundColor.ToNative());
+                       ApplyBarItemColors(toolbarItem, BarItemColorType.Text, Element.BarTextColor.ToNative());
+                       ApplyBarItemColors(toolbarItem, BarItemColorType.SelectedTab, Element.SelectedTabColor.ToNative());
+                       ApplyBarItemColors(toolbarItem, BarItemColorType.UnselectedTab, Element.UnselectedTabColor.ToNative());
+
+                       var childContent = Platform.GetOrCreateRenderer(newItem).NativeView;
+                       _innerBox.PackEnd(childContent);
+
+                       newItem.PropertyChanged += OnPageTitleChanged;
+
+                       return toolbarItem;
+               }
+
+               void RemoveToolbarItems(NotifyCollectionChangedEventArgs e)
+               {
+                       foreach (Page item in e.OldItems)
+                       {
+                               RemoveToolbarItem(item);
+                       }
+               }
+
+               void RemoveToolbarItem(Page oldItem)
+               {
+                       foreach (var pair in _itemToItemPage)
+                       {
+                               if (pair.Value == oldItem)
+                               {
+                                       pair.Value.PropertyChanged -= OnPageTitleChanged;
+                                       _toolbarItemList.Remove(pair.Key);
+                                       _itemToItemPage.Remove(pair.Key);
+                                       pair.Key.Delete();
+                                       return;
+                               }
+                       }
+               }
+
+               void ResetToolbarItems()
+               {
+                       _isResettingToolbarItems = true;
+                       foreach (var pair in _itemToItemPage)
+                       {
+                               pair.Value.PropertyChanged -= OnPageTitleChanged;
+                               pair.Key.Delete();
+                       }
+                       _itemToItemPage.Clear();
+                       _toolbarItemList.Clear();
+
+                       FillToolbarAndContents();
+                       _isResettingToolbarItems = false;
+               }
+
+               void FillToolbarAndContents()
+               {
+                       int index = 0;
+                       //add items to toolbar
+                       foreach (Page child in Element.Children)
+                       {
+                               EToolbarItem toolbarItem = AddToolbarItem(child, index++);
+
+                               if (Element.CurrentPage == child)
+                               {
+                                       //select item on the toolbar and fill content
+                                       toolbarItem.IsSelected = true;
+                               }
+                       }
+               }
+
+               void OnToolbarItemSelected(object sender, EToolbarItemEventArgs e)
+               {
+                       if (_toolbar.SelectedItem == null || _isResettingToolbarItems)
+                               return;
+                       if (_isUpdateByCurrentPage || _isUpdateByScroller)
+                               return;
+                       _isUpdateByToolbar = true;
+
+                       var oldPage = Element.CurrentPage;
+                       var newPage = _itemToItemPage[_toolbar.SelectedItem];
+
+                       if (oldPage != newPage)
+                       {
+                               oldPage?.SendDisappearing();
+                               Element.CurrentPage = newPage;
+                               newPage?.SendAppearing();
+
+                               int index = MultiPage<Page>.GetIndex(newPage);
+                               _scroller.ScrollTo(index, 0, true);
+
+                               Element.UpdateFocusTreePolicy();
+                       }
+                       _isUpdateByToolbar = false;
+               }
+
+               void OnCurrentPageChanged()
+               {
+                       // To update TabIndex order
+                       CustomFocusManager.StartReorderTabIndex();
+
+                       if (_isUpdateByScroller || _isUpdateByToolbar || !_isInitialized)
+                               return;
+
+                       _isUpdateByCurrentPage = true;
+                       Page oldPage = null;
+                       if (_toolbar.SelectedItem != null && _itemToItemPage.ContainsKey(_toolbar.SelectedItem))
+                               oldPage = _itemToItemPage[_toolbar.SelectedItem];
+
+                       oldPage?.SendDisappearing();
+                       Element.CurrentPage?.SendAppearing();
+
+                       int index = MultiPage<Page>.GetIndex(Element.CurrentPage);
+                       _toolbarItemList[index].IsSelected = true;
+                       _scroller.ScrollTo(index, 0, true);
+
+                       Element.UpdateFocusTreePolicy();
+                       _isUpdateByCurrentPage = false;
+               }
+
+               void ApplyBarItemColors(EToolbarItem item, BarItemColorType type, EColor color)
+               {
+                       if (color.IsDefault)
+                       {
+                               ClearBarItemColors(item, type);
+                       }
+                       else
+                       {
+                               switch (type)
+                               {
+                                       case BarItemColorType.Background:
+                                               item.SetPartColor("bg", color);
+                                               break;
+                                       case BarItemColorType.Text:
+                                               if (string.IsNullOrEmpty(item.Icon))
+                                               {
+                                                       item.SetPartColor("text", color);
+                                                       item.SetPartColor("text_pressed", color);
+                                                       item.SetPartColor("text_selected", color);
+                                               }
+                                               else
+                                               {
+                                                       item.SetPartColor("text_under_icon", color);
+                                                       item.SetPartColor("text_under_icon_pressed", color);
+                                                       item.SetPartColor("text_under_icon_selected", color);
+                                               }
+                                               item.SetPartColor("underline", color);
+                                               break;
+                                       case BarItemColorType.SelectedTab:
+                                               if (string.IsNullOrEmpty(item.Icon))
+                                               {
+                                                       item.SetPartColor("text_selected", color);
+                                               }
+                                               else
+                                               {
+                                                       item.SetPartColor("text_under_icon_selected", color);
+                                                       item.SetPartColor("icon_selected", color);
+                                               }
+                                               item.SetPartColor("underline", color);
+                                               break;
+                                       case BarItemColorType.UnselectedTab:
+                                               if (string.IsNullOrEmpty(item.Icon))
+                                               {
+                                                       item.SetPartColor("text", color);
+                                                       item.SetPartColor("text_pressed", color);
+                                               }
+                                               else
+                                               {
+                                                       item.SetPartColor("text_under_icon", color);
+                                                       item.SetPartColor("text_under_icon_pressed", color);
+                                                       item.SetPartColor("icon", color);
+                                                       item.SetPartColor("icon_pressed", color);
+                                               }
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+
+               void ClearBarItemColors(EToolbarItem item, BarItemColorType type)
+               {
+                       switch (type)
+                       {
+                               case BarItemColorType.Background:
+                                       item.DeletePartColor("bg");
+                                       break;
+                               case BarItemColorType.Text:
+                                       if (string.IsNullOrEmpty(item.Icon))
+                                       {
+                                               item.DeletePartColor("text");
+                                               item.DeletePartColor("text_pressed");
+                                               item.DeletePartColor("text_selected");
+                                       }
+                                       else
+                                       {
+                                               item.DeletePartColor("text_under_icon");
+                                               item.DeletePartColor("text_under_icon_pressed");
+                                               item.DeletePartColor("text_under_icon_selected");
+                                       }
+                                       item.DeletePartColor("underline");
+                                       break;
+                               case BarItemColorType.SelectedTab:
+                                       if (string.IsNullOrEmpty(item.Icon))
+                                       {
+                                               item.DeletePartColor("text_selected");
+                                       }
+                                       else
+                                       {
+                                               item.DeletePartColor("text_under_icon_selected");
+                                               item.DeletePartColor("icon_selected");
+                                       }
+                                       item.DeletePartColor("underline");
+                                       break;
+                               case BarItemColorType.UnselectedTab:
+                                       if (string.IsNullOrEmpty(item.Icon))
+                                       {
+                                               item.DeletePartColor("text");
+                                               item.DeletePartColor("text_pressed");
+                                       }
+                                       else
+                                       {
+                                               item.DeletePartColor("text_under_icon");
+                                               item.DeletePartColor("text_under_icon_pressed");
+                                               item.DeletePartColor("icon");
+                                               item.DeletePartColor("icon_pressed");
+                                       }
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       enum BarItemColorType
+       {
+               Background,
+               Text,
+               SelectedTab,
+               UnselectedTab
+       }
+}
diff --git a/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/TimePickerRenderer.cs b/Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Renderers/TimePickerRenderer.cs
new file mode 100644 (file)
index 0000000..35c91d2
--- /dev/null
@@ -0,0 +1,144 @@
+using System;
+using System.Globalization;
+using Xamarin.Forms.Platform.Tizen.Native;
+using WatchDataTimePickerDialog = Xamarin.Forms.Platform.Tizen.Native.Watch.WatchDataTimePickerDialog;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class TimePickerRenderer : ViewRenderer<TimePicker, EditfieldEntry>
+       {
+               //TODO need to add internationalization support
+               const string DialogTitle = "Choose Time";
+               static readonly string s_defaultFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
+
+               TimeSpan _time = DateTime.Now.TimeOfDay;
+               Lazy<IDateTimeDialog> _lazyDialog;
+
+               public TimePickerRenderer()
+               {
+                       RegisterPropertyHandler(TimePicker.FormatProperty, UpdateFormat);
+                       RegisterPropertyHandler(TimePicker.TimeProperty, UpdateTime);
+                       RegisterPropertyHandler(TimePicker.TextColorProperty, UpdateTextColor);
+                       RegisterPropertyHandler(TimePicker.FontAttributesProperty, UpdateFontAttributes);
+                       RegisterPropertyHandler(TimePicker.FontFamilyProperty, UpdateFontFamily);
+                       RegisterPropertyHandler(TimePicker.FontSizeProperty, UpdateFontSize);
+               }
+
+               protected virtual IDateTimeDialog CreateDialog()
+               {
+                       if (Device.Idiom == TargetIdiom.Watch)
+                       {
+                               return new WatchDataTimePickerDialog(Forms.NativeParent);
+                       }
+                       else
+                       {
+                               return new DateTimePickerDialog(Forms.NativeParent);
+                       }
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
+               {
+                       if (Control == null)
+                       {
+                               var entry = new Native.EditfieldEntry(Forms.NativeParent)
+                               {
+                                       IsSingleLine = true,
+                                       HorizontalTextAlignment = Native.TextAlignment.Center,
+                                       InputPanelShowByOnDemand = true,
+                               };
+                               entry.SetVerticalTextAlignment("elm.text", 0.5);
+                               entry.TextBlockFocused += OnTextBlockFocused;
+                               SetNativeControl(entry);
+
+                               _lazyDialog = new Lazy<IDateTimeDialog>(() => {
+                                       var dialog = CreateDialog();
+                                       dialog.Picker.Mode = DateTimePickerMode.Time;
+                                       dialog.Title = DialogTitle;
+                                       dialog.DateTimeChanged += OnDialogTimeChanged;
+                                       return dialog;
+                               });
+                       }
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               if (Control != null)
+                               {
+                                       Control.TextBlockFocused -= OnTextBlockFocused;
+                               }
+                               if (_lazyDialog.IsValueCreated)
+                               {
+                                       _lazyDialog.Value.DateTimeChanged -= OnDialogTimeChanged;
+                                       _lazyDialog.Value.Unrealize();
+                               }
+                       }
+
+                       base.Dispose(disposing);
+               }
+
+               protected override Size MinimumSize()
+               {
+                       return Control.Measure(Control.MinimumWidth, Control.MinimumHeight).ToDP();
+               }
+
+               void OnTextBlockFocused(object o, EventArgs e)
+               {
+                       // For EFL Entry, the event will occur even if it is currently disabled.
+                       // If the problem is resolved, no conditional statement is required.
+                       if (Element.IsEnabled)
+                       {
+                               var dialog = _lazyDialog.Value;
+                               dialog.Picker.Time = Element.Time;
+                               // You need to call Show() after ui thread occupation because of EFL problem.
+                               // Otherwise, the content of the popup will not receive focus.
+                               Device.BeginInvokeOnMainThread(() => dialog.Show());
+                       }
+               }
+
+               void OnDialogTimeChanged(object sender, Native.DateChangedEventArgs dcea)
+               {
+                       Element.SetValueFromRenderer(TimePicker.TimeProperty, dcea.NewDate.TimeOfDay);
+                       UpdateTime();
+               }
+
+               void UpdateFormat()
+               {
+                       UpdateTimeAndFormat();
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.ToNative();
+               }
+
+               void UpdateTime()
+               {
+                       _time = Element.Time;
+                       UpdateTimeAndFormat();
+               }
+
+               void UpdateFontSize()
+               {
+                       Control.FontSize = Element.FontSize;
+               }
+
+               void UpdateFontFamily()
+               {
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               void UpdateFontAttributes()
+               {
+                       Control.FontAttributes = Element.FontAttributes;
+               }
+
+               void UpdateTimeAndFormat()
+               {
+                       // Xamarin using DateTime formatting (https://developer.xamarin.com/api/property/Xamarin.Forms.TimePicker.Format/)
+                       Control.Text = new DateTime(_time.Ticks).ToString(Element.Format ?? s_defaultFormat);
+               }
+       }
+}
index 72f9cc3..5bcb66a 100644 (file)
@@ -41,7 +41,7 @@ namespace Xamarin.Forms.Platform.Tizen
 
                        _title = new Native.Label(Forms.NativeParent)
                        {
-                               FontSize = 23,
+                               FontSize = Device.Idiom == TargetIdiom.TV ? 60 : 23,
                                VerticalTextAlignment = Native.TextAlignment.Center,
                                TextColor = _backgroudColor,
                                FontAttributes = FontAttributes.Bold,
index ba3277f..4f7b3ce 100644 (file)
@@ -72,18 +72,25 @@ namespace Xamarin.Forms.Platform.Tizen
                        Registered.Register(typeof(CarouselPage), () => new CarouselPageRenderer());
                        Registered.Register(typeof(Page), () => new PageRenderer());
                        Registered.Register(typeof(NavigationPage), () => new NavigationPageRenderer());
+                       Registered.Register(typeof(MasterDetailPage), () => new MasterDetailPageRenderer());
+                       Registered.Register(typeof(TabbedPage), () => new TabbedPageRenderer());
                        Registered.Register(typeof(Shell), () => new ShellRenderer());
                        Registered.Register(typeof(Label), () => new LabelRenderer());
                        Registered.Register(typeof(Button), () => new ButtonRenderer());
                        Registered.Register(typeof(Image), () => new ImageRenderer());
                        Registered.Register(typeof(Slider), () => new SliderRenderer());
+                       Registered.Register(typeof(Picker), () => new PickerRenderer());
                        Registered.Register(typeof(Frame), () => new FrameRenderer());
                        Registered.Register(typeof(Stepper), () => new StepperRenderer());
+                       Registered.Register(typeof(DatePicker), () => new DatePickerRenderer());
+                       Registered.Register(typeof(TimePicker), () => new TimePickerRenderer());
                        Registered.Register(typeof(ProgressBar), () => new ProgressBarRenderer());
                        Registered.Register(typeof(Switch), () => new SwitchRenderer());
+                       Registered.Register(typeof(CheckBox), () => new CheckBoxRenderer());
                        Registered.Register(typeof(ListView), () => new ListViewRenderer());
                        Registered.Register(typeof(BoxView), () => new BoxViewRenderer());
                        Registered.Register(typeof(ActivityIndicator), () => new ActivityIndicatorRenderer());
+                       Registered.Register(typeof(SearchBar), () => new SearchBarRenderer());
                        Registered.Register(typeof(Entry), () => new EntryRenderer());
                        Registered.Register(typeof(Editor), () => new EditorRenderer());
                        Registered.Register(typeof(TableView), () => new TableViewRenderer());
index 51e03ad..9550490 100644 (file)
@@ -57,32 +57,32 @@ namespace Xamarin.Forms.Platform.Tizen
                        switch (size)
                        {
                                case NamedSize.Micro:
-                                       pt = 24;
+                                       pt = Device.Idiom == TargetIdiom.TV || Device.Idiom == TargetIdiom.Watch ? 24 : 19;
                                        break;
                                case NamedSize.Small:
-                                       pt = 30;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 26 : (Device.Idiom == TargetIdiom.Watch ? 30 : 22);
                                        break;
                                case NamedSize.Default:
                                case NamedSize.Medium:
-                                       pt = 32;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 28 : (Device.Idiom == TargetIdiom.Watch ? 32 : 25);
                                        break;
                                case NamedSize.Large:
-                                       pt = 36;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 32 : (Device.Idiom == TargetIdiom.Watch ? 36 : 31);
                                        break;
                                case NamedSize.Body:
-                                       pt = 32;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 30 : (Device.Idiom == TargetIdiom.Watch ? 32 : 28);
                                        break;
                                case NamedSize.Caption:
-                                       pt = 24;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 26 : (Device.Idiom == TargetIdiom.Watch ? 24 : 22);
                                        break;
                                case NamedSize.Header:
-                                       pt = 36;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 84 : (Device.Idiom == TargetIdiom.Watch ? 36 : 138);
                                        break;
                                case NamedSize.Subtitle:
-                                       pt = 30;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 30 : (Device.Idiom == TargetIdiom.Watch ? 30 : 28);
                                        break;
                                case NamedSize.Title:
-                                       pt = 36;
+                                       pt = Device.Idiom == TargetIdiom.TV ? 42 : (Device.Idiom == TargetIdiom.Watch ? 36 : 40);
                                        break;
                                default:
                                        throw new ArgumentOutOfRangeException(nameof(size));
index 7a3cd59..d060611 100644 (file)
        {
        }
 
+       internal class _SearchBarRenderer
+       {
+       }
+
        internal class _SwitchRenderer
        {
        }
 
+       internal class _DatePickerRenderer
+       {
+       }
+
+       internal class _TimePickerRenderer
+       {
+       }
+
+       internal class _PickerRenderer
+       {
+       }
+
        internal class _StepperRenderer
        {
        }
        {
        }
 
+       internal class _CheckBoxRenderer
+       {
+       }
+
        internal class _IndicatorViewRenderer
        {
        }
        {
        }
 
+       internal class _TabbedPageRenderer
+       {
+       }
+
        internal class _NavigationPageRenderer
        {
        }
        {
        }
 
+       internal class _MasterDetailPageRenderer
+       {
+       }
+
        internal class _SwipeViewRenderer
        {
        }
-}
+}
\ No newline at end of file