diff --git a/Toolkit.Avalonia/FrameHandler.cs b/Toolkit.Avalonia/FrameHandler.cs index f855733..9a42b1f 100644 --- a/Toolkit.Avalonia/FrameHandler.cs +++ b/Toolkit.Avalonia/FrameHandler.cs @@ -111,28 +111,30 @@ public class FrameHandler : FrameNavigationOptions navigationOptions = new(); List postNavigateActions = []; - void CleanUp() + void CleanUp(int start, int end) { - foreach (PageStackEntry? entry in frame.BackStack) + int startIndex = Math.Max(0, start - 1); + int endIndex = Math.Min(frame.BackStack.Count - 1, end - 1); + + for (int i = endIndex; i >= startIndex; i--) { + PageStackEntry? entry = frame.BackStack[i]; if (entry.Context is Control control) { - if (control.DataContext is object content) + if (control.DataContext is IDisposable disposable) { - if (content is IDisposable disposable) - { - disposable.Dispose(); - } + disposable.Dispose(); } } - } - frame.BackStack.Clear(); + frame.BackStack.RemoveAt(i); + } } if (args.Parameters is not null) { - if (args.Parameters.TryGetValue("Transition", out object? transition)) + if (args.Parameters.TryGetValue("Transition", + out object? transition)) { switch ($"{transition}") { @@ -149,7 +151,8 @@ public class FrameHandler : } } - if (args.Parameters.TryGetValue("IsBackStackEnabled", out object? isBackStackEnabled)) + if (args.Parameters.TryGetValue("IsBackStackEnabled", + out object? isBackStackEnabled)) { if (isBackStackEnabled is bool value) { @@ -157,24 +160,49 @@ public class FrameHandler : } } - if (args.Parameters.TryGetValue("ClearBackStack", out object? clearBackStack)) + if (args.Parameters.TryGetValue("ClearBackStack", + out object? clearBackStack)) { - if (clearBackStack is bool value) + if (clearBackStack is bool clearBool) { - if (value) + if (clearBool) { - postNavigateActions.Add(() => CleanUp()); + postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count)); } } + + if (clearBackStack is string clearString) + { + if (clearString.StartsWith('[') && clearString.EndsWith(']') && + clearString.Contains('-')) + { + string range = clearString.Trim('[', ']'); + string[] parts = range.Split('-'); + + if (parts.Length == 2 && int.TryParse(parts[0], out int start) && + int.TryParse(parts[1], out int end)) + { + postNavigateActions.Add(() => CleanUp(start, end)); + } + else + { + postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count)); + } + } + else + { + postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count)); + } + } } } - foreach (Action postAction in postNavigateActions) - { - postAction.Invoke(); - } frame.NavigateFromObject(control, navigationOptions); + foreach (Action postAction in postNavigateActions) + { + postAction.Invoke(); + } } } diff --git a/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.cs b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.cs index 70a998b..8a2f9f7 100644 --- a/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.cs +++ b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPicture.cs @@ -42,7 +42,7 @@ public class PersonPicture : TemplatedControl private TextBlock? badgeNumberTextBlock; private Ellipse? badgingBackgroundEllipse; private Ellipse? badgingEllipse; - private PersonPictureColourGenerator colourGenerator = new(hue: 210, saturation: 0.8f, lightness: 0.6f); + private PersonPictureColourGenerator colourGenerator = new(); private string? displayNameInitials; private TextBlock? initialsTextBlock; @@ -339,7 +339,7 @@ public class PersonPicture : TemplatedControl if (DisplayName is { Length: > 0 }) { - Color rgb = colourGenerator.Create(DisplayName); + Color rgb = colourGenerator.GenerateColour(DisplayName); SetValue(BackgroundProperty, new SolidColorBrush(Color.FromArgb(rgb.A, rgb.R, rgb.G, rgb.B))); } diff --git a/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs index 0eca004..43c46f1 100644 --- a/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs +++ b/Toolkit.UI.Controls.Avalonia/PersonPicture/PersonPictureColourGenerator.cs @@ -6,70 +6,39 @@ 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; + private readonly string[] colours = + [ + "#FFB900", "#E81123", "#0078D7", "#0099BC", "#7A7574", + "#767676", "#FF8C00", "#E81123", "#0063B1", "#2D7D9A", + "#5D5A58", "#4C4A48", "#F7630C", "#EA005E", "#8E8CD8", + "#0078D7", "#68768A", "#69797E", "#CA5010", "#C30052", + "#6B69D6", "#038387", "#515C6B", "#4A5459", "#DA3B01", + "#E3008C", "#8764B8", "#00B294", "#567C73", "#647C64" + ]; - 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) + public Color GenerateColour(string input) { byte[] hashBytes = GetHash(input); + int colourIndex = BitConverter.ToInt32(hashBytes, 0) % colours.Length; + colourIndex = Math.Abs(colourIndex); - 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); + return HexToColour(colours[colourIndex]); } - 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) + private byte[] GetHash(string input) { - 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)); + return SHA256.HashData(Encoding.UTF8.GetBytes(input)); } - private float HueToRgb(float p, float q, float t) + private Color HexToColour(string hex) { - 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; + hex = hex.Replace("#", string.Empty); + + byte a = 255; + byte r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber); + byte g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber); + byte b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber); + + return Color.FromArgb(a, r, g, b); } }