Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Entry: Read-only Entry and Editor #1972

Merged
merged 25 commits into from Jan 10, 2019
Merged
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f4efb90
InputView BindableProperty IsReadOnly
almirvuk Aug 11, 2018
8a0efac
Android Editor and Entry setup
almirvuk Aug 11, 2018
c95b5b4
MacOS Editor and Entry setup
almirvuk Aug 11, 2018
63428f3
Tizen Editor and Entry setup
almirvuk Aug 11, 2018
3911b45
UAP Editor and Entry setup
almirvuk Aug 11, 2018
613704f
WPF Editor and Entry setup
almirvuk Aug 11, 2018
c36ea78
iOS Editor and Entry setup
almirvuk Aug 11, 2018
2d83e01
Issue1678 - TestContentPage added
almirvuk Aug 12, 2018
40423ee
Tests added
almirvuk Aug 12, 2018
ffaa298
Tizen Editor and Entry fix
almirvuk Aug 19, 2018
c1eb7fd
UI Test fix
almirvuk Aug 19, 2018
d7360bc
Android fix for Entry and Editor.
almirvuk Sep 23, 2018
2339be5
Unit Tests fix.
almirvuk Oct 3, 2018
8e71c91
Android Renderer first try.
almirvuk Oct 29, 2018
0b6a421
MacOS Entry renderer small fix.
almirvuk Nov 14, 2018
eddeab2
UpdateEditable fix.
almirvuk Nov 18, 2018
6734fdb
Android Entry and Editor reduced number of calls to BP.
almirvuk Nov 18, 2018
9855fb9
Merge branch 'master' into feature/1678-read-only-entry
rmarinho Nov 30, 2018
55d52eb
fix TestAttributes conflicts
PureWeen Dec 20, 2018
d83a47e
Remove keyboard
PureWeen Dec 20, 2018
89a9125
Merge branch 'master' into feature/1678-read-only-entry
PureWeen Dec 20, 2018
1b3509e
Merge branch 'master' into pr/1972
PureWeen Jan 8, 2019
571764e
[macOS] relinquish first responder
PureWeen Jan 8, 2019
4b21b84
[Android] remove call to UpdateCursorSelection
PureWeen Jan 8, 2019
e314ef7
[UWP] fix tabs
PureWeen Jan 8, 2019
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+228 −16
Diff settings

Always

Just for now

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;

using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 1678, "[Enhancement] Entry: Read-only entry", PlatformAffected.All)]
public class Issue1678
: TestContentPage
{
protected override void Init()
{
var entryText = "Entry Lorem Ipsum";
var editorText = "Editor Lorem Ipsum";

var entryDefaults = new Entry { Text = entryText };
var editorDefaults = new Editor { Text = editorText };
var entryReadOnly = new Entry { Text = entryText, IsReadOnly = true };
var editorReadOnly = new Editor { Text = editorText, IsReadOnly = true };
var entryToggleable = new Entry { Text = entryText };
var editorToggleable = new Editor { Text = editorText };

var toggle = new Switch { IsToggled = false };

var stackLayout = new StackLayout();
stackLayout.Children.Add(new Label { Text = "Defaults" });
stackLayout.Children.Add(entryDefaults);
stackLayout.Children.Add(editorDefaults);
stackLayout.Children.Add(new Label { Text = "Read Only" });
stackLayout.Children.Add(entryReadOnly);
stackLayout.Children.Add(editorReadOnly);
stackLayout.Children.Add(new Label { Text = "Toggleable is read only" });
stackLayout.Children.Add(entryToggleable);
stackLayout.Children.Add(editorToggleable);
stackLayout.Children.Add(toggle);

toggle.Toggled += (_, b) =>
{
entryToggleable.IsReadOnly = b.Value;
editorToggleable.IsReadOnly = b.Value;
};

stackLayout.Padding = new Thickness(0, 20, 0, 0);
Content = stackLayout;
}
}
}
@@ -35,6 +35,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue3788.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1724.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3524.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1678.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2004.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3333.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2338.cs" />
@@ -40,6 +40,8 @@ protected override void Build(StackLayout stackLayout)

var maxLengthContainer = new ViewContainer<Editor>(Test.InputView.MaxLength, new Editor { MaxLength = 3 });

var readOnlyContainer = new ViewContainer<Editor>(Test.Editor.IsReadOnly, new Editor { Text = "This is read-only Editor", IsReadOnly = true });

Add(completedContainer);
Add(textContainer);
Add(textChangedContainer);
@@ -54,6 +56,7 @@ protected override void Build(StackLayout stackLayout)
Add(textColorDisabledContainer);
Add(keyboardContainer);
Add(maxLengthContainer);
Add(readOnlyContainer);
}
}
}
@@ -66,6 +66,7 @@ protected override void Build (StackLayout stackLayout)

var maxLengthContainer = new ViewContainer<Entry>(Test.InputView.MaxLength, new Entry { MaxLength = 3 });

var readOnlyContainer = new ViewContainer<Entry>(Test.Entry.IsReadOnly, new Entry { Text = "This is read-only Entry", IsReadOnly = true });
var isPasswordInputScopeContainer = new ViewContainer<Entry>(Test.Entry.IsPasswordNumeric, new Entry { Keyboard = Keyboard.Numeric });
var switchPasswordButton = new Button
{
@@ -110,6 +111,7 @@ protected override void Build (StackLayout stackLayout)
Add (placeholderColorDisabledContainer);
Add (passwordColorContainer);
Add (maxLengthContainer);
Add (readOnlyContainer);
Add (isPasswordInputScopeContainer);
}
}
@@ -30,5 +30,19 @@ public void EditorTextChangedEventArgs (string initialText, string finalText)
Assert.AreEqual (initialText, oldText);
Assert.AreEqual (finalText, newText);
}

[TestCase(true)]
public void IsReadOnlyTest(bool isReadOnly)
{
Editor editor = new Editor();
editor.SetValue(InputView.IsReadOnlyProperty, isReadOnly);
Assert.AreEqual(isReadOnly, editor.IsReadOnly);
}
[Test]
public void IsReadOnlyDefaultValueTest()
{
Editor editor = new Editor();
Assert.AreEqual(editor.IsReadOnly, false);
}
}
}
@@ -154,5 +154,20 @@ public void ReturnTypeCommandNullTestIsEnabled(bool isEnabled)

Assert.True(result == isEnabled ? true : false);
}

[TestCase(true)]
public void IsReadOnlyTest(bool isReadOnly)
{
Entry entry = new Entry();
entry.SetValue(InputView.IsReadOnlyProperty, isReadOnly);
Assert.AreEqual(isReadOnly, entry.IsReadOnly);
}

[Test]
public void IsReadOnlyDefaultValueTest()
{
Entry entry = new Entry();
Assert.AreEqual(entry.IsReadOnly, false);
}
}
}
@@ -151,7 +151,9 @@ public override INotifyPropertyChanged CreateView ()
new PropertyTestCase<TapGestureRecognizer, int> ("NumberOfTapsRequired", t => t.NumberOfTapsRequired, (t, o) => t.NumberOfTapsRequired = o, () => 1, 3),
new PropertyTestCase<TapGestureRecognizer, object> ("CommandParameter", t => t.CommandParameter, (t, o) => t.CommandParameter = o, () => null, "Test"),
new PropertyTestCase<TapGestureRecognizer, ICommand> ("Command", t => t.Command, (t, o) => t.Command = o, () => null, new Command(()=>{})),
new PropertyTestCase<MasterDetailPage, bool> ("IsGestureEnabled", md => md.IsGestureEnabled, (md, v) => md.IsGestureEnabled = v, () => true, false)
new PropertyTestCase<MasterDetailPage, bool> ("IsGestureEnabled", md => md.IsGestureEnabled, (md, v) => md.IsGestureEnabled = v, () => true, false),
new PropertyTestCase<Entry, bool> ("IsReadOnly", v => v.IsReadOnly, (v, o) => v.IsReadOnly = o, () => false, true),
new PropertyTestCase<Editor, bool> ("IsReadOnly", v => v.IsReadOnly, (v, o) => v.IsReadOnly = o, () => false, true)
};
#pragma warning restore 0414

@@ -8,6 +8,8 @@ public class InputView : View

public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create(nameof(MaxLength), typeof(int), typeof(int), int.MaxValue);

public static readonly BindableProperty IsReadOnlyProperty = BindableProperty.Create(nameof(IsReadOnly), typeof(bool), typeof(InputView), false);

public int MaxLength
{
get { return (int)GetValue(MaxLengthProperty); }
@@ -29,5 +31,11 @@ public bool IsSpellCheckEnabled
get { return (bool)GetValue(IsSpellCheckEnabledProperty); }
set { SetValue(IsSpellCheckEnabledProperty, value); }
}

public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
}
}
@@ -507,6 +507,8 @@ public enum Editor
FontAttributes,
FontFamily,
FontSize,
MaxLength,
IsReadOnly
}

public enum Entry
@@ -530,6 +532,8 @@ public enum Entry
TextDisabledColor,
PlaceholderDisabledColor,
PasswordColor,
MaxLength,
IsReadOnly,
IsPasswordNumeric
}

@@ -90,6 +90,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
UpdateMaxLength();
UpdatePlaceholderColor();
UpdatePlaceholderText();
UpdateIsReadOnly();
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -116,6 +117,8 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
UpdatePlaceholderText();
else if (e.PropertyName == Editor.PlaceholderColorProperty.PropertyName)
UpdatePlaceholderColor();
else if (e.PropertyName == InputView.IsReadOnlyProperty.PropertyName)
UpdateIsReadOnly();

base.OnElementPropertyChanged(sender, e);
}
@@ -247,5 +250,14 @@ void UpdateMaxLength()
if (currentControlText.Length > Element.MaxLength)
Control.Text = currentControlText.Substring(0, Element.MaxLength);
}

void UpdateIsReadOnly()
{
bool isReadOnly = !Element.IsReadOnly;

Control.FocusableInTouchMode = isReadOnly;
Control.Focusable = isReadOnly;
Control.SetCursorVisible(isReadOnly);
}
}
}
@@ -109,6 +109,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
UpdateMaxLength();
UpdateImeOptions();
UpdateReturnType();
UpdateIsReadOnly();

if (_cursorPositionChangePending || _selectionLengthChangePending)
UpdateCursorSelection();
@@ -183,6 +184,8 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
UpdateCursorSelection();
else if (e.PropertyName == Entry.CursorPositionProperty.PropertyName)
UpdateCursorSelection();
else if (e.PropertyName == InputView.IsReadOnlyProperty.PropertyName)
UpdateIsReadOnly();

base.OnElementPropertyChanged(sender, e);
}
@@ -332,7 +335,7 @@ void UpdateCursorSelection()
if (_nativeSelectionIsUpdating || Control == null || Element == null)
return;

if (Control.RequestFocus())
if (!Element.IsReadOnly && Control.RequestFocus())
{
try
{
@@ -414,5 +417,14 @@ void SetSelectionLengthFromRenderer(int selectionLength)
_nativeSelectionIsUpdating = false;
}
}

void UpdateIsReadOnly()
{
bool isReadOnly = !Element.IsReadOnly;

Control.FocusableInTouchMode = isReadOnly;
Control.Focusable = isReadOnly;
Control.SetCursorVisible(isReadOnly);
}
}
}
}
@@ -42,6 +42,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
UpdateTextColor();
UpdateEditable();
UpdateMaxLength();
UpdateIsReadOnly();
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -62,6 +63,8 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
UpdateFont();
else if (e.PropertyName == InputView.MaxLengthProperty.PropertyName)
UpdateMaxLength();
else if (e.PropertyName == Xamarin.Forms.InputView.IsReadOnlyProperty.PropertyName)
UpdateIsReadOnly();
}

protected override void SetBackgroundColor(Color color)
@@ -148,5 +151,12 @@ void UpdateMaxLength()
if (currentControlText.Length > Element?.MaxLength)
Control.StringValue = currentControlText.Substring(0, Element.MaxLength);
}

void UpdateIsReadOnly()
{
Control.Editable = !Element.IsReadOnly;

This comment has been minimized.

Copy link
@PureWeen

PureWeen Aug 14, 2018

Contributor

MacOS/iOS/gtk looks to have a quirk where if the field is the first responder when it goes readonly the field remains editable until it's no longer the first responder

a62168f1-b724-4b89-9fb1-489c46076e6c

UWP nothing happens with these focuses
Android the keyboard shows up which is a little awkward

Another way to see this is to add focus calls here.

toggle.Toggled += (_, b) =>
			{
				entryToggleable.IsReadOnly = b.Value;
				editorToggleable.IsReadOnly = b.Value;

				entryToggleable.Focus();
				editorToggleable.Focus();
			};

I'm wondering if ShouldBeginEditing would be a more thorough way to go?
https://stackoverflow.com/questions/7949071/iphone-ipad-how-to-make-uitextfield-readonly-but-not-disabled

Wire that up and return false if Element.IsReadOnly

This comment has been minimized.

Copy link
@almirvuk

almirvuk Aug 15, 2018

Author Contributor

Thanks for suggestion, I will try :)

This comment has been minimized.

Copy link
@PureWeen

PureWeen Nov 16, 2018

Contributor

This comments I made earlier on this look to still apply

if (Element.IsReadOnly && Control.Window?.FirstResponder == Control.CurrentEditor)
Control.Window?.MakeFirstResponder(null);

This comment has been minimized.

Copy link
@PureWeen

PureWeen Jan 8, 2019

Contributor

@rmarinho I added this code on MacOS to fix #4834 so please re-review macos

}
}
}
@@ -132,6 +132,8 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
UpdateAlignment();
else if (e.PropertyName == InputView.MaxLengthProperty.PropertyName)
UpdateMaxLength();
else if (e.PropertyName == Xamarin.Forms.InputView.IsReadOnlyProperty.PropertyName)
UpdateIsReadOnly();

base.OnElementPropertyChanged(sender, e);
}
@@ -201,7 +203,8 @@ void UpdateControl()
UpdateFont();
UpdateAlignment();
UpdateMaxLength();
}
UpdateIsReadOnly();
}

void TextFieldFocusChanged(object sender, BoolEventArgs e)
{
@@ -289,5 +292,13 @@ void UpdateMaxLength()
if (currentControlText.Length > Element?.MaxLength)
Control.StringValue = currentControlText.Substring(0, Element.MaxLength);
}


void UpdateIsReadOnly()
{
Control.Editable = !Element.IsReadOnly;
if (Element.IsReadOnly && Control.Window?.FirstResponder == Control.CurrentEditor)
Control.Window?.MakeFirstResponder(null);

This comment has been minimized.

Copy link
@PureWeen

PureWeen Jan 8, 2019

Contributor

@rmarinho I added this code on MacOS to fix #4834 so please re-review macos

This comment has been minimized.

Copy link
@rmarinho
}
}
}
@@ -16,6 +16,7 @@ public EditorRenderer()
RegisterPropertyHandler(InputView.IsSpellCheckEnabledProperty, UpdateIsSpellCheckEnabled);
RegisterPropertyHandler(Editor.PlaceholderProperty, UpdatePlaceholder);
RegisterPropertyHandler(Editor.PlaceholderColorProperty, UpdatePlaceholderColor);
RegisterPropertyHandler(InputView.IsReadOnlyProperty, UpdateIsReadOnly);
}

protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
@@ -153,5 +154,10 @@ string MaxLengthFilter(ElmSharp.Entry entry, string s)

return null;
}

void UpdateIsReadOnly()
{
Control.IsEditable = !Element.IsReadOnly;
}
}
}
@@ -23,6 +23,7 @@ public EntryRenderer()
RegisterPropertyHandler(Entry.IsTextPredictionEnabledProperty, UpdateIsSpellCheckEnabled);
RegisterPropertyHandler(Specific.FontWeightProperty, UpdateFontWeight);
RegisterPropertyHandler(Entry.SelectionLengthProperty, UpdateSelectionLength);
RegisterPropertyHandler(InputView.IsReadOnlyProperty, UpdateIsReadOnly);
}

protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
@@ -198,5 +199,10 @@ int GetCursorPosition()

return Element.Text.IndexOf(selection, Math.Max(Control.CursorPosition - selection.Length, 0));
}

void UpdateIsReadOnly()

This comment has been minimized.

Copy link
@adrianknight89

adrianknight89 Feb 26, 2018

Contributor

Can move this above MaxLengthFilter

This comment has been minimized.

Copy link
@almirvuk

almirvuk Feb 26, 2018

Author Contributor

I will :)

This comment has been minimized.

Copy link
@StephaneDelcroix

StephaneDelcroix Feb 27, 2018

Member

this is fine.

{
Control.IsEditable = !Element.IsReadOnly;
}
}
}
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.