Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

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

Merged
merged 25 commits into from
Jan 10, 2019
Merged
Show file tree
Hide file tree
Changes from all 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 by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -54,6 +56,7 @@ protected override void Build(StackLayout stackLayout)
Add(textColorDisabledContainer);
Add(keyboardContainer);
Add(maxLengthContainer);
Add(readOnlyContainer);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -110,6 +111,7 @@ protected override void Build (StackLayout stackLayout)
Add (placeholderColorDisabledContainer);
Add (passwordColorContainer);
Add (maxLengthContainer);
Add (readOnlyContainer);
Add (isPasswordInputScopeContainer);
}
}
Expand Down
14 changes: 14 additions & 0 deletions Xamarin.Forms.Core.UnitTests/EditorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
15 changes: 15 additions & 0 deletions Xamarin.Forms.Core.UnitTests/EntryUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
4 changes: 3 additions & 1 deletion Xamarin.Forms.Core.UnitTests/NotifiedPropertiesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 8 additions & 0 deletions Xamarin.Forms.Core/InputView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand All @@ -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); }
}
}
}
4 changes: 4 additions & 0 deletions Xamarin.Forms.CustomAttributes/TestAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ public enum Editor
FontAttributes,
FontFamily,
FontSize,
MaxLength,
IsReadOnly
}

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

Expand Down
12 changes: 12 additions & 0 deletions Xamarin.Forms.Platform.Android/Renderers/EditorRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
UpdateMaxLength();
UpdatePlaceholderColor();
UpdatePlaceholderText();
UpdateIsReadOnly();
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
}
}
}
16 changes: 14 additions & 2 deletions Xamarin.Forms.Platform.Android/Renderers/EntryRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
UpdateMaxLength();
UpdateImeOptions();
UpdateReturnType();
UpdateIsReadOnly();

if (_cursorPositionChangePending || _selectionLengthChangePending)
UpdateCursorSelection();
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -332,7 +335,7 @@ void UpdateCursorSelection()
if (_nativeSelectionIsUpdating || Control == null || Element == null)
return;

if (Control.RequestFocus())
if (!Element.IsReadOnly && Control.RequestFocus())
{
try
{
Expand Down Expand Up @@ -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);
}
}
}
}
10 changes: 10 additions & 0 deletions Xamarin.Forms.Platform.MacOS/Renderers/EditorRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
UpdateTextColor();
UpdateEditable();
UpdateMaxLength();
UpdateIsReadOnly();
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
Expand All @@ -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)
Expand Down Expand Up @@ -148,5 +151,12 @@ void UpdateMaxLength()
if (currentControlText.Length > Element?.MaxLength)
Control.StringValue = currentControlText.Substring(0, Element.MaxLength);
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for suggestion, I will try :)

Copy link
Contributor

@PureWeen PureWeen Nov 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comments I made earlier on this look to still apply

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

}
}
}
13 changes: 12 additions & 1 deletion Xamarin.Forms.Platform.MacOS/Renderers/EntryRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -201,7 +203,8 @@ void UpdateControl()
UpdateFont();
UpdateAlignment();
UpdateMaxLength();
}
UpdateIsReadOnly();
}

void TextFieldFocusChanged(object sender, BoolEventArgs e)
{
Expand Down Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
}
}
6 changes: 6 additions & 0 deletions Xamarin.Forms.Platform.Tizen/Renderers/EditorRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -153,5 +154,10 @@ string MaxLengthFilter(ElmSharp.Entry entry, string s)

return null;
}

void UpdateIsReadOnly()
{
Control.IsEditable = !Element.IsReadOnly;
}
}
}
6 changes: 6 additions & 0 deletions Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -198,5 +199,10 @@ int GetCursorPosition()

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

void UpdateIsReadOnly()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can move this above MaxLengthFilter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine.

{
Control.IsEditable = !Element.IsReadOnly;
}
}
}
8 changes: 8 additions & 0 deletions Xamarin.Forms.Platform.UAP/EditorRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
UpdateDetectReadingOrderFromContent();
UpdatePlaceholderText();
UpdatePlaceholderColor();
UpdateIsReadOnly();
}

base.OnElementChanged(e);
Expand Down Expand Up @@ -127,6 +128,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();
}

void OnLostFocus(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -357,5 +360,10 @@ void UpdateDetectReadingOrderFromContent()
}
}
}

void UpdateIsReadOnly()
{
Control.IsReadOnly = Element.IsReadOnly;
}
}
}
Loading