diff --git a/Xamarin.Forms.Controls/ControlGalleryPages/EntryReturnTypeGalleryPage.cs b/Xamarin.Forms.Controls/ControlGalleryPages/EntryReturnTypeGalleryPage.cs new file mode 100644 index 000000000..01611ee91 --- /dev/null +++ b/Xamarin.Forms.Controls/ControlGalleryPages/EntryReturnTypeGalleryPage.cs @@ -0,0 +1,90 @@ +using System; +using System.Threading.Tasks; + +namespace Xamarin.Forms.Controls +{ + public class EntryReturnTypeGalleryPage: ContentPage + { + Picker picker; + Entry returnTypeEntry; + Label lblCompleted; + public EntryReturnTypeGalleryPage() + { + BackgroundColor = Color.LightBlue; + var layout = new StackLayout + { + VerticalOptions = LayoutOptions.StartAndExpand + }; + lblCompleted = new Label + { + HorizontalOptions = LayoutOptions.FillAndExpand + }; + + picker = new Picker + { + HorizontalOptions = LayoutOptions.FillAndExpand + }; + picker.Items.Add(ReturnType.Done.ToString()); + picker.Items.Add(ReturnType.Go.ToString()); + picker.Items.Add(ReturnType.Next.ToString()); + picker.Items.Add(ReturnType.Search.ToString()); + picker.Items.Add(ReturnType.Send.ToString()); + picker.Items.Add(ReturnType.Default.ToString()); + + returnTypeEntry = new Entry + { + HorizontalOptions = LayoutOptions.Fill, + Placeholder = $"Entry with {ReturnType.Go}", + ReturnCommand = new Command(obj => + { + lblCompleted.Text = "Completed Fired"; + }), + ReturnCommandParameter = "hello titles", + AutomationId = "returnTypeEntry" + }; + + returnTypeEntry.PropertyChanged += (s, e) => + { + if (e.PropertyName == Entry.ReturnTypeProperty.PropertyName) + { + returnTypeEntry.Placeholder = $"Entry with {returnTypeEntry.ReturnType}"; + } + }; + + picker.SelectedIndexChanged += (s, e) => + { + if (picker.SelectedItem.ToString() == ReturnType.Done.ToString()) + { + returnTypeEntry.ReturnType = ReturnType.Done; + } + if (picker.SelectedItem.ToString() == ReturnType.Go.ToString()) + { + returnTypeEntry.ReturnType = ReturnType.Go; + } + if (picker.SelectedItem.ToString() == ReturnType.Next.ToString()) + { + returnTypeEntry.ReturnType = ReturnType.Next; + } + if (picker.SelectedItem.ToString() == ReturnType.Search.ToString()) + { + returnTypeEntry.ReturnType = ReturnType.Search; + } + if (picker.SelectedItem.ToString() == ReturnType.Send.ToString()) + { + returnTypeEntry.ReturnType = ReturnType.Send; + } + if (picker.SelectedItem.ToString() == ReturnType.Default.ToString()) + { + returnTypeEntry.ReturnType = ReturnType.Default; + } + }; + + layout.Children.Add(returnTypeEntry); + layout.Children.Add(picker); + layout.Children.Add(lblCompleted); + picker.SelectedIndex = 0; + + Content = layout; + } + } +} diff --git a/Xamarin.Forms.Controls/CoreGallery.cs b/Xamarin.Forms.Controls/CoreGallery.cs index 4eabd7b5c..d160a9d8e 100644 --- a/Xamarin.Forms.Controls/CoreGallery.cs +++ b/Xamarin.Forms.Controls/CoreGallery.cs @@ -246,6 +246,7 @@ namespace Xamarin.Forms.Controls List _pages = new List { new GalleryPageFactory(() => new Issues.PerformanceGallery(), "Performance"), + new GalleryPageFactory(() => new EntryReturnTypeGalleryPage(), "Entry ReturnType "), new GalleryPageFactory(() => new VisualStateManagerGallery(), "VisualStateManager Gallery"), new GalleryPageFactory(() => new FlowDirectionGalleryLandingPage(), "FlowDirection"), new GalleryPageFactory(() => new AutomationPropertiesGallery(), "Accessibility"), diff --git a/Xamarin.Forms.Core.UnitTests/EntryUnitTests.cs b/Xamarin.Forms.Core.UnitTests/EntryUnitTests.cs index 83f71b9a3..2c32dc0b0 100644 --- a/Xamarin.Forms.Core.UnitTests/EntryUnitTests.cs +++ b/Xamarin.Forms.Core.UnitTests/EntryUnitTests.cs @@ -51,5 +51,50 @@ namespace Xamarin.Forms.Core.UnitTests Assert.AreEqual (initial, oldValue); Assert.AreEqual (final, newValue); } + + [TestCase(true)] + [TestCase(false)] + public void ReturnTypeCommand(bool isEnabled) + { + var entry = new Entry() + { + IsEnabled = isEnabled, + }; + + bool result = false; + + var bindingContext = new + { + Command = new Command(() => { result = true; }, () => true) + }; + + entry.SetBinding(Entry.ReturnCommandProperty, "Command"); + entry.BindingContext = bindingContext; + + entry.SendCompleted(); + + Assert.True(result == isEnabled ? true : false); + } + + [TestCase(true)] + [TestCase(false)] + public void ReturnTypeCommandNullTestIsEnabled(bool isEnabled) + { + var entry = new Entry() + { + IsEnabled = isEnabled, + }; + + bool result = false; + + entry.SetBinding(Entry.ReturnCommandProperty, "Command"); + entry.BindingContext = null; + entry.Completed += (s, e) => { + result = true; + }; + entry.SendCompleted(); + + Assert.True(result == isEnabled ? true : false); + } } } diff --git a/Xamarin.Forms.Core/Entry.cs b/Xamarin.Forms.Core/Entry.cs index 73a1acd7c..8936a3fec 100644 --- a/Xamarin.Forms.Core/Entry.cs +++ b/Xamarin.Forms.Core/Entry.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.Windows.Input; using Xamarin.Forms.Internals; using Xamarin.Forms.Platform; @@ -8,6 +9,12 @@ namespace Xamarin.Forms [RenderWith(typeof(_EntryRenderer))] public class Entry : InputView, IFontElement, ITextElement, ITextAlignmentElement, IEntryController, IElementConfiguration { + public static readonly BindableProperty ReturnTypeProperty = BindableProperty.Create(nameof(ReturnType), typeof(ReturnType), typeof(Entry), ReturnType.Default); + + public static readonly BindableProperty ReturnCommandProperty = BindableProperty.Create(nameof(ReturnCommand), typeof(ICommand), typeof(Entry), default(ICommand)); + + public static readonly BindableProperty ReturnCommandParameterProperty = BindableProperty.Create(nameof(ReturnCommandParameter), typeof(object), typeof(Entry), default(object)); + public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create("Placeholder", typeof(string), typeof(Entry), default(string)); public static readonly BindableProperty IsPasswordProperty = BindableProperty.Create("IsPassword", typeof(bool), typeof(Entry), default(bool)); @@ -88,6 +95,24 @@ namespace Xamarin.Forms set { SetValue(FontSizeProperty, value); } } + public ReturnType ReturnType + { + get => (ReturnType)GetValue(ReturnTypeProperty); + set => SetValue(ReturnTypeProperty, value); + } + + public ICommand ReturnCommand + { + get => (ICommand)GetValue(ReturnCommandProperty); + set => SetValue(ReturnCommandProperty, value); + } + + public object ReturnCommandParameter + { + get => GetValue(ReturnCommandParameterProperty); + set => SetValue(ReturnCommandParameterProperty, value); + } + double IFontElement.FontSizeDefaultValueCreator() => Device.GetNamedSize(NamedSize.Default, (Entry)this); @@ -102,7 +127,7 @@ namespace Xamarin.Forms void IFontElement.OnFontChanged(Font oldValue, Font newValue) => InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged); - + public event EventHandler Completed; public event EventHandler TextChanged; @@ -110,7 +135,15 @@ namespace Xamarin.Forms [EditorBrowsable(EditorBrowsableState.Never)] public void SendCompleted() { - Completed?.Invoke(this, EventArgs.Empty); + if (IsEnabled) + { + Completed?.Invoke(this, EventArgs.Empty); + + if (ReturnCommand != null && ReturnCommand.CanExecute(ReturnCommandParameter)) + { + ReturnCommand.Execute(ReturnCommandParameter); + } + } } static void OnTextChanged(BindableObject bindable, object oldValue, object newValue) diff --git a/Xamarin.Forms.Core/ReturnType.cs b/Xamarin.Forms.Core/ReturnType.cs new file mode 100644 index 000000000..5f68acac1 --- /dev/null +++ b/Xamarin.Forms.Core/ReturnType.cs @@ -0,0 +1,14 @@ +using System; + +namespace Xamarin.Forms +{ + public enum ReturnType + { + Default, + Done, + Go, + Next, + Search, + Send, + } +} diff --git a/Xamarin.Forms.Platform.Android/Extensions/EntryRendererExtensions.cs b/Xamarin.Forms.Platform.Android/Extensions/EntryRendererExtensions.cs index 58aebd4ca..c2882a38d 100644 --- a/Xamarin.Forms.Platform.Android/Extensions/EntryRendererExtensions.cs +++ b/Xamarin.Forms.Platform.Android/Extensions/EntryRendererExtensions.cs @@ -4,6 +4,28 @@ namespace Xamarin.Forms.Platform.Android { internal static class EntryRendererExtensions { + + internal static ImeAction ToAndroidImeAction(this ReturnType returnType) + { + switch (returnType) + { + case ReturnType.Go: + return ImeAction.Go; + case ReturnType.Next: + return ImeAction.Next; + case ReturnType.Send: + return ImeAction.Send; + case ReturnType.Search: + return ImeAction.Search; + case ReturnType.Done: + return ImeAction.Done; + case ReturnType.Default: + return ImeAction.Done; + default: + throw new System.NotImplementedException($"ReturnType {returnType} not supported"); + } + } + public static ImeAction ToAndroidImeOptions(this PlatformConfiguration.AndroidSpecific.ImeFlags flags) { switch (flags) diff --git a/Xamarin.Forms.Platform.Android/Renderers/EntryRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/EntryRenderer.cs index 9ca94f9ce..28517b789 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/EntryRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/EntryRenderer.cs @@ -19,7 +19,6 @@ namespace Xamarin.Forms.Platform.Android TextColorSwitcher _hintColorSwitcher; TextColorSwitcher _textColorSwitcher; bool _disposed; - //global::Android.Views.InputMethods.ImeFlags _defaultInputImeFlag; ImeAction _currentInputImeFlag; public EntryRenderer(Context context) : base(context) @@ -98,6 +97,7 @@ namespace Xamarin.Forms.Platform.Android UpdatePlaceholderColor(); UpdateMaxLength(); UpdateImeOptions(); + UpdateReturnType(); } protected override void Dispose(bool disposing) @@ -160,6 +160,8 @@ namespace Xamarin.Forms.Platform.Android UpdateMaxLength(); else if (e.PropertyName == PlatformConfiguration.AndroidSpecific.Entry.ImeOptionsProperty.PropertyName) UpdateImeOptions(); + else if (e.PropertyName == Entry.ReturnTypeProperty.PropertyName) + UpdateReturnType(); base.OnElementPropertyChanged(sender, e); } @@ -255,5 +257,14 @@ namespace Xamarin.Forms.Platform.Android if (currentControlText.Length > Element.MaxLength) Control.Text = currentControlText.Substring(0, Element.MaxLength); } + + void UpdateReturnType() + { + if (Control == null || Element == null) + return; + + Control.ImeOptions = Element.ReturnType.ToAndroidImeAction(); + _currentInputImeFlag = Control.ImeOptions; + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/EntryExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/EntryExtensions.cs new file mode 100644 index 000000000..71b0842be --- /dev/null +++ b/Xamarin.Forms.Platform.Tizen/Extensions/EntryExtensions.cs @@ -0,0 +1,29 @@ +using ElmSharp; + +namespace Xamarin.Forms.Platform.Tizen +{ + internal static class EntryExtensions + { + internal static InputPanelReturnKeyType ToInputPanelReturnKeyType(this ReturnType returnType) + { + switch (returnType) + { + case ReturnType.Go: + return InputPanelReturnKeyType.Go; + case ReturnType.Next: + return InputPanelReturnKeyType.Next; + case ReturnType.Send: + return InputPanelReturnKeyType.Send; + case ReturnType.Search: + return InputPanelReturnKeyType.Search; + case ReturnType.Done: + return InputPanelReturnKeyType.Done; + case ReturnType.Default: + return InputPanelReturnKeyType.Default; + default: + throw new System.NotImplementedException($"ReturnType {returnType} not supported"); + } + } + + } +} diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs index 41146e550..a2f19b377 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs @@ -1,5 +1,4 @@ using System; -using ElmSharp; using Specific = Xamarin.Forms.PlatformConfiguration.TizenSpecific.Entry; namespace Xamarin.Forms.Platform.Tizen @@ -19,6 +18,7 @@ namespace Xamarin.Forms.Platform.Tizen RegisterPropertyHandler(Entry.PlaceholderProperty, UpdatePlaceholder); RegisterPropertyHandler(Entry.PlaceholderColorProperty, UpdatePlaceholderColor); RegisterPropertyHandler(InputView.MaxLengthProperty, UpdateMaxLength); + RegisterPropertyHandler(Entry.ReturnTypeProperty, UpdateReturnType); if (TizenPlatformServices.AppDomain.IsTizenSpecificAvailable) { RegisterPropertyHandler("FontWeight", UpdateFontWeight); @@ -146,5 +146,10 @@ namespace Xamarin.Forms.Platform.Tizen return null; } + + void UpdateReturnType() + { + Control.SetInputPanelReturnKeyType(Element.ReturnType.ToInputPanelReturnKeyType()); + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/EntryRenderer.cs b/Xamarin.Forms.Platform.UAP/EntryRenderer.cs index abb03f0b8..bf1941510 100644 --- a/Xamarin.Forms.Platform.UAP/EntryRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/EntryRenderer.cs @@ -49,6 +49,7 @@ namespace Xamarin.Forms.Platform.UWP UpdatePlaceholderColor(); UpdateMaxLength(); UpdateDetectReadingOrderFromContent(); + UpdateReturnType(); } } @@ -95,6 +96,8 @@ namespace Xamarin.Forms.Platform.UWP UpdateMaxLength(); else if (e.PropertyName == Specifics.DetectReadingOrderFromContentProperty.PropertyName) UpdateDetectReadingOrderFromContent(); + else if (e.PropertyName == Entry.ReturnTypeProperty.PropertyName) + UpdateReturnType(); } protected override void UpdateBackgroundColor() @@ -249,5 +252,13 @@ namespace Xamarin.Forms.Platform.UWP } } } + + void UpdateReturnType() + { + if (Control == null || Element == null) + return; + + Control.InputScope = Element.ReturnType.ToInputScope(); + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/Extensions.cs b/Xamarin.Forms.Platform.UAP/Extensions.cs index f33dd8987..c65dfda74 100644 --- a/Xamarin.Forms.Platform.UAP/Extensions.cs +++ b/Xamarin.Forms.Platform.UAP/Extensions.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using Windows.Foundation; using Windows.UI.Xaml; +using Windows.UI.Xaml.Input; namespace Xamarin.Forms.Platform.UWP { @@ -26,5 +27,37 @@ namespace Xamarin.Forms.Platform.UWP { self.SetBinding(property, new Windows.UI.Xaml.Data.Binding { Path = new PropertyPath(path), Converter = converter }); } + + internal static InputScopeNameValue GetKeyboardButtonType(this ReturnType returnType) + { + switch (returnType) + { + case ReturnType.Default: + case ReturnType.Done: + case ReturnType.Go: + case ReturnType.Next: + case ReturnType.Send: + return InputScopeNameValue.Default; + case ReturnType.Search: + return InputScopeNameValue.Search; + default: + throw new System.NotImplementedException($"ReturnType {returnType} not supported"); + } + } + + internal static InputScope ToInputScope(this ReturnType returnType) + { + var scopeName = new InputScopeName() + { + NameValue = GetKeyboardButtonType(returnType) + }; + + var inputScope = new InputScope + { + Names = { scopeName } + }; + + return inputScope; + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Extensions/Extensions.cs b/Xamarin.Forms.Platform.iOS/Extensions/Extensions.cs index 49e486795..1baeff47d 100644 --- a/Xamarin.Forms.Platform.iOS/Extensions/Extensions.cs +++ b/Xamarin.Forms.Platform.iOS/Extensions/Extensions.cs @@ -68,6 +68,27 @@ namespace Xamarin.Forms.Platform.iOS } } + internal static UIReturnKeyType ToUIReturnKeyType(this ReturnType returnType) + { + switch (returnType) + { + case ReturnType.Go: + return UIReturnKeyType.Go; + case ReturnType.Next: + return UIReturnKeyType.Next; + case ReturnType.Send: + return UIReturnKeyType.Send; + case ReturnType.Search: + return UIReturnKeyType.Search; + case ReturnType.Done: + return UIReturnKeyType.Done; + case ReturnType.Default: + return UIReturnKeyType.Default; + default: + throw new System.NotImplementedException($"ReturnType {returnType} not supported"); + } + } + internal static DeviceOrientation ToDeviceOrientation(this UIDeviceOrientation orientation) { switch (orientation) diff --git a/Xamarin.Forms.Platform.iOS/Renderers/EntryRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/EntryRenderer.cs index b5673ccca..27809aa2f 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/EntryRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/EntryRenderer.cs @@ -108,6 +108,7 @@ namespace Xamarin.Forms.Platform.iOS UpdateAlignment(); UpdateAdjustsFontSizeToFitWidth(); UpdateMaxLength(); + UpdateReturnType(); } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) @@ -143,6 +144,8 @@ namespace Xamarin.Forms.Platform.iOS UpdateAlignment(); else if (e.PropertyName == Xamarin.Forms.InputView.MaxLengthProperty.PropertyName) UpdateMaxLength(); + else if (e.PropertyName == Entry.ReturnTypeProperty.PropertyName) + UpdateReturnType(); base.OnElementPropertyChanged(sender, e); } @@ -278,5 +281,13 @@ namespace Xamarin.Forms.Platform.iOS var newLength = textField?.Text?.Length + replacementString.Length - range.Length; return newLength <= Element?.MaxLength; } + + void UpdateReturnType() + { + if (Control == null || Element == null) + return; + Control.ReturnKeyType = Element.ReturnType.ToUIReturnKeyType(); + } + } } diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/Entry.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/Entry.xml index aa686c653..2689041a1 100644 --- a/docs/Xamarin.Forms.Core/Xamarin.Forms/Entry.xml +++ b/docs/Xamarin.Forms.Core/Xamarin.Forms/Entry.xml @@ -417,6 +417,99 @@ View CreateLoginForm () + + + + Property + + 2.0.0.0 + + + System.Windows.Input.ICommand + + + To be added. + To be added. + To be added. + + + + + + Property + + 2.0.0.0 + + + System.Object + + + To be added. + To be added. + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.BindableProperty + + + To be added. + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.BindableProperty + + + To be added. + To be added. + + + + + + Property + + 2.0.0.0 + + + Xamarin.Forms.ReturnType + + + To be added. + To be added. + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.BindableProperty + + + To be added. + To be added. + + diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/ReturnType.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/ReturnType.xml new file mode 100644 index 000000000..270355e42 --- /dev/null +++ b/docs/Xamarin.Forms.Core/Xamarin.Forms/ReturnType.xml @@ -0,0 +1,101 @@ + + + + + Xamarin.Forms.Core + 2.0.0.0 + + + System.Enum + + + To be added. + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.ReturnType + + + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.ReturnType + + + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.ReturnType + + + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.ReturnType + + + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.ReturnType + + + To be added. + + + + + + Field + + 2.0.0.0 + + + Xamarin.Forms.ReturnType + + + To be added. + + + + diff --git a/docs/Xamarin.Forms.Core/index.xml b/docs/Xamarin.Forms.Core/index.xml index 6af094f85..566c9a588 100644 --- a/docs/Xamarin.Forms.Core/index.xml +++ b/docs/Xamarin.Forms.Core/index.xml @@ -369,6 +369,7 @@ +