Skip to content

Commit

Permalink
feat: (macOS) Add SecureTextBox for PasswordBox
Browse files Browse the repository at this point in the history
  • Loading branch information
ajpinedam committed May 4, 2020
1 parent 0a2ca68 commit 7e826cb
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/Uno.UI/Mixins/macOS/FrameworkElementMixins.tt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// AddClass("Windows.UI.Xaml.Controls", "ProgressRing", hasAttachedToWindow: false, overridesAttachedToWindow: true);
// AddClass("Uno.UI.Controls.Legacy", "ListViewBase", hasAttachedToWindow: false, overridesAttachedToWindow: true, defineSetNeedsLayout: false, defineLayoutSubviews: false);
AddClass("Windows.UI.Xaml.Controls", "TextBoxView", hasAutomationPeer: false, hasAttachedToWindow: true, overridesAttachedToWindow: false);
AddClass("Windows.UI.Xaml.Controls", "SecureTextBoxView", hasAutomationPeer: false, hasAttachedToWindow: true, overridesAttachedToWindow: false);
#>
<#@include file="..\..\UI\Xaml\IFrameworkElementImplementation.macOS.tt"#>
#endif
3 changes: 3 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/PasswordBox/PasswordBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public partial class PasswordBox : TextBox
private readonly SerialDisposable _revealButtonSubscription = new SerialDisposable();

public PasswordBox()
#if __MACOS__
: base(true)
#endif
{

}
Expand Down
191 changes: 191 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/PasswordBox/SecuredTextBoxView.macOS.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
using CoreGraphics;
using System;
using Uno.Extensions;
using Windows.UI.Xaml.Media;
using Uno.UI.Controls;
using Foundation;
using System.Collections;
using System.Linq;
using AppKit;

namespace Windows.UI.Xaml.Controls
{
public partial class SecureTextBoxView : NSSecureTextField, ITextBoxView, DependencyObject, IFontScalable
{
//private TextBoxViewDelegate _delegate;
private readonly WeakReference<TextBox> _textBox;

public SecureTextBoxView(TextBox textBox)
{
_textBox = new WeakReference<TextBox>(textBox);

InitializeBinder();
Initialize();
}


private void OnEditingChanged(object sender, EventArgs e)
{
OnTextChanged();
}

internal void OnChanged()
{
OnTextChanged();
}

public string Text
{
get => base.StringValue;

set
{
// The native control will ignore a value of null and retain an empty string. We coalesce the null to prevent a spurious empty string getting bounced back via two-way binding.
value = value ?? string.Empty;
if (base.StringValue != value)
{
base.StringValue = value;
OnTextChanged();
}
}
}

private void OnTextChanged()
{
var textBox = _textBox?.GetTarget();
if (textBox != null)
{
var text = textBox.ProcessTextInput(Text);
SetTextNative(text);
}
}

public void SetTextNative(string text) => Text = text;

private void Initialize()
{
//Delegate = _delegate = new TextBoxViewDelegate(_textBox, new WeakReference<SecureTextBoxView>(this))
//{
// IsKeyboardHiddenOnEnter = true
//};

DrawsBackground = false;
Bezeled = false;
}

public override CGSize SizeThatFits(CGSize size)
{
return IFrameworkElementHelper.SizeThatFits(this, base.SizeThatFits(size));
}

public void UpdateFont()
{
var textBox = _textBox.GetTarget();

if (textBox != null)
{
var newFont = NSFontHelper.TryGetFont((float)textBox.FontSize, textBox.FontWeight, textBox.FontStyle, textBox.FontFamily);

if (newFont != null)
{
base.Font = newFont;
this.InvalidateMeasure();
}
}
}

public Brush Foreground
{
get { return (Brush)GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}

public bool HasMarkedText => throw new NotImplementedException();

public nint ConversationIdentifier => throw new NotImplementedException();

public NSRange MarkedRange => throw new NotImplementedException();

public NSRange SelectedRange => throw new NotImplementedException();

public NSString[] ValidAttributesForMarkedText => null;

public static readonly DependencyProperty ForegroundProperty =
DependencyProperty.Register(
"Foreground",
typeof(Brush),
typeof(SecureTextBoxView),
new FrameworkPropertyMetadata(
defaultValue: SolidColorBrushHelper.Black,
options: FrameworkPropertyMetadataOptions.Inherits,
propertyChangedCallback: (s, e) => ((SecureTextBoxView)s).OnForegroundChanged((Brush)e.OldValue, (Brush)e.NewValue)
)
);

public void OnForegroundChanged(Brush oldValue, Brush newValue)
{
var textBox = _textBox.GetTarget();

if (textBox != null)
{
var scb = newValue as SolidColorBrush;

if (scb != null)
{
this.TextColor = scb.Color;
}
}

UpdateCaretColor();
}

private void UpdateCaretColor()
{
if (CurrentEditor is NSTextView textField && Foreground is SolidColorBrush scb)
{
textField.InsertionPointColor = scb.Color;
}
}

public void RefreshFont()
{
UpdateFont();
}

public override bool BecomeFirstResponder()
{
UpdateCaretColor();
return base.BecomeFirstResponder();
}

public void InsertText(NSObject insertString)
{
throw new NotImplementedException();
}

public void SetMarkedText(NSObject @string, NSRange selRange)
{
throw new NotImplementedException();
}

public void UnmarkText()
{
throw new NotImplementedException();
}

public NSAttributedString GetAttributedSubstring(NSRange range)
{
throw new NotImplementedException();
}

public CGRect GetFirstRectForCharacterRange(NSRange range)
{
throw new NotImplementedException();
}

public nuint GetCharacterIndex(CGPoint point)
{
throw new NotImplementedException();
}
}
}
35 changes: 24 additions & 11 deletions src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.macOS.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using Uno.UI;
using Windows.UI.Xaml.Data;
using AppKit;
using AppKit;
using CoreGraphics;
using Uno.UI.Extensions;
using Uno.Extensions;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Input;
using Uno.Client;
using Foundation;
using Uno.Logging;

namespace Windows.UI.Xaml.Controls
Expand Down Expand Up @@ -63,12 +56,19 @@ private void UpdateTextBoxView()
{
if (_contentElement != null)
{
if (_textBoxView is TextBoxView)
if (_textBoxView is TextBoxView || _textBoxView is SecureTextBoxView)
{
return;
}

_textBoxView = new TextBoxView(this) { UsesSingleLineMode = AcceptsReturn || TextWrapping != TextWrapping.NoWrap };
if (_isPassword)
{
_textBoxView = new SecureTextBoxView(this) { UsesSingleLineMode = true };
}
else
{
_textBoxView = new TextBoxView(this) { UsesSingleLineMode = AcceptsReturn || TextWrapping != TextWrapping.NoWrap };
}

_contentElement.Content = _textBoxView;
_textBoxView.SetTextNative(Text);
Expand Down Expand Up @@ -134,10 +134,14 @@ public int SelectionStart
}
set
{
if(_textBoxView is TextBoxView sltbv)
if (_textBoxView is TextBoxView sltbv)
{
sltbv.SelectWithFrame(sltbv.Frame, sltbv.CurrentEditor, null, value, _textBoxView.SelectedRange.Length);
}
else if (_textBoxView is SecureTextBoxView securedtv)
{
securedtv.SelectWithFrame(securedtv.Frame, securedtv.CurrentEditor, null, value, _textBoxView.SelectedRange.Length);
}
}
}

Expand All @@ -158,6 +162,10 @@ public int SelectionLength
{
sltbv.SelectWithFrame(sltbv.Frame, sltbv.CurrentEditor, null, _textBoxView.SelectedRange.Location, value);
}
else if (_textBoxView is SecureTextBoxView securedtv)
{
securedtv.SelectWithFrame(securedtv.Frame, securedtv.CurrentEditor, null, _textBoxView.SelectedRange.Location, value);
}
}
}

Expand All @@ -179,5 +187,10 @@ partial void OnForegroundColorChangedPartial(Brush newValue)
_textBoxView.Foreground = newValue;
}
}

protected void SetSecureTextEntry(bool isSecure)
{
}

}
}

0 comments on commit 7e826cb

Please sign in to comment.