From 9ddc790264b5e2ab4b4dcec1a6a545f5c703041b Mon Sep 17 00:00:00 2001 From: WantToBeeMe <93130991+WantToBeeMe@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:01:11 +0100 Subject: [PATCH 1/3] add meme number state --- WheelWizard/Views/App.axaml | 1 + .../MemeNumberState.axaml.cs | 165 ++++++++++++++++++ .../StandardLibrary/MemeNumberState.axaml | 88 ++++++++++ .../StandardLibrary/MemeNumberState.axaml.cs | 121 +++++++++++++ .../Components/StandardLibrary/StateBox.axaml | 16 +- .../StandardLibrary/StateBox.axaml.cs | 8 + WheelWizard/Views/Pages/RoomsPage.axaml | 8 +- WheelWizard/Views/Pages/RoomsPage.axaml.cs | 2 - WheelWizard/WheelWizard.csproj | 3 + 9 files changed, 401 insertions(+), 11 deletions(-) create mode 100644 WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs create mode 100644 WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml create mode 100644 WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml.cs diff --git a/WheelWizard/Views/App.axaml b/WheelWizard/Views/App.axaml index c8b10f02..65f76ef6 100644 --- a/WheelWizard/Views/App.axaml +++ b/WheelWizard/Views/App.axaml @@ -61,6 +61,7 @@ + diff --git a/WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs b/WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs new file mode 100644 index 00000000..b1fc0c8a --- /dev/null +++ b/WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs @@ -0,0 +1,165 @@ +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Media; +using Avalonia.Styling; + +namespace WheelWizard.Views.Components.BehaviorComponents; + +public class MemeNumberState : TemplatedControl +{ + private StateBox? _stateBox; + private FormFieldLabel? _niceLabel; + + public static readonly StyledProperty ValueProperty = AvaloniaProperty.Register(nameof(Value), "0"); + + public string Value + { + get => GetValue(ValueProperty); + set => SetValue(ValueProperty, value); + } + + public static readonly StyledProperty IconDataProperty = AvaloniaProperty.Register( + nameof(IconData) + ); + + public Geometry IconData + { + get => GetValue(IconDataProperty); + set => SetValue(IconDataProperty, value); + } + + public static readonly StyledProperty IconSizeProperty = AvaloniaProperty.Register( + nameof(IconSize), + 20 + ); + + public double IconSize + { + get => GetValue(IconSizeProperty); + set => SetValue(IconSizeProperty, value); + } + + public static readonly StyledProperty TipTextProperty = AvaloniaProperty.Register(nameof(TipText)); + + public string TipText + { + get => GetValue(TipTextProperty); + set => SetValue(TipTextProperty, value); + } + + public static readonly StyledProperty VariantProperty = AvaloniaProperty.Register< + MemeNumberState, + StateBox.StateBoxVariantType + >(nameof(Variant), StateBox.StateBoxVariantType.Default); + + public StateBox.StateBoxVariantType Variant + { + get => GetValue(VariantProperty); + set => SetValue(VariantProperty, value); + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + _stateBox = e.NameScope.Find("PART_StateBox"); + _niceLabel = e.NameScope.Find("PART_NiceLabel"); + + UpdateState(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == ValueProperty) + { + UpdateState(); + } + } + + private void UpdateState() + { + if (_stateBox == null || _niceLabel == null) + return; + + var val = Value; + + // Reset defaults + _niceLabel.IsVisible = false; + _stateBox.Content = null; + _stateBox.Text = val; // Always ensure text is set for normal cases + + if (val == "69") + { + _niceLabel.IsVisible = true; + } + else if (val == "67") + { + _stateBox.Content = CreateBobbingBadge(); + } + } + + private Control CreateBobbingBadge() + { + // 6 7 bobbing animation + var grid = new Grid { ColumnDefinitions = new ColumnDefinitions("Auto, Auto") }; + + var t6 = new TextBlock + { + Text = "6", + Foreground = Brushes.LightGoldenrodYellow, + FontWeight = FontWeight.Bold, + FontSize = 14, // Match StateBox default or bind it + VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, + }; + + var t7 = new TextBlock + { + Text = "7", + Foreground = Brushes.LightGoldenrodYellow, + FontWeight = FontWeight.Bold, + FontSize = 14, + VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, + }; + + // Add to grid + Grid.SetColumn(t6, 0); + Grid.SetColumn(t7, 1); + grid.Children.Add(t6); + grid.Children.Add(t7); + + // Animations + var anim6 = CreateBobAnimation(0); + var anim7 = CreateBobAnimation(0.5); // Phase shift + + anim6.RunAsync(t6); + anim7.RunAsync(t7); + + return grid; + } + + private Animation CreateBobAnimation(double delayRatio) + { + var animation = new Animation + { + Duration = TimeSpan.FromSeconds(1), + IterationCount = IterationCount.Infinite, + PlaybackDirection = PlaybackDirection.Alternate, + Delay = TimeSpan.FromSeconds(delayRatio), // Just initial offset, might not be perfect out of phase + }; + + // Keyframes: 0% -> 0, 100% -> -5 (up) + // Since it's Alternate, it will go 0 -> -5 -> 0 -> -5... + + var kf1 = new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(TranslateTransform.YProperty, 0d) } }; + + var kf2 = new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(TranslateTransform.YProperty, -4d) } }; + + animation.Children.Add(kf1); + animation.Children.Add(kf2); + + return animation; + } +} diff --git a/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml b/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml new file mode 100644 index 00000000..cd9f56e2 --- /dev/null +++ b/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml.cs b/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml.cs new file mode 100644 index 00000000..4dc62a87 --- /dev/null +++ b/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml.cs @@ -0,0 +1,121 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Media; + +namespace WheelWizard.Views.Components; + +public class MemeNumberState : TemplatedControl +{ + private StateBox? _stateBox; + private StateBox? _specialBadge; + private FormFieldLabel? _niceLabel; + + public static readonly StyledProperty TextProperty = AvaloniaProperty.Register(nameof(Text), "0"); + + public string Text + { + get => GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + public static readonly StyledProperty IconDataProperty = AvaloniaProperty.Register( + nameof(IconData) + ); + + public Geometry IconData + { + get => GetValue(IconDataProperty); + set => SetValue(IconDataProperty, value); + } + + public static readonly StyledProperty IconSizeProperty = AvaloniaProperty.Register( + nameof(IconSize), + 20 + ); + + public double IconSize + { + get => GetValue(IconSizeProperty); + set => SetValue(IconSizeProperty, value); + } + + public static readonly StyledProperty TipTextProperty = AvaloniaProperty.Register(nameof(TipText)); + + public string TipText + { + get => GetValue(TipTextProperty); + set => SetValue(TipTextProperty, value); + } + + public static readonly StyledProperty VariantProperty = AvaloniaProperty.Register< + MemeNumberState, + StateBox.StateBoxVariantType + >(nameof(Variant), StateBox.StateBoxVariantType.Default); + + public StateBox.StateBoxVariantType Variant + { + get => GetValue(VariantProperty); + set => SetValue(VariantProperty, value); + } + + public static readonly StyledProperty Enable67Property = AvaloniaProperty.Register(nameof(Enable67), true); + + public bool Enable67 + { + get => GetValue(Enable67Property); + set => SetValue(Enable67Property, value); + } + + public static readonly StyledProperty Enable69Property = AvaloniaProperty.Register(nameof(Enable69), true); + + public bool Enable69 + { + get => GetValue(Enable69Property); + set => SetValue(Enable69Property, value); + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + _stateBox = e.NameScope.Find("PART_StateBox"); + _specialBadge = e.NameScope.Find("PART_SpecialBadge"); + _niceLabel = e.NameScope.Find("PART_NiceLabel"); + + UpdateState(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == TextProperty) + { + UpdateState(); + } + } + + private void UpdateState() + { + if (_stateBox == null || _niceLabel == null || _specialBadge == null) + return; + + var val = Text; + + // Reset defaults + _niceLabel.IsVisible = false; + _stateBox.IsVisible = true; + _specialBadge.IsVisible = false; + + _stateBox.Text = val; // Always ensure text is set for normal cases + + if (val == "69" && Enable69) + { + _niceLabel.IsVisible = true; + } + else if (val == "67" && Enable67) + { + _stateBox.IsVisible = false; + _specialBadge.IsVisible = true; + } + } +} diff --git a/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml b/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml index 2e1b3e67..89a43018 100644 --- a/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml +++ b/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml @@ -30,7 +30,8 @@ ToolTip.Tip="{TemplateBinding TipText}" ToolTip.Placement="{TemplateBinding TipPlacement}" ToolTip.ShowDelay="20"> - + + @@ -38,15 +39,24 @@ Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center"/> + - + + FontWeight="Medium" VerticalAlignment="Center" + IsVisible="{TemplateBinding Content, Converter={x:Static ObjectConverters.IsNull}}"/> + + + diff --git a/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml.cs b/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml.cs index 8c3c2039..632ef21b 100644 --- a/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml.cs +++ b/WheelWizard/Views/Components/StandardLibrary/StateBox.axaml.cs @@ -41,6 +41,14 @@ public Geometry IconData set => SetValue(IconDataProperty, value); } + public static readonly StyledProperty ContentProperty = AvaloniaProperty.Register(nameof(Content)); + + public object? Content + { + get => GetValue(ContentProperty); + set => SetValue(ContentProperty, value); + } + public static readonly StyledProperty IconSizeProperty = AvaloniaProperty.Register(nameof(IconSize), 20); public double IconSize diff --git a/WheelWizard/Views/Pages/RoomsPage.axaml b/WheelWizard/Views/Pages/RoomsPage.axaml index 401423d0..292286a3 100644 --- a/WheelWizard/Views/Pages/RoomsPage.axaml +++ b/WheelWizard/Views/Pages/RoomsPage.axaml @@ -50,9 +50,7 @@ - - + @@ -126,9 +124,7 @@ - - + diff --git a/WheelWizard/Views/Pages/RoomsPage.axaml.cs b/WheelWizard/Views/Pages/RoomsPage.axaml.cs index 23b6ff2c..ea311f1d 100644 --- a/WheelWizard/Views/Pages/RoomsPage.axaml.cs +++ b/WheelWizard/Views/Pages/RoomsPage.axaml.cs @@ -61,7 +61,6 @@ public void OnUpdate(RepeatedTaskManager sender) foreach (var room in liveRooms.CurrentRooms) Rooms.Add(room); - RoomsNiceLabel.IsVisible = liveRooms.CurrentRooms.Count == 69; RoomsListItemCount.Text = liveRooms.CurrentRooms.Count.ToString(); PerformSearch(_searchQuery); } @@ -88,7 +87,6 @@ private void PerformSearch(string? query) foreach (var player in matchingPlayers) Players.Add(player); - PlayerNiceLabel.IsVisible = matchingPlayers.Count == 69; PlayerListItemCount.Text = matchingPlayers.Count.ToString(); } diff --git a/WheelWizard/WheelWizard.csproj b/WheelWizard/WheelWizard.csproj index 513ab804..4fbdcc10 100644 --- a/WheelWizard/WheelWizard.csproj +++ b/WheelWizard/WheelWizard.csproj @@ -115,6 +115,9 @@ EditorEmpty.axaml Code + + MemeNumberState.axaml + From 626d1e162838389fa0503fc7da2dad0729e23a09 Mon Sep 17 00:00:00 2001 From: WantToBeeMe <93130991+WantToBeeMe@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:06:23 +0100 Subject: [PATCH 2/3] organize logic --- .../StandardLibrary/MemeNumberState.axaml | 27 ++++++++++++++----- WheelWizard/Views/Pages/RoomsPage.axaml | 3 ++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml b/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml index cd9f56e2..4e6c7ec3 100644 --- a/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml +++ b/WheelWizard/Views/Components/StandardLibrary/MemeNumberState.axaml @@ -3,12 +3,27 @@ xmlns:components="clr-namespace:WheelWizard.Views.Components"> - - - - - + + + + + + + + + + + + + + + + + + + + @@ -54,7 +69,7 @@ Text="Nice!" x:Name="PART_NiceLabel" IsVisible="False" - VerticalAlignment="Center" /> + VerticalAlignment="Center" /> diff --git a/WheelWizard/Views/Pages/RoomsPage.axaml b/WheelWizard/Views/Pages/RoomsPage.axaml index 292286a3..2b0029b8 100644 --- a/WheelWizard/Views/Pages/RoomsPage.axaml +++ b/WheelWizard/Views/Pages/RoomsPage.axaml @@ -50,7 +50,8 @@ - + From e3bfd7e5572f69523a08108671ce53cb16cab54b Mon Sep 17 00:00:00 2001 From: WantToBeeMe <93130991+WantToBeeMe@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:08:17 +0100 Subject: [PATCH 3/3] remove unusedfile --- .../MemeNumberState.axaml.cs | 165 ------------------ 1 file changed, 165 deletions(-) delete mode 100644 WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs diff --git a/WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs b/WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs deleted file mode 100644 index b1fc0c8a..00000000 --- a/WheelWizard/Views/Components/BehaviorComponents/MemeNumberState.axaml.cs +++ /dev/null @@ -1,165 +0,0 @@ -using Avalonia; -using Avalonia.Animation; -using Avalonia.Animation.Easings; -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Media; -using Avalonia.Styling; - -namespace WheelWizard.Views.Components.BehaviorComponents; - -public class MemeNumberState : TemplatedControl -{ - private StateBox? _stateBox; - private FormFieldLabel? _niceLabel; - - public static readonly StyledProperty ValueProperty = AvaloniaProperty.Register(nameof(Value), "0"); - - public string Value - { - get => GetValue(ValueProperty); - set => SetValue(ValueProperty, value); - } - - public static readonly StyledProperty IconDataProperty = AvaloniaProperty.Register( - nameof(IconData) - ); - - public Geometry IconData - { - get => GetValue(IconDataProperty); - set => SetValue(IconDataProperty, value); - } - - public static readonly StyledProperty IconSizeProperty = AvaloniaProperty.Register( - nameof(IconSize), - 20 - ); - - public double IconSize - { - get => GetValue(IconSizeProperty); - set => SetValue(IconSizeProperty, value); - } - - public static readonly StyledProperty TipTextProperty = AvaloniaProperty.Register(nameof(TipText)); - - public string TipText - { - get => GetValue(TipTextProperty); - set => SetValue(TipTextProperty, value); - } - - public static readonly StyledProperty VariantProperty = AvaloniaProperty.Register< - MemeNumberState, - StateBox.StateBoxVariantType - >(nameof(Variant), StateBox.StateBoxVariantType.Default); - - public StateBox.StateBoxVariantType Variant - { - get => GetValue(VariantProperty); - set => SetValue(VariantProperty, value); - } - - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - _stateBox = e.NameScope.Find("PART_StateBox"); - _niceLabel = e.NameScope.Find("PART_NiceLabel"); - - UpdateState(); - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - if (change.Property == ValueProperty) - { - UpdateState(); - } - } - - private void UpdateState() - { - if (_stateBox == null || _niceLabel == null) - return; - - var val = Value; - - // Reset defaults - _niceLabel.IsVisible = false; - _stateBox.Content = null; - _stateBox.Text = val; // Always ensure text is set for normal cases - - if (val == "69") - { - _niceLabel.IsVisible = true; - } - else if (val == "67") - { - _stateBox.Content = CreateBobbingBadge(); - } - } - - private Control CreateBobbingBadge() - { - // 6 7 bobbing animation - var grid = new Grid { ColumnDefinitions = new ColumnDefinitions("Auto, Auto") }; - - var t6 = new TextBlock - { - Text = "6", - Foreground = Brushes.LightGoldenrodYellow, - FontWeight = FontWeight.Bold, - FontSize = 14, // Match StateBox default or bind it - VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, - }; - - var t7 = new TextBlock - { - Text = "7", - Foreground = Brushes.LightGoldenrodYellow, - FontWeight = FontWeight.Bold, - FontSize = 14, - VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, - }; - - // Add to grid - Grid.SetColumn(t6, 0); - Grid.SetColumn(t7, 1); - grid.Children.Add(t6); - grid.Children.Add(t7); - - // Animations - var anim6 = CreateBobAnimation(0); - var anim7 = CreateBobAnimation(0.5); // Phase shift - - anim6.RunAsync(t6); - anim7.RunAsync(t7); - - return grid; - } - - private Animation CreateBobAnimation(double delayRatio) - { - var animation = new Animation - { - Duration = TimeSpan.FromSeconds(1), - IterationCount = IterationCount.Infinite, - PlaybackDirection = PlaybackDirection.Alternate, - Delay = TimeSpan.FromSeconds(delayRatio), // Just initial offset, might not be perfect out of phase - }; - - // Keyframes: 0% -> 0, 100% -> -5 (up) - // Since it's Alternate, it will go 0 -> -5 -> 0 -> -5... - - var kf1 = new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(TranslateTransform.YProperty, 0d) } }; - - var kf2 = new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(TranslateTransform.YProperty, -4d) } }; - - animation.Children.Add(kf1); - animation.Children.Add(kf2); - - return animation; - } -}