Skip to content

Commit

Permalink
Rework the Label mappers for FormattedText
Browse files Browse the repository at this point in the history
The current implementation did not recreate the FormattedText spans when certain properties changed: Font and TextColor
  • Loading branch information
mattleibow committed Oct 19, 2023
1 parent 4226851 commit 4db51b0
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 159 deletions.
6 changes: 0 additions & 6 deletions src/Controls/src/Core/Label/Label.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,10 @@ private protected override void OnHandlerChangedCore()
}
}

public static void MapTextType(LabelHandler handler, Label label) => MapTextType((ILabelHandler)handler, label);
public static void MapText(LabelHandler handler, Label label) => MapText((ILabelHandler)handler, label);
public static void MapLineBreakMode(LabelHandler handler, Label label) => MapLineBreakMode((ILabelHandler)handler, label);


public static void MapTextType(ILabelHandler handler, Label label)
{
handler.UpdateValue(nameof(ILabel.Text));
}

public static void MapText(ILabelHandler handler, Label label)
{
Platform.TextViewExtensions.UpdateText(handler.PlatformView, label);
Expand Down
168 changes: 159 additions & 9 deletions src/Controls/src/Core/Label/Label.Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,172 @@ internal static new void RemapForControls()
// ILabel does not include the TextType property, so we map it here to handle HTML text
// And we map some of the other property handlers to Controls-specific versions that avoid stepping on HTML text settings

// these just refresh Text / FormattedText
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(TextType), MapTextType);
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(TextTransform), MapTextTransform);

// these are really a single property
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(Text), MapText);
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(FormattedText), MapText);
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(TextTransform), MapText);
#if WINDOWS
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(PlatformConfiguration.WindowsSpecific.InputView.DetectReadingOrderFromContentProperty.PropertyName, MapDetectReadingOrderFromContent);
#endif
#if IOS

LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(LineBreakMode), MapLineBreakMode);
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(MaxLines), MapMaxLines);

#if ANDROID || IOS
// these are for platforms that do no support view properties reaching spans
LabelHandler.Mapper.ModifyMapping<Label, ILabelHandler>(nameof(ILabel.Font), MapFont);
LabelHandler.Mapper.ModifyMapping<Label, ILabelHandler>(nameof(TextColor), MapTextColor);

// these are for properties that should only apply to plain text (not spans nor html)
LabelHandler.Mapper.ModifyMapping<Label, ILabelHandler>(nameof(TextDecorations), MapTextDecorations);
LabelHandler.Mapper.ModifyMapping<Label, ILabelHandler>(nameof(CharacterSpacing), MapCharacterSpacing);
LabelHandler.Mapper.ModifyMapping<Label, ILabelHandler>(nameof(LineHeight), MapLineHeight);
LabelHandler.Mapper.ModifyMapping<Label, ILabelHandler>(nameof(ILabel.Font), MapFont);
LabelHandler.Mapper.ModifyMapping<Label, ILabelHandler>(nameof(TextColor), MapTextColor);
#endif
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(Label.LineBreakMode), MapLineBreakMode);
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(Label.MaxLines), MapMaxLines);

// platform-specifics
#if WINDOWS
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(PlatformConfiguration.WindowsSpecific.InputView.DetectReadingOrderFromContentProperty.PropertyName, MapDetectReadingOrderFromContent);
#endif
}


// Some properties just need to re-evaluate the Text property
// which then makes a decision about Text vs FormattedText:
// - TextType
// - TextTransform
public static void MapTextType(LabelHandler handler, Label label) =>
MapTextOrFormattedText(handler, label);
public static void MapTextType(ILabelHandler handler, Label label) =>
MapTextOrFormattedText(handler, label);
static void MapTextTransform(ILabelHandler handler, Label label) =>
MapTextOrFormattedText(handler, label);
static void MapTextOrFormattedText(ILabelHandler handler, Label label)
{
if (label.HasFormattedTextSpans)
handler.UpdateValue(nameof(FormattedText));
else
handler.UpdateValue(nameof(Text));
}

#if ANDROID || IOS

#if IOS // iOS had these public, so we cannot remove
public static void MapTextDecorations(ILabelHandler handler, Label label) =>
MapTextDecorations(handler, label, (h, v) => LabelHandler.MapTextDecorations(handler, label));

public static void MapCharacterSpacing(ILabelHandler handler, Label label) =>
MapCharacterSpacing(handler, label, (h, v) => LabelHandler.MapCharacterSpacing(handler, label));

public static void MapLineHeight(ILabelHandler handler, Label label) =>
MapLineHeight(handler, label, (h, v) => LabelHandler.MapLineHeight(handler, label));

public static void MapFont(ILabelHandler handler, Label label) =>
MapFont(handler, label, (h, v) => LabelHandler.MapFont(handler, label));

public static void MapTextColor(ILabelHandler handler, Label label) =>
MapTextColor(handler, label, (h, v) => LabelHandler.MapTextColor(handler, label));

public static void MapTextDecorations(LabelHandler handler, Label label) =>
MapTextDecorations((ILabelHandler)handler, label);

public static void MapCharacterSpacing(LabelHandler handler, Label label) =>
MapCharacterSpacing((ILabelHandler)handler, label);

public static void MapLineHeight(LabelHandler handler, Label label) =>
MapLineHeight((ILabelHandler)handler, label);

public static void MapFont(LabelHandler handler, Label label) =>
MapFont((ILabelHandler)handler, label);

public static void MapTextColor(LabelHandler handler, Label label) =>
MapTextColor((ILabelHandler)handler, label);
#endif

// these are for properties that should only apply to plain text (not spans nor html)

static void MapLineHeight(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (!IsPlainText(label))
return;

baseMethod?.Invoke(handler, label);
}

static void MapTextDecorations(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (!IsPlainText(label))
return;

baseMethod?.Invoke(handler, label);
}

static void MapCharacterSpacing(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (!IsPlainText(label))
return;

baseMethod?.Invoke(handler, label);
}

// these are for platforms that do no support view properties reaching spans

static void MapFont(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (label.HasFormattedTextSpans)
{
// if there is formatted text,
// then we re-apply the whole formatted text
handler.UpdateValue(nameof(FormattedText));
}
else if (label.TextType == TextType.Text || !IsDefaultFont(label))
{
// if this is plain text or if the user specifically wants to override html,
// then we fall back to the base implementation
baseMethod?.Invoke(handler, label);
}
}

static void MapTextColor(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (label.HasFormattedTextSpans)
{
// if there is formatted text,
// then we re-apply the whole formatted text
handler.UpdateValue(nameof(FormattedText));
}
else if (label.TextType == TextType.Text || !label.TextColor.IsDefault())
{
// if this is plain text or if the user specifically wants to override html,
// then we fall back to the base implementation
baseMethod?.Invoke(handler, label);
}
}

#endif

static bool IsPlainText(Label label)
{
if (label.HasFormattedTextSpans)
return false;

if (label.TextType != TextType.Text)
return false;

return true;
}

static bool IsDefaultFont(Label label)
{
if (label.IsSet(Label.FontAttributesProperty))
return false;

if (label.IsSet(Label.FontFamilyProperty))
return false;

if (label.IsSet(Label.FontSizeProperty))
return false;

return true;
}
}
}
3 changes: 0 additions & 3 deletions src/Controls/src/Core/Label/Label.Standard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ namespace Microsoft.Maui.Controls
/// <include file="../../../docs/Microsoft.Maui.Controls/Label.xml" path="Type[@FullName='Microsoft.Maui.Controls.Label']/Docs/*" />
public partial class Label
{
public static void MapTextType(ILabelHandler handler, Label label) { }
public static void MapText(ILabelHandler handler, Label label) { }

public static void MapLineBreakMode(ILabelHandler handler, Label label) { }
public static void MapMaxLines(ILabelHandler handler, Label label) { }

public static void MapTextType(LabelHandler handler, Label label) => MapText((ILabelHandler)handler, label);
public static void MapText(LabelHandler handler, Label label) => MapText((ILabelHandler)handler, label);
public static void MapLineBreakMode(LabelHandler handler, Label label) => MapLineBreakMode((ILabelHandler)handler, label);
public static void MapMaxLines(LabelHandler handler, Label label) => MapMaxLines((ILabelHandler)handler, label);
Expand Down
6 changes: 0 additions & 6 deletions src/Controls/src/Core/Label/Label.Tizen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@ namespace Microsoft.Maui.Controls
{
public partial class Label
{
public static void MapTextType(LabelHandler handler, Label label) => MapTextType((ILabelHandler)handler, label);
public static void MapText(LabelHandler handler, Label label) => MapText((ILabelHandler)handler, label);

public static void MapTextType(ILabelHandler handler, Label label)
{
handler.UpdateValue(nameof(ILabel.Text));
}

public static void MapText(ILabelHandler handler, Label label)
{
Platform.TextExtensions.UpdateText(handler.PlatformView, label);
Expand Down
4 changes: 0 additions & 4 deletions src/Controls/src/Core/Label/Label.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@ namespace Microsoft.Maui.Controls
public partial class Label
{
public static void MapDetectReadingOrderFromContent(LabelHandler handler, Label label) => MapDetectReadingOrderFromContent((ILabelHandler)handler, label);
public static void MapTextType(LabelHandler handler, Label label) => MapTextType((ILabelHandler)handler, label);
public static void MapText(LabelHandler handler, Label label) => MapText((ILabelHandler)handler, label);


public static void MapDetectReadingOrderFromContent(ILabelHandler handler, Label label) =>
Platform.TextBlockExtensions.UpdateDetectReadingOrderFromContent(handler.PlatformView, label);

public static void MapTextType(ILabelHandler handler, Label label) =>
handler.UpdateValue(nameof(ILabel.Text));

public static void MapText(ILabelHandler handler, Label label) =>
Platform.TextBlockExtensions.UpdateText(handler.PlatformView, label);

Expand Down
113 changes: 6 additions & 107 deletions src/Controls/src/Core/Label/Label.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,7 @@ namespace Microsoft.Maui.Controls
{
public partial class Label
{
public static void MapTextType(LabelHandler handler, Label label) => MapTextType((ILabelHandler)handler, label);
public static void MapText(LabelHandler handler, Label label) => MapText((ILabelHandler)handler, label);
public static void MapCharacterSpacing(LabelHandler handler, Label label) => MapCharacterSpacing((ILabelHandler)handler, label);
public static void MapTextDecorations(LabelHandler handler, Label label) => MapTextDecorations((ILabelHandler)handler, label);
public static void MapLineHeight(LabelHandler handler, Label label) => MapLineHeight((ILabelHandler)handler, label);
public static void MapFont(LabelHandler handler, Label label) => MapFont((ILabelHandler)handler, label);
public static void MapTextColor(LabelHandler handler, Label label) => MapTextColor((ILabelHandler)handler, label);

public static void MapTextDecorations(ILabelHandler handler, Label label) =>
MapTextDecorations(handler, label, (h, v) => LabelHandler.MapTextDecorations(handler, label));

public static void MapCharacterSpacing(ILabelHandler handler, Label label) =>
MapCharacterSpacing(handler, label, (h, v) => LabelHandler.MapCharacterSpacing(handler, label));

public static void MapLineHeight(ILabelHandler handler, Label label) =>
MapLineHeight(handler, label, (h, v) => LabelHandler.MapLineHeight(handler, label));

public static void MapFont(ILabelHandler handler, Label label) =>
MapFont(handler, label, (h, v) => LabelHandler.MapFont(handler, label));

public static void MapTextColor(ILabelHandler handler, Label label) =>
MapTextColor(handler, label, (h, v) => LabelHandler.MapTextColor(handler, label));

public static void MapTextType(ILabelHandler handler, Label label)
{
handler.UpdateValue(nameof(ILabel.Text));
}

public static void MapText(ILabelHandler handler, Label label)
{
Expand All @@ -41,60 +15,6 @@ public static void MapText(ILabelHandler handler, Label label)
MapFormatting(handler, label);
}

static void MapTextDecorations(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (!IsPlainText(label))
return;

baseMethod?.Invoke(handler, label);
}

static void MapCharacterSpacing(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (!IsPlainText(label))
return;

baseMethod?.Invoke(handler, label);
}

static void MapLineHeight(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (!IsPlainText(label))
return;

baseMethod?.Invoke(handler, label);
}

static void MapFont(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (label.HasFormattedTextSpans)
return;

if (label.TextType == TextType.Html && IsDefaultFont(label))
{
// If no explicit font has been specified and we're displaying HTML,
// let the HTML determine the font
return;
}

baseMethod?.Invoke(handler, label);
}

static void MapTextColor(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (label.HasFormattedTextSpans)
return;

if (label.TextType == TextType.Html && label.TextColor.IsDefault())
{
// If no explicit text color has been specified and we're displaying HTML,
// let the HTML determine the colors
return;
}

baseMethod?.Invoke(handler, label);
}

public static void MapLineBreakMode(ILabelHandler handler, Label label)
{
handler.PlatformView?.UpdateLineBreakMode(label);
Expand All @@ -107,38 +27,17 @@ public static void MapMaxLines(ILabelHandler handler, Label label)

static void MapFormatting(ILabelHandler handler, Label label)
{
handler.UpdateValue(nameof(ILabel.TextColor));
handler.UpdateValue(nameof(ILabel.Font));
// we need to re-apply color and font for HTML labels
if (!label.HasFormattedTextSpans && label.TextType == TextType.Html)
{
handler.UpdateValue(nameof(ILabel.TextColor));
handler.UpdateValue(nameof(ILabel.Font));
}

if (!IsPlainText(label))
return;

LabelHandler.MapFormatting(handler, label);
}

static bool IsDefaultFont(Label label)
{
if (label.IsSet(Label.FontAttributesProperty))
return false;

if (label.IsSet(Label.FontFamilyProperty))
return false;

if (label.IsSet(Label.FontSizeProperty))
return false;

return true;
}

static bool IsPlainText(Label label)
{
if (label.HasFormattedTextSpans)
return false;

if (label.TextType != TextType.Text)
return false;

return true;
}
}
}

0 comments on commit 4db51b0

Please sign in to comment.