From c646036b7384fe5fad063a3919723bd3e2fd27f3 Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Tue, 25 Jun 2024 23:08:45 +0100 Subject: [PATCH] More UI improvements --- Toolkit.Avalonia/FrameHandler.cs | 5 +- .../PersonPicture/PersonPicture.axaml | 17 +++-- .../PersonPicture/PersonPicture.cs | 10 ++- .../PersonPictureColourGenerator.cs | 75 +++++++++++++++++++ 4 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs diff --git a/Toolkit.Avalonia/FrameHandler.cs b/Toolkit.Avalonia/FrameHandler.cs index 3dbcdd8..f855733 100644 --- a/Toolkit.Avalonia/FrameHandler.cs +++ b/Toolkit.Avalonia/FrameHandler.cs @@ -168,12 +168,13 @@ public class FrameHandler : } } } - - frame.NavigateFromObject(control, navigationOptions); foreach (Action postAction in postNavigateActions) { postAction.Invoke(); } + + frame.NavigateFromObject(control, navigationOptions); + } } diff --git a/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.axaml b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.axaml index a0741ce..f1f81b5 100644 --- a/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.axaml +++ b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.axaml @@ -4,19 +4,19 @@ xmlns:controls="using:Toolkit.UI.Controls.Avalonia"> - + - + - + - + @@ -27,18 +27,19 @@ 0,-4,-4,0 + + + + - - - BadgeGlyphProperty = @@ -36,11 +37,12 @@ public class PersonPicture : TemplatedControl private static readonly StyledProperty TemplateSettingsProperty = AvaloniaProperty.Register(nameof(TemplateSettings)); + private readonly ImageBrush? badgeImageBrush; private FontIcon? badgeGlyphIcon; - private ImageBrush? badgeImageBrush; private TextBlock? badgeNumberTextBlock; private Ellipse? badgingBackgroundEllipse; private Ellipse? badgingEllipse; + private PersonPictureColourGenerator colourGenerator = new(hue: 210, saturation: 0.8f, lightness: 0.6f); private string? displayNameInitials; private TextBlock? initialsTextBlock; @@ -335,6 +337,12 @@ public class PersonPicture : TemplatedControl PersonPictureTemplateSettings templateSettings = TemplateSettings; templateSettings.ActualInitials = initials; + if (DisplayName is { Length: > 0 }) + { + Color rgb = colourGenerator.Create(DisplayName); + SetValue(BackgroundProperty, new SolidColorBrush(Color.FromArgb(rgb.A, rgb.R, rgb.G, rgb.B))); + } + if (imageSource is not null) { ImageBrush? imageBrush = templateSettings.ActualImageBrush; diff --git a/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs new file mode 100644 index 0000000..0eca004 --- /dev/null +++ b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs @@ -0,0 +1,75 @@ +using Avalonia.Media; +using System.Security.Cryptography; +using System.Text; + +namespace Toolkit.UI.Controls.Avalonia; + +public class PersonPictureColourGenerator +{ + private readonly float hue; + private readonly float saturation; + private readonly float lightness; + private const float minLightness = 0.2f; + private const float maxLightness = 0.8f; + + public PersonPictureColourGenerator(float hue = 210, + float saturation = 0.8f, + float lightness = 0.6f) + { + this.hue = hue; + this.saturation = saturation; + this.lightness = lightness; + } + + public Color Create(string input) + { + byte[] hashBytes = GetHash(input); + + float h = (hashBytes[0] + hue) % 360; + float s = (hashBytes[1] / 255.0f) * saturation; + float l = EnsureNonExtremeLightness((hashBytes[2] / 255.0f) * lightness); + + (byte r, byte g, byte b) = HslToRgb(h, s, l); + + return Color.FromRgb(r, g, b); + } + + private byte[] GetHash(string input) => + SHA256.HashData(Encoding.UTF8.GetBytes(input)); + + private float EnsureNonExtremeLightness(float calculatedLightness) => + calculatedLightness < minLightness ? minLightness : calculatedLightness > maxLightness ? + maxLightness : calculatedLightness; + + private (byte r, byte g, byte b) HslToRgb(float h, float s, float l) + { + h /= 360; + float r, g, b; + + if (s == 0) + { + r = g = b = l; + } + else + { + float q = l < 0.5f ? l * (1 + s) : l + s - l * s; + float p = 2 * l - q; + + r = HueToRgb(p, q, h + 1.0f / 3.0f); + g = HueToRgb(p, q, h); + b = HueToRgb(p, q, h - 1.0f / 3.0f); + } + + return ((byte)(r * 255), (byte)(g * 255), (byte)(b * 255)); + } + + private float HueToRgb(float p, float q, float t) + { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1.0f / 6.0f) return p + (q - p) * 6 * t; + if (t < 1.0f / 2.0f) return q; + if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6; + return p; + } +}