Skip to content

Commit

Permalink
Implement Font properties in SearchBarHandlers (#533)
Browse files Browse the repository at this point in the history
* Speed up PR builds (#510)

Reduce the jobs and use the new pools

* implement Font properties in SearchBarHandlers

* Fix rebase issues

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: E.Z. Hart <hartez@gmail.com>
  • Loading branch information
3 people committed Mar 17, 2021
1 parent 205573e commit 108e7a4
Show file tree
Hide file tree
Showing 15 changed files with 228 additions and 39 deletions.
Expand Up @@ -233,6 +233,7 @@ void ClearFocus(SearchView view)
view.ClearFocus();
}

[PortHandler]
void UpdateFont()
{
_editText = _editText ?? Control.GetChildrenOfType<EditText>().FirstOrDefault();
Expand Down
Expand Up @@ -291,6 +291,7 @@ public virtual void UpdateCancelButton()
}
}

[PortHandler]
void UpdateFont()
{
_textField = _textField ?? Control.FindDescendantView<UITextField>();
Expand Down
12 changes: 2 additions & 10 deletions src/Core/src/Core/ISearchBar.cs
Expand Up @@ -3,16 +3,8 @@
/// <summary>
/// Represents a View used to initiating a search.
/// </summary>
public interface ISearchBar : IView, IPlaceholder, ITextAlignment
public interface ISearchBar : IView, IText, IPlaceholder, ITextAlignment
{
/// <summary>
/// Gets a string containing the query text in the SearchBar.
/// </summary>
string Text { get; }

/// <summary>
/// Gets a string containing the query text in the SearchBar.
/// </summary>
double CharacterSpacing { get; }

}
}
13 changes: 12 additions & 1 deletion src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs
@@ -1,5 +1,7 @@
using System.Linq;
using System;
using System.Linq;
using Android.Widget;
using Microsoft.Extensions.DependencyInjection;
using SearchView = AndroidX.AppCompat.Widget.SearchView;

namespace Microsoft.Maui.Handlers
Expand Down Expand Up @@ -28,6 +30,15 @@ public static void MapPlaceholder(SearchBarHandler handler, ISearchBar searchBar
handler.TypedNativeView?.UpdatePlaceholder(searchBar);
}

public static void MapFont(SearchBarHandler handler, ISearchBar searchBar)
{
var services = App.Current?.Services
?? throw new InvalidOperationException($"Unable to find service provider, the App.Current.Services was null.");
var fontManager = services.GetRequiredService<IFontManager>();

handler.TypedNativeView?.UpdateFont(searchBar, fontManager, handler._editText);
}

public static void MapHorizontalTextAlignment(SearchBarHandler handler, ISearchBar searchBar)
{
handler.QueryEditor?.UpdateHorizontalTextAlignment(searchBar);
Expand Down
Expand Up @@ -8,6 +8,7 @@ public partial class SearchBarHandler : AbstractViewHandler<ISearchBar, object>

public static void MapText(IViewHandler handler, ISearchBar searchBar) { }
public static void MapPlaceholder(IViewHandler handler, ISearchBar searchBar) { }
public static void MapFont(IViewHandler handler, ISearchBar searchBar) { }
public static void MapHorizontalTextAlignment(IViewHandler handler, ISearchBar searchBar) { }
public static void MapCharacterSpacing(IViewHandler handler, ISearchBar searchBar) { }
}
Expand Down
1 change: 1 addition & 0 deletions src/Core/src/Handlers/SearchBar/SearchBarHandler.cs
Expand Up @@ -6,6 +6,7 @@ public partial class SearchBarHandler
{
[nameof(ISearchBar.Text)] = MapText,
[nameof(ISearchBar.Placeholder)] = MapPlaceholder,
[nameof(ISearchBar.Font)] = MapFont,
[nameof(ISearchBar.HorizontalTextAlignment)] = MapHorizontalTextAlignment,
[nameof(ISearchBar.CharacterSpacing)] = MapCharacterSpacing
};
Expand Down
13 changes: 13 additions & 0 deletions src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs
@@ -1,4 +1,6 @@
using System;
using System.Drawing;
using Microsoft.Extensions.DependencyInjection;
using UIKit;

namespace Microsoft.Maui.Handlers
Expand Down Expand Up @@ -27,6 +29,17 @@ public static void MapPlaceholder(SearchBarHandler handler, ISearchBar searchBar
handler.TypedNativeView?.UpdatePlaceholder(searchBar);
}

// TODO ezhart The extension methods are handling the dependent property updates; those should be in the mapping

public static void MapFont(SearchBarHandler handler, ISearchBar searchBar)
{
var services = App.Current?.Services ??
throw new InvalidOperationException($"Unable to find service provider, the App.Current.Services was null.");
var fontManager = services.GetRequiredService<IFontManager>();

handler.QueryEditor?.UpdateFont(searchBar, fontManager);
}

public static void MapHorizontalTextAlignment(SearchBarHandler handler, ISearchBar searchBar)
{
handler.QueryEditor?.UpdateHorizontalTextAlignment(searchBar);
Expand Down
26 changes: 25 additions & 1 deletion src/Core/src/Platform/Android/SearchBarExtensions.cs
@@ -1,4 +1,7 @@
using SearchView = AndroidX.AppCompat.Widget.SearchView;
using System.Linq;
using Android.Util;
using Android.Widget;
using SearchView = AndroidX.AppCompat.Widget.SearchView;

namespace Microsoft.Maui
{
Expand All @@ -13,5 +16,26 @@ public static void UpdatePlaceholder(this SearchView searchView, ISearchBar sear
{
searchView.QueryHint = searchBar.Placeholder;
}

public static void UpdateFont(this SearchView searchView, ISearchBar searchBar, IFontManager fontManager)
{
searchView.UpdateFont(searchBar, fontManager, null);
}

public static void UpdateFont(this SearchView searchView, ISearchBar searchBar, IFontManager fontManager, EditText? editText)
{
editText ??= searchView.GetChildrenOfType<EditText>().FirstOrDefault();

if (editText == null)
return;

var font = searchBar.Font;

var tf = fontManager.GetTypeface(font);
editText.Typeface = tf;

var sp = fontManager.GetScaledPixel(font);
editText.SetTextSize(ComplexUnitType.Sp, sp);
}
}
}
52 changes: 26 additions & 26 deletions src/Core/src/Platform/iOS/LabelExtensions.cs
Expand Up @@ -79,6 +79,32 @@ public static void UpdatePadding(this MauiLabel nativeLabel, ILabel label)
(float)label.Padding.Right);
}

public static void UpdateTextDecorations(this UILabel nativeLabel, ILabel label)
{
if (nativeLabel.AttributedText != null && !(nativeLabel.AttributedText?.Length > 0))
return;

var textDecorations = label?.TextDecorations;

var newAttributedText = nativeLabel.AttributedText != null ? new NSMutableAttributedString(nativeLabel.AttributedText) : new NSMutableAttributedString(label?.Text ?? string.Empty);
var strikeThroughStyleKey = UIStringAttributeKey.StrikethroughStyle;
var underlineStyleKey = UIStringAttributeKey.UnderlineStyle;

var range = new NSRange(0, newAttributedText.Length);

if ((textDecorations & TextDecorations.Strikethrough) == 0)
newAttributedText.RemoveAttribute(strikeThroughStyleKey, range);
else
newAttributedText.AddAttribute(strikeThroughStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);

if ((textDecorations & TextDecorations.Underline) == 0)
newAttributedText.RemoveAttribute(underlineStyleKey, range);
else
newAttributedText.AddAttribute(underlineStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);

nativeLabel.AttributedText = newAttributedText;
}

internal static void SetLineBreakMode(this UILabel nativeLabel, ILabel label)
{
int maxLines = label.MaxLines;
Expand Down Expand Up @@ -113,31 +139,5 @@ internal static void SetLineBreakMode(this UILabel nativeLabel, ILabel label)

nativeLabel.Lines = maxLines;
}

public static void UpdateTextDecorations(this UILabel nativeLabel, ILabel label)
{
if (nativeLabel.AttributedText != null && !(nativeLabel.AttributedText?.Length > 0))
return;

var textDecorations = label?.TextDecorations;

var newAttributedText = nativeLabel.AttributedText != null ? new NSMutableAttributedString(nativeLabel.AttributedText) : new NSMutableAttributedString(label?.Text ?? string.Empty);
var strikeThroughStyleKey = UIStringAttributeKey.StrikethroughStyle;
var underlineStyleKey = UIStringAttributeKey.UnderlineStyle;

var range = new NSRange(0, newAttributedText.Length);

if ((textDecorations & TextDecorations.Strikethrough) == 0)
newAttributedText.RemoveAttribute(strikeThroughStyleKey, range);
else
newAttributedText.AddAttribute(strikeThroughStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);

if ((textDecorations & TextDecorations.Underline) == 0)
newAttributedText.RemoveAttribute(underlineStyleKey, range);
else
newAttributedText.AddAttribute(underlineStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);

nativeLabel.AttributedText = newAttributedText;
}
}
}
34 changes: 34 additions & 0 deletions src/Core/src/Platform/iOS/SearchBarExtensions.cs
Expand Up @@ -13,5 +13,39 @@ public static void UpdatePlaceholder(this UISearchBar uiSearchBar, ISearchBar se
{
uiSearchBar.Placeholder = searchBar.Placeholder;
}

public static void UpdateFont(this UISearchBar uiSearchBar, ISearchBar searchBar, IFontManager fontManager)
{
uiSearchBar.UpdateFont(searchBar, fontManager, null);
}

public static void UpdateFont(this UISearchBar uiSearchBar, ISearchBar searchBar, IFontManager fontManager, UITextField? textField)
{
textField ??= uiSearchBar.FindDescendantView<UITextField>();

if (textField == null)
return;

var uiFont = fontManager.GetFont(searchBar.Font);
textField.Font = uiFont;
}

//public static void UpdateHorizontalTextAlignment(this UISearchBar uiSearchBar, ISearchBar searchBar)
//{
// UpdateHorizontalTextAlignment(uiSearchBar, searchBar, null);
//}

//public static void UpdateHorizontalTextAlignment(this UISearchBar uiSearchBar, ISearchBar searchBar, UITextField? textField)
//{
// textField ??= uiSearchBar.FindDescendantView<UITextField>();

// if (textField == null)
// return;

// // We don't have a FlowDirection yet, so there's nothing to pass in here.
// // TODO: Update this when FlowDirection is available
// // (or update the extension to take an ILabel instead of an alignment and work it out from there)
// textField.TextAlignment = searchBar.HorizontalTextAlignment.ToNative(true);
//}
}
}
8 changes: 8 additions & 0 deletions src/Core/src/Platform/iOS/TextFieldExtensions.cs
Expand Up @@ -13,5 +13,13 @@ public static void UpdateCharacterSpacing(this UITextField textField, ISearchBar

// TODO: Include AttributedText to Label Placeholder
}

public static void UpdateFont(this UITextField textField, ISearchBar searchBar, IFontManager fontManager)
{
var uiFont = fontManager.GetFont(searchBar.Font);
textField.Font = uiFont;

textField.UpdateCharacterSpacing(searchBar);
}
}
}
Expand Up @@ -90,5 +90,38 @@ Android.Views.TextAlignment GetNativeTextAlignment(SearchBarHandler searchBarHan
var editText = searchView.GetChildrenOfType<EditText>().First();
return editText.TextAlignment;
}

double GetNativeUnscaledFontSize(SearchBarHandler searchBarHandler)
{
var searchView = GetNativeSearchBar(searchBarHandler);
var editText = searchView.GetChildrenOfType<EditText>().FirstOrDefault();

if (editText == null)
return -1;

return editText.TextSize / editText.Resources.DisplayMetrics.Density;
}

bool GetNativeIsBold(SearchBarHandler searchBarHandler)
{
var searchView = GetNativeSearchBar(searchBarHandler);
var editText = searchView.GetChildrenOfType<EditText>().FirstOrDefault();

if (editText == null)
return false;

return editText.Typeface.IsBold;
}

bool GetNativeIsItalic(SearchBarHandler searchBarHandler)
{
var searchView = GetNativeSearchBar(searchBarHandler);
var editText = searchView.GetChildrenOfType<EditText>().FirstOrDefault();

if (editText == null)
return false;

return editText.Typeface.IsItalic;
}
}
}
Expand Up @@ -56,5 +56,38 @@ public async Task PlaceholderInitializesCorrectly()

await ValidatePropertyInitValue(searchBar, () => searchBar.Placeholder, GetNativePlaceholder, searchBar.Placeholder);
}

[Theory(DisplayName = "Font Size Initializes Correctly")]
[InlineData(1)]
[InlineData(10)]
[InlineData(20)]
[InlineData(100)]
public async Task FontSizeInitializesCorrectly(int fontSize)
{
var searchBar = new SearchBarStub()
{
Text = "Test",
Font = Font.OfSize("Arial", fontSize)
};

await ValidatePropertyInitValue(searchBar, () => searchBar.Font.FontSize, GetNativeUnscaledFontSize, searchBar.Font.FontSize);
}

[Theory(DisplayName = "Font Attributes Initialize Correctly")]
[InlineData(FontAttributes.None, false, false)]
[InlineData(FontAttributes.Bold, true, false)]
[InlineData(FontAttributes.Italic, false, true)]
[InlineData(FontAttributes.Bold | FontAttributes.Italic, true, true)]
public async Task FontAttributesInitializeCorrectly(FontAttributes attributes, bool isBold, bool isItalic)
{
var searchBar = new SearchBarStub()
{
Text = "Test",
Font = Font.OfSize("Arial", 10).WithAttributes(attributes)
};

await ValidatePropertyInitValue(searchBar, () => searchBar.Font.FontAttributes.HasFlag(FontAttributes.Bold), GetNativeIsBold, isBold);
await ValidatePropertyInitValue(searchBar, () => searchBar.Font.FontAttributes.HasFlag(FontAttributes.Italic), GetNativeIsItalic, isItalic);
}
}
}
Expand Up @@ -86,5 +86,38 @@ UITextAlignment GetNativeTextAlignment(SearchBarHandler searchBarHandler)

return textField.AttributedText.GetCharacterSpacing();
}

double GetNativeUnscaledFontSize(SearchBarHandler searchBarHandler)
{
var uiSearchBar = GetNativeSearchBar(searchBarHandler);
var textField = uiSearchBar.FindDescendantView<UITextField>();

if (textField == null)
return -1;

return textField.Font.PointSize;
}

bool GetNativeIsBold(SearchBarHandler searchBarHandler)
{
var uiSearchBar = GetNativeSearchBar(searchBarHandler);
var textField = uiSearchBar.FindDescendantView<UITextField>();

if (textField == null)
return false;

return textField.Font.FontDescriptor.SymbolicTraits.HasFlag(UIFontDescriptorSymbolicTraits.Bold);
}

bool GetNativeIsItalic(SearchBarHandler searchBarHandler)
{
var uiSearchBar = GetNativeSearchBar(searchBarHandler);
var textField = uiSearchBar.FindDescendantView<UITextField>();

if (textField == null)
return false;

return textField.Font.FontDescriptor.SymbolicTraits.HasFlag(UIFontDescriptorSymbolicTraits.Italic);
}
}
}
6 changes: 5 additions & 1 deletion src/Core/tests/DeviceTests/Stubs/SearchBarStub.cs
Expand Up @@ -8,8 +8,12 @@ public partial class SearchBarStub : StubBase, ISearchBar

public string Placeholder { get; set; }

public TextAlignment HorizontalTextAlignment { get; set; }
public Color TextColor { get; set; }

public double CharacterSpacing { get; set; }

public Font Font { get; set; }

public TextAlignment HorizontalTextAlignment { get; set; }
}
}

0 comments on commit 108e7a4

Please sign in to comment.