Kaynağa Gözat

Added some update notifs and animations

Krzysztof Krysiński 4 ay önce
ebeveyn
işleme
ae7060dcd3

+ 62 - 0
src/PixiEditor/Helpers/Behaviours/ShowFlyoutOnTrigger.cs

@@ -0,0 +1,62 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Xaml.Interactivity;
+using PixiEditor.Helpers.UI;
+
+namespace PixiEditor.Helpers.Behaviours;
+
+internal class ShowFlyoutOnTrigger : Behavior<Button>
+{
+    public static readonly StyledProperty<ExecutionTrigger> TriggerProperty =
+        AvaloniaProperty.Register<ShowFlyoutOnTrigger, ExecutionTrigger>(
+            nameof(Trigger));
+
+    public ExecutionTrigger Trigger
+    {
+        get => GetValue(TriggerProperty);
+        set => SetValue(TriggerProperty, value);
+    }
+
+    static ShowFlyoutOnTrigger()
+    {
+        TriggerProperty.Changed.AddClassHandler<ShowFlyoutOnTrigger, ExecutionTrigger>(TriggerChanged);
+    }
+
+    protected override void OnAttached()
+    {
+        base.OnAttached();
+        if (Trigger != null)
+        {
+            Trigger.Triggered += OnTrigger;
+        }
+    }
+
+
+    protected override void OnDetaching()
+    {
+        base.OnDetaching();
+        if (Trigger != null)
+        {
+            Trigger.Triggered -= OnTrigger;
+        }
+    }
+
+    private void OnTrigger(object? sender, EventArgs e)
+    {
+        AssociatedObject?.Flyout?.ShowAt(AssociatedObject);
+    }
+
+    private static void TriggerChanged(ShowFlyoutOnTrigger sender, AvaloniaPropertyChangedEventArgs<ExecutionTrigger> e)
+    {
+        if (e.OldValue.Value != null)
+        {
+            e.OldValue.Value.Triggered -= sender.OnTrigger;
+        }
+
+        if (e.NewValue.Value != null)
+        {
+            e.NewValue.Value.Triggered += sender.OnTrigger;
+        }
+    }
+}

+ 11 - 0
src/PixiEditor/Helpers/UI/ExecutionTrigger.cs

@@ -1,8 +1,19 @@
 namespace PixiEditor.Helpers.UI;
 
+internal class ExecutionTrigger
+{
+    public event EventHandler Triggered;
+
+    public void Execute(object sender)
+    {
+        Triggered?.Invoke(sender, EventArgs.Empty);
+    }
+}
+
 internal class ExecutionTrigger<T>
 {
     public event EventHandler<T> Triggered;
+
     public void Execute(object sender, T args)
     {
         Triggered?.Invoke(sender, args);

+ 38 - 1
src/PixiEditor/ViewModels/Menu/MenuBarViewModel.cs

@@ -10,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Models.Commands.XAML;
 using PixiEditor.Extensions.Common.Localization;
 using PixiEditor.Extensions.UI;
+using PixiEditor.Helpers.UI;
 using PixiEditor.Models.Commands;
 using PixiEditor.OperatingSystem;
 using PixiEditor.ViewModels.SubViewModels;
@@ -25,6 +26,7 @@ internal class MenuBarViewModel : PixiObservableObject
     private AdditionalContentViewModel additionalContentViewModel;
     private UpdateViewModel updateViewModel;
     private UserViewModel userViewModel;
+    private ExecutionTrigger _openPixiEditorMenuTrigger;
 
     public AdditionalContentViewModel AdditionalContentSubViewModel
     {
@@ -47,6 +49,12 @@ internal class MenuBarViewModel : PixiObservableObject
     public ObservableCollection<MenuItem>? MenuEntries { get; set; }
     public NativeMenu? NativeMenu { get; private set; }
 
+    public ExecutionTrigger OpenPixiEditorMenuTrigger
+    {
+        get => _openPixiEditorMenuTrigger;
+        set => SetProperty(ref _openPixiEditorMenuTrigger, value);
+    }
+
     private Dictionary<string, MenuTreeItem> menuItems = new();
     private List<NativeMenuItem> nativeMenuItems;
 
@@ -62,11 +70,13 @@ internal class MenuBarViewModel : PixiObservableObject
         { "DEBUG", 1000 },
     };
 
-    public MenuBarViewModel(AdditionalContentViewModel? additionalContentSubViewModel, UpdateViewModel? updateViewModel, UserViewModel? userViewModel)
+    public MenuBarViewModel(AdditionalContentViewModel? additionalContentSubViewModel, UpdateViewModel? updateViewModel,
+        UserViewModel? userViewModel)
     {
         AdditionalContentSubViewModel = additionalContentSubViewModel;
         UpdateViewModel = updateViewModel;
         UserViewModel = userViewModel;
+        OpenPixiEditorMenuTrigger = new ExecutionTrigger();
     }
 
     public void Init(IServiceProvider serviceProvider, CommandController controller)
@@ -85,6 +95,33 @@ internal class MenuBarViewModel : PixiObservableObject
         }
 
         BuildMenu(controller, builders);
+
+        if (!UpdateViewModel.IsUpdateAvailable)
+        {
+            UpdateViewModel.PropertyChanged += UpdateViewModelChanged;
+        }
+        else
+        {
+            Dispatcher.UIThread.Post(() =>
+            {
+                OpenPixiEditorMenuTrigger.Execute(this);
+            });
+        }
+    }
+
+    private void UpdateViewModelChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
+    {
+        if (e.PropertyName == nameof(UpdateViewModel.IsUpdateAvailable))
+        {
+            Dispatcher.UIThread.Post(() =>
+            {
+                if (UpdateViewModel.IsUpdateAvailable)
+                {
+                    UpdateViewModel.PropertyChanged -= UpdateViewModelChanged;
+                    OpenPixiEditorMenuTrigger.Execute(this);
+                }
+            });
+        }
     }
 
     private int GetCategoryMultiplier(Commands_Command command)

+ 42 - 8
src/PixiEditor/Views/Auth/UserAvatarToggle.axaml

@@ -17,6 +17,37 @@
     </Design.DataContext>
 
     <Grid>
+        <Grid.Styles>
+            <Style Selector="Ellipse.pulse">
+                <Style.Animations>
+                    <Animation Duration="0:0:1" DelayBetweenIterations="0:0:5" IterationCount="60">
+                        <Animation.Easing>
+                            <CubicEaseInOut />
+                        </Animation.Easing>
+                        <KeyFrame Cue="0%">
+                            <Setter Property="ScaleTransform.ScaleX" Value="1" />
+                            <Setter Property="ScaleTransform.ScaleY" Value="1" />
+                        </KeyFrame>
+                        <KeyFrame Cue="25%">
+                            <Setter Property="ScaleTransform.ScaleX" Value="1.5" />
+                            <Setter Property="ScaleTransform.ScaleY" Value="1.5" />
+                        </KeyFrame>
+                        <KeyFrame Cue="50%">
+                            <Setter Property="ScaleTransform.ScaleX" Value="1" />
+                            <Setter Property="ScaleTransform.ScaleY" Value="1" />
+                        </KeyFrame>
+                        <KeyFrame Cue="75%">
+                            <Setter Property="ScaleTransform.ScaleX" Value="1.5" />
+                            <Setter Property="ScaleTransform.ScaleY" Value="1.5" />
+                        </KeyFrame>
+                        <KeyFrame Cue="100%">
+                            <Setter Property="ScaleTransform.ScaleX" Value="1" />
+                            <Setter Property="ScaleTransform.ScaleY" Value="1" />
+                        </KeyFrame>
+                    </Animation>
+                </Style.Animations>
+            </Style>
+        </Grid.Styles>
         <Border ClipToBounds="True" IsVisible="{Binding IsLoggedIn}" CornerRadius="25">
             <Button Name="UserAvatarButton" Padding="0"
                     BorderThickness="0" Classes="pixi-icon">
@@ -133,16 +164,19 @@
         </Border>
 
         <Ellipse IsVisible="{Binding AnyUpdateAvailable}"
-                   ClipToBounds="False"
-                   Width="12" Height="12"
-                   HorizontalAlignment="Right"
-                   VerticalAlignment="Bottom"
-                   StrokeThickness="2"
-                   Stroke="{DynamicResource ThemeBackgroundBrush}"
-                   Fill="{DynamicResource ThemeAccent3Brush}" />
+                 IsHitTestVisible="False"
+                 ClipToBounds="False"
+                 Classes="pulse"
+                 Width="12" Height="12"
+                 HorizontalAlignment="Right"
+                 VerticalAlignment="Bottom"
+                 StrokeThickness="2"
+                 Stroke="{DynamicResource ThemeBackgroundBrush}"
+                 Fill="{DynamicResource ThemeAccent3Brush}">
+        </Ellipse>
         <Button IsVisible="{Binding !IsLoggedIn}"
                 Classes="pixi-icon"
                 Content="{DynamicResource icon-user}"
                 Command="{xaml:Command Name=PixiEditor.Window.OpenAccountWindow}" />
-    </Grid>
+        </Grid>
 </UserControl>

+ 37 - 3
src/PixiEditor/Views/Main/MainTitleBar.axaml

@@ -12,6 +12,7 @@
              xmlns:main="clr-namespace:PixiEditor.Views.Main"
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:auth="clr-namespace:PixiEditor.Views.Auth"
+             xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:DataType="menu:MenuBarViewModel"
              x:Class="PixiEditor.Views.Main.MainTitleBar">
@@ -22,12 +23,13 @@
         <dialogs:DialogTitleBar
             DockPanel.Dock="Top">
             <dialogs:DialogTitleBar.AdditionalElement>
-                <StackPanel Margin="5 0" Spacing="5" Orientation="Horizontal" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=main:MainTitleBar}}">
+                <StackPanel Margin="5 0" Spacing="5" Orientation="Horizontal"
+                            DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=main:MainTitleBar}}">
                     <Border BorderThickness="1" BorderBrush="{DynamicResource AccentColor}"
                             Padding="5 0" CornerRadius="5" Height="25"
                             IsVisible="{Binding Path=AdditionalContentSubViewModel.IsFoundersPackAvailable, FallbackValue=False}">
                         <TextBlock VerticalAlignment="Center"
-                                   ui:Translator.Key="PixiEditor.SupporterPack:AWESOME_SUPPORTER" />
+                                   ui:Translator.Key="PixiEditor.FoundersPack:AWESOME_SUPPORTER" />
                     </Border>
                     <auth:UserAvatarToggle Width="26" Height="26" DataContext="{Binding Path=UserViewModel}" />
                 </StackPanel>
@@ -46,6 +48,9 @@
                 </OnPlatform>
             </Panel.Margin>
             <ToggleButton Name="LogoButton" Padding="0" BorderThickness="0">
+                <Interaction.Behaviors>
+                    <behaviours:ShowFlyoutOnTrigger Trigger="{Binding OpenPixiEditorMenuTrigger}" />
+                </Interaction.Behaviors>
                 <ToggleButton.Background>
                     <VisualBrush>
                         <VisualBrush.Visual>
@@ -82,9 +87,38 @@
             <Panel ClipToBounds="False" Margin="10, 10, 0, 0"
                    IsVisible="{Binding UpdateViewModel.SelfUpdatingAvailable}"
                    IsHitTestVisible="False" VerticalAlignment="Bottom" HorizontalAlignment="Right">
+                <Panel.Styles>
+                    <Style Selector="TextBlock.pulse">
+                        <Style.Animations>
+                            <Animation Duration="0:0:1" DelayBetweenIterations="0:0:2.5" IterationCount="60">
+                                <Animation.Easing>
+                                    <CubicEaseInOut />
+                                </Animation.Easing>
+                                <KeyFrame Cue="0%">
+                                    <Setter Property="ScaleTransform.ScaleX" Value="1" />
+                                    <Setter Property="ScaleTransform.ScaleY" Value="1" />
+                                    <Setter Property="RotateTransform.Angle" Value="0" />
+                                </KeyFrame>
+                                <KeyFrame Cue="50%">
+                                    <Setter Property="ScaleTransform.ScaleX" Value="1.5" />
+                                    <Setter Property="ScaleTransform.ScaleY" Value="1.5" />
+                                    <Setter Property="RotateTransform.Angle" Value="45" />
+                                </KeyFrame>
+                                <KeyFrame Cue="75%">
+                                    <Setter Property="RotateTransform.Angle" Value="-45" />
+                                </KeyFrame>
+                                <KeyFrame Cue="100%">
+                                    <Setter Property="ScaleTransform.ScaleX" Value="1" />
+                                    <Setter Property="ScaleTransform.ScaleY" Value="1" />
+                                    <Setter Property="RotateTransform.Angle" Value="0" />
+                                </KeyFrame>
+                            </Animation>
+                        </Style.Animations>
+                    </Style>
+                </Panel.Styles>
                 <TextBlock Text="!" IsVisible="{Binding UpdateViewModel.IsUpdateAvailable}"
                            ClipToBounds="False"
-                           FontWeight="SemiBold"
+                           FontWeight="SemiBold" Classes="pulse"
                            Foreground="Yellow" FontSize="18" />
                 <TextBlock Text="{DynamicResource icon-settings}"
                            ClipToBounds="False"