diff --git a/FasdDesktopUi/Basics/UserControls/Badge.xaml b/FasdDesktopUi/Basics/UserControls/Badge.xaml index c85f5f4..10b98b4 100644 --- a/FasdDesktopUi/Basics/UserControls/Badge.xaml +++ b/FasdDesktopUi/Basics/UserControls/Badge.xaml @@ -3,25 +3,70 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:FasdDesktopUi.Basics.UserControls" - xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon" mc:Ignorable="d" d:DesignHeight="20" d:DesignWidth="40" - x:Name="BadgeControl"> + x:Name="BadgeControl" + Loaded="BadgeControl_Loaded" + Unloaded="BadgeControl_Unloaded"> - + + + + + + - - - + + + + + + + + - + + + + + + + + + diff --git a/FasdDesktopUi/Basics/UserControls/Badge.xaml.cs b/FasdDesktopUi/Basics/UserControls/Badge.xaml.cs index 8c095aa..2eb9e0c 100644 --- a/FasdDesktopUi/Basics/UserControls/Badge.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/Badge.xaml.cs @@ -1,10 +1,16 @@ -using System.Windows; +using System; +using System.Windows; using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Animation; namespace FasdDesktopUi.Basics.UserControls { public partial class Badge : UserControl { + private readonly Storyboard _sparkleStoryboard; + private const double SparkleBaseScale = 0.6; + public string Text { get { return (string)GetValue(TextProperty); } @@ -14,10 +20,118 @@ namespace FasdDesktopUi.Basics.UserControls public static readonly DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(Badge), new PropertyMetadata("Beta")); + public bool IsSparkleEnabled + { + get { return (bool)GetValue(IsSparkleEnabledProperty); } + set { SetValue(IsSparkleEnabledProperty, value); } + } + + public static readonly DependencyProperty IsSparkleEnabledProperty = + DependencyProperty.Register(nameof(IsSparkleEnabled), typeof(bool), typeof(Badge), new PropertyMetadata(false, OnIsSparkleEnabledChanged)); + public Badge() { InitializeComponent(); + _sparkleStoryboard = CreateSparkleStoryboard(); + UpdateSparkleState(); + } + + private static void OnIsSparkleEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = d as Badge; + control?.UpdateSparkleState(); + } + + private void BadgeControl_Loaded(object sender, RoutedEventArgs e) + { + UpdateSparkleState(); + } + + private void BadgeControl_Unloaded(object sender, RoutedEventArgs e) + { + StopSparkles(); + } + + private void UpdateSparkleState() + { + if (SparkleCanvas == null || _sparkleStoryboard == null) + { + return; + } + + if (IsSparkleEnabled) + { + SparkleCanvas.Visibility = Visibility.Visible; + _sparkleStoryboard.Begin(this, true); + return; + } + + SparkleCanvas.Visibility = Visibility.Collapsed; + StopSparkles(); + } + + private void StopSparkles() + { + _sparkleStoryboard?.Stop(this); + + if (SparkleTopRight != null) + { + SparkleTopRight.Opacity = 0; + if (SparkleTopRight.RenderTransform is ScaleTransform topTransform) + { + topTransform.ScaleX = SparkleBaseScale; + topTransform.ScaleY = SparkleBaseScale; + } + } + + if (SparkleBottomLeft != null) + { + SparkleBottomLeft.Opacity = 0; + if (SparkleBottomLeft.RenderTransform is ScaleTransform bottomTransform) + { + bottomTransform.ScaleX = SparkleBaseScale; + bottomTransform.ScaleY = SparkleBaseScale; + } + } + } + + private Storyboard CreateSparkleStoryboard() + { + var storyboard = new Storyboard + { + RepeatBehavior = RepeatBehavior.Forever + }; + + AddKeyFrames(storyboard, SparkleTopRight, "Opacity", + (0.00, 0.0), (0.18, 1.0), (0.42, 0.0), (2.20, 0.0)); + AddKeyFrames(storyboard, SparkleTopRight, "(UIElement.RenderTransform).(ScaleTransform.ScaleX)", + (0.00, SparkleBaseScale), (0.22, 1.15), (0.42, SparkleBaseScale), (2.20, SparkleBaseScale)); + AddKeyFrames(storyboard, SparkleTopRight, "(UIElement.RenderTransform).(ScaleTransform.ScaleY)", + (0.00, SparkleBaseScale), (0.22, 1.15), (0.42, SparkleBaseScale), (2.20, SparkleBaseScale)); + + AddKeyFrames(storyboard, SparkleBottomLeft, "Opacity", + (0.00, 0.0), (1.00, 0.0), (1.18, 1.0), (1.42, 0.0), (2.20, 0.0)); + AddKeyFrames(storyboard, SparkleBottomLeft, "(UIElement.RenderTransform).(ScaleTransform.ScaleX)", + (0.00, SparkleBaseScale), (1.00, SparkleBaseScale), (1.22, 1.15), (1.42, SparkleBaseScale), (2.20, SparkleBaseScale)); + AddKeyFrames(storyboard, SparkleBottomLeft, "(UIElement.RenderTransform).(ScaleTransform.ScaleY)", + (0.00, SparkleBaseScale), (1.00, SparkleBaseScale), (1.22, 1.15), (1.42, SparkleBaseScale), (2.20, SparkleBaseScale)); + + return storyboard; + } + + private static void AddKeyFrames(Storyboard storyboard, DependencyObject target, string targetProperty, params (double TimeSeconds, double Value)[] frames) + { + var animation = new DoubleAnimationUsingKeyFrames(); + + foreach (var frame in frames) + { + animation.KeyFrames.Add(new LinearDoubleKeyFrame(frame.Value, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(frame.TimeSeconds)))); + } + + Storyboard.SetTarget(animation, target); + Storyboard.SetTargetProperty(animation, new PropertyPath(targetProperty)); + storyboard.Children.Add(animation); } } } diff --git a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml index c4a2144..f63532e 100644 --- a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml +++ b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml @@ -120,6 +120,7 @@ FontWeight="Bold" Visibility="Visible" />