Selaa lähdekoodia

Shit is compiling

Krzysztof Krysiński 2 vuotta sitten
vanhempi
commit
b0dc8c57bb
20 muutettua tiedostoa jossa 155 lisäystä ja 186 poistoa
  1. 0 1
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI.Browser/Program.cs
  2. 40 0
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Helpers/Extensions/LinqExtensions.cs
  3. 23 0
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Helpers/Extensions/MethodExtension.cs
  4. 33 11
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/CommandController.cs
  5. 6 5
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/CommandMethods.cs
  6. 8 0
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Commands/Command.cs
  7. 0 23
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/CanExecuteAsyncEvaluator.cs
  8. 2 1
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/CanExecuteEvaluator.cs
  9. 1 0
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/Evaluator.cs
  10. 2 1
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/IconEvaluator.cs
  11. 2 1
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/XAML/Command.cs
  12. 10 6
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/XAML/Menu.cs
  13. 12 133
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/PixiEditor.AvaloniaUI.csproj
  14. 5 0
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/ViewModels/SubViewModels/ClipboardViewModel.cs
  15. 1 1
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Views/Main/MainTitleBar.axaml
  16. 5 0
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Views/MainView.axaml
  17. 3 3
      src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Views/Windows/HelloTherePopup.axaml
  18. 1 0
      src/PixiEditor.UI.Common/Accents/Base.axaml
  19. 0 0
      src/PixiEditor.UI.Common/Fonts/feather.ttf
  20. 1 0
      src/PixiEditor.UI.Common/PixiEditor.UI.Common.csproj

+ 0 - 1
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI.Browser/Program.cs

@@ -2,7 +2,6 @@
 using System.Threading.Tasks;
 using Avalonia;
 using Avalonia.Browser;
-using PixiEditor.Avalonia;
 using PixiEditor.AvaloniaUI;
 
 [assembly: SupportedOSPlatform("browser")]

+ 40 - 0
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Helpers/Extensions/LinqExtensions.cs

@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace PixiEditor.AvaloniaUI.Helpers.Extensions;
+
+public static class LinqExtensions
+{
+    // This is for async predicates with either a sync or async source.
+    // This is the only one you need for your example
+    public static async Task<bool> AllAsync<TSource>(this IEnumerable<TSource> source, Func<TSource, Task<bool>> predicate)
+    {
+        if (source == null)
+            throw new ArgumentNullException(nameof(source));
+        if (predicate == null)
+            throw new ArgumentNullException(nameof(predicate));
+        foreach (var item in source)
+        {
+            var result = await predicate(item);
+            if (!result)
+                return false;
+        }
+        return true;
+    }
+
+    // This is for synchronous predicates with an async source.
+    public static async Task<bool> AllAsync<TSource>(this IEnumerable<Task<TSource>> source, Func<TSource, bool> predicate)
+    {
+        if (source == null)
+            throw new ArgumentNullException(nameof(source));
+        if (predicate == null)
+            throw new ArgumentNullException(nameof(predicate));
+        foreach (var item in source)
+        {
+            var awaitedItem = await item;
+            if (!predicate(awaitedItem))
+                return false;
+        }
+        return true;
+    }
+}

+ 23 - 0
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Helpers/Extensions/MethodExtension.cs

@@ -0,0 +1,23 @@
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Threading;
+
+namespace PixiEditor.AvaloniaUI.Helpers.Extensions;
+
+public static class MethodExtension
+{
+    public static async Task<T> InvokeAsync<T>(this MethodInfo @this, object obj, params object[] parameters)
+    {
+        //TODO: uhh, make sure this is ok?
+        Dispatcher.UIThread.InvokeAsync(async () => await Task.Run(async () =>
+        {
+            var task = (Task)@this.Invoke(obj, parameters);
+            await task.ConfigureAwait(false);
+            var resultProperty = task.GetType().GetProperty("Result");
+            return (T)resultProperty.GetValue(task);
+        }));
+
+        return default;
+    }
+}

+ 33 - 11
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/CommandController.cs

@@ -5,8 +5,10 @@ using System.Reflection;
 using System.Threading.Tasks;
 using Avalonia.Media;
 using Avalonia.Media.Imaging;
+using Avalonia.Threading;
 using Microsoft.Extensions.DependencyInjection;
 using Newtonsoft.Json;
+using PixiEditor.AvaloniaUI.Helpers.Extensions;
 using PixiEditor.AvaloniaUI.Models.Commands.Attributes.Evaluators;
 using PixiEditor.AvaloniaUI.Models.Commands.Commands;
 using PixiEditor.AvaloniaUI.Models.Commands.Evaluators;
@@ -360,7 +362,8 @@ internal class CommandController
             where T : Evaluator<TParameter>, new()
             where TAttr : Evaluator.EvaluatorAttribute
         {
-            if (!method.ReturnType.IsAssignableFrom(typeof(TParameter)) && !IsAssignaleAsync<TAttr, T, TParameter>(method))
+            bool isAssignableAsync = IsAssignaleAsync<TAttr, T, TParameter>(method);
+            if (!method.ReturnType.IsAssignableFrom(typeof(TParameter)) && !isAssignableAsync)
             {
                 throw new Exception(
                     $"Invalid return type for the CanExecute evaluator '{attribute.Name}' at {method.ReflectedType.FullName}.{method.Name}\nExpected '{typeof(TParameter).FullName}'");
@@ -378,21 +381,41 @@ internal class CommandController
 
             var parameters = method.GetParameters();
 
-            Func<object, TParameter> func;
-
-            if (parameters.Length == 1)
+            if (!isAssignableAsync)
             {
-                func = x => (TParameter)method.Invoke(serviceInstance,
-                    new[] { CastParameter(x, parameters[0].ParameterType) });
+                Func<object, TParameter> func;
+
+                if (parameters.Length == 1)
+                {
+                    func = x => (TParameter)method.Invoke(serviceInstance,
+                        new[] { CastParameter(x, parameters[0].ParameterType) });
+                }
+                else
+                {
+                    func = x => (TParameter)method.Invoke(serviceInstance, null);
+                }
+
+                T evaluator = factory(func);
+                evaluators.Add(evaluator.Name, evaluator);
             }
             else
             {
-                func = x => (TParameter)method.Invoke(serviceInstance, null);
+                Func<object, Task<TParameter>> func;
+                if (parameters.Length == 1)
+                {
+                    func = async x => await method.InvokeAsync<TParameter>(serviceInstance,
+                        new[] { CastParameter(x, parameters[0].ParameterType) });
+                }
+                else
+                {
+                    func = async x => await method.InvokeAsync<TParameter>(serviceInstance, null);
+                }
+
+                T evaluator = factory(x => Task.Run(async () => await func(x)).Result);//TODO: This is not truly async
+                evaluators.Add(evaluator.Name, evaluator);
             }
 
-            T evaluator = factory(func);
 
-            evaluators.Add(evaluator.Name, evaluator);
         }
 
         void AddEvaluator<TAttr, T, TParameter>(MethodInfo method, object instance, TAttr attribute,
@@ -424,7 +447,6 @@ internal class CommandController
                                         canExecuteAttribute.NamesOfRequiredCanExecuteEvaluators.Select(x =>
                                             controller.CanExecuteEvaluators[x]);
 
-                                bool isAsync = methodInfo.ReturnType == typeof(Task<bool>);
                                 AddEvaluatorFactory<Evaluator.CanExecuteAttribute, CanExecuteEvaluator, bool>(
                                     methodInfo,
                                     serviceProvider.GetService(type.Key),
@@ -437,7 +459,7 @@ internal class CommandController
                                             evaluateFunction.Invoke(evaluateFunctionArgument) &&
                                             getRequiredEvaluatorsObjectsOfCurrentEvaluator.Invoke(this).All(
                                                 requiredEvaluator =>
-                                                    requiredEvaluator.CallEvaluate(null, evaluateFunctionArgument))
+                                                    requiredEvaluator.CallEvaluate(null, evaluateFunctionArgument)),
                                     });
                                 break;
                             }

+ 6 - 5
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/CommandMethods.cs

@@ -1,4 +1,5 @@
-using PixiEditor.AvaloniaUI.Models.Commands.Commands;
+using System.Threading.Tasks;
+using PixiEditor.AvaloniaUI.Models.Commands.Commands;
 using PixiEditor.AvaloniaUI.Models.Commands.Evaluators;
 
 namespace PixiEditor.AvaloniaUI.Models.Commands;
@@ -6,21 +7,21 @@ namespace PixiEditor.AvaloniaUI.Models.Commands;
 internal class CommandMethods
 {
     private readonly Command _command;
-    private readonly Action<object> _execute;
+    private readonly Func<object, Task> _execute;
     private readonly CanExecuteEvaluator _canExecute;
 
-    public CommandMethods(Command command, Action<object> execute, CanExecuteEvaluator canExecute)
+    public CommandMethods(Command command, Func<object, Task> execute, CanExecuteEvaluator canExecute)
     {
         _execute = execute;
         _canExecute = canExecute;
         _command = command;
     }
 
-    public void Execute(object parameter)
+    public async Task Execute(object parameter)
     {
         if (CanExecute(parameter))
         {
-            _execute(parameter);
+            await _execute(parameter);
         }
     }
 

+ 8 - 0
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Commands/Command.cs

@@ -1,4 +1,5 @@
 using System.Diagnostics;
+using System.Threading.Tasks;
 using Avalonia.Media;
 using CommunityToolkit.Mvvm.ComponentModel;
 using PixiEditor.AvaloniaUI.Models.Commands.Evaluators;
@@ -46,6 +47,13 @@ internal abstract partial class Command : ObservableObject
     public abstract object GetParameter();
 
     protected Command(Action<object> onExecute, CanExecuteEvaluator canExecute)
+    {
+        Methods = new(this, (_) => Task.FromResult(onExecute), canExecute);
+        ILocalizationProvider.Current.OnLanguageChanged += OnLanguageChanged;
+        /*InputLanguageManager.Current.InputLanguageChanged += (_, _) => this.OnPropertyChanged(nameof(Shortcut)); TODO: Didn't find implementation of this in Avalonia*/
+    }
+
+    protected Command(Func<object, Task> onExecute, CanExecuteEvaluator canExecute)
     {
         Methods = new(this, onExecute, canExecute);
         ILocalizationProvider.Current.OnLanguageChanged += OnLanguageChanged;

+ 0 - 23
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/CanExecuteAsyncEvaluator.cs

@@ -1,23 +0,0 @@
-using System.Threading.Tasks;
-using PixiEditor.AvaloniaUI.Models.Commands.Commands;
-
-namespace PixiEditor.AvaloniaUI.Models.Commands.Evaluators;
-
-internal class CanExecuteAsyncEvaluator : Evaluator<Task<bool>>
-{
-    public static CanExecuteAsyncEvaluator AlwaysTrue { get; } = new StaticAsyncValueEvaluator(true);
-
-    public static CanExecuteAsyncEvaluator AlwaysFalse { get; } = new StaticAsyncValueEvaluator(false);
-
-    private class StaticAsyncValueEvaluator : CanExecuteAsyncEvaluator
-    {
-        private readonly bool value;
-
-        public StaticAsyncValueEvaluator(bool value)
-        {
-            this.value = value;
-        }
-
-        public override Task<bool> CallEvaluate(Command command, object parameter) => Task.FromResult(value);
-    }
-}

+ 2 - 1
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/CanExecuteEvaluator.cs

@@ -1,4 +1,5 @@
-using PixiEditor.AvaloniaUI.Models.Commands.Commands;
+using System.Threading.Tasks;
+using PixiEditor.AvaloniaUI.Models.Commands.Commands;
 
 namespace PixiEditor.AvaloniaUI.Models.Commands.Evaluators;
 

+ 1 - 0
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/Evaluator.cs

@@ -1,4 +1,5 @@
 using System.Diagnostics;
+using System.Threading.Tasks;
 using PixiEditor.AvaloniaUI.Models.Commands.Commands;
 
 namespace PixiEditor.AvaloniaUI.Models.Commands.Evaluators;

+ 2 - 1
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/Evaluators/IconEvaluator.cs

@@ -4,6 +4,7 @@ using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Reflection;
+using System.Threading.Tasks;
 using Avalonia.Media;
 using Avalonia.Media.Imaging;
 using PixiEditor.AvaloniaUI.Models.Commands.Commands;
@@ -58,7 +59,7 @@ internal class IconEvaluator : Evaluator<IImage>
 
         public static Dictionary<string, Bitmap> images = new();
 
-        public override Bitmap CallEvaluate(Command command, object parameter)
+        public override IImage CallEvaluate(Command command, object parameter)
         {
             string path = GetDefaultPath(command);
 

+ 2 - 1
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/XAML/Command.cs

@@ -1,4 +1,5 @@
-using System.Windows.Input;
+using System.Threading.Tasks;
+using System.Windows.Input;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
 using PixiEditor.AvaloniaUI.Helpers;

+ 10 - 6
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Models/Commands/XAML/Menu.cs

@@ -1,4 +1,5 @@
-using Avalonia;
+using System.Threading.Tasks;
+using Avalonia;
 using Avalonia.Controls;
 using PixiEditor.AvaloniaUI.Helpers;
 using PixiEditor.AvaloniaUI.Models.Input;
@@ -19,7 +20,7 @@ internal class Menu : global::Avalonia.Controls.Menu
     public static string GetCommand(MenuItem menu) => (string)menu.GetValue(CommandProperty);
     public static void SetCommand(MenuItem menu, string value) => menu.SetValue(CommandProperty, value);
 
-    public static void CommandChanged(AvaloniaPropertyChangedEventArgs e)
+    public static async void CommandChanged(AvaloniaPropertyChangedEventArgs e) //TODO: Validate async void works
     {
         if (e.NewValue is not string value || e.Sender is not MenuItem item)
         {
@@ -34,18 +35,21 @@ internal class Menu : global::Avalonia.Controls.Menu
 
         var command = CommandController.Current.Commands[value];
 
+        bool canExecute = command.CanExecute();
+
         var icon = new Image
         {
-            Source = command.GetIcon(), 
+            Source = command.GetIcon(),
             Width = IconDimensions, Height = IconDimensions,
-            Opacity = command.CanExecute() ? 1 : 0.75
+            Opacity = canExecute ? 1 : 0.75
         };
 
-        icon.PropertyChanged += (sender, args) =>
+        icon.PropertyChanged += async (sender, args) =>
         {
+            bool canExecute = command.CanExecute();
             if (args.Property.Name == nameof(icon.IsVisible))
             {
-                icon.Opacity = command.CanExecute() ? 1 : 0.75;
+                icon.Opacity = canExecute ? 1 : 0.75;
             }
         };
 

+ 12 - 133
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/PixiEditor.AvaloniaUI.csproj

@@ -12,6 +12,12 @@
       <AvaloniaResource Include="Assets\**" />
       <AvaloniaResource Include="Data\**" />
       <AvaloniaResource Include="Data\Languages\**" />
+      <None Remove="Images\Create-mask.svg" />
+      <AvaloniaResource Include="Images\Create-mask.svg" />
+      <None Remove="Images\Lock-alpha.svg" />
+      <AvaloniaResource Include="Images\Lock-alpha.svg" />
+      <None Remove="Images\Merge-downwards.svg" />
+      <AvaloniaResource Include="Images\Merge-downwards.svg" />
     </ItemGroup>
 
     <ItemGroup>
@@ -59,139 +65,12 @@
     </ItemGroup>
   
     <ItemGroup>
-      <Resource Include="Images\Add-reference.png" />
-      <Resource Include="Images\AnchorDot.png" />
-      <Resource Include="Images\Arrow-right.png" />
-      <Resource Include="Images\Check-square.png" />
-      <Resource Include="Images\CheckerTile.png" />
-      <Resource Include="Images\Chevron-right.png" />
-      <Resource Include="Images\ChevronDown.png" />
-      <Resource Include="Images\ChevronsDown.png" />
-      <Resource Include="Images\Commands\PixiEditor\Clipboard\Copy.png" />
-      <Resource Include="Images\Commands\PixiEditor\Clipboard\Cut.png" />
-      <Resource Include="Images\Commands\PixiEditor\Clipboard\Paste.png" />
-      <Resource Include="Images\Commands\PixiEditor\Clipboard\PasteAsNewLayer.png" />
-      <Resource Include="Images\Commands\PixiEditor\Clipboard\PasteReferenceLayer.png" />
-      <Resource Include="Images\Commands\PixiEditor\Colors\Swap.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\CenterContent.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\ResizeCanvas.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\ResizeDocument.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\Rotate180Deg.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\Rotate180DegLayers.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\Rotate270Deg.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\Rotate270DegLayers.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\Rotate90Deg.png" />
-      <Resource Include="Images\Commands\PixiEditor\Document\Rotate90DegLayers.png" />
-      <Resource Include="Images\Commands\PixiEditor\File\Export.png" />
-      <Resource Include="Images\Commands\PixiEditor\File\New.png" />
-      <Resource Include="Images\Commands\PixiEditor\File\Open.png" />
-      <Resource Include="Images\Commands\PixiEditor\File\OpenFileFromClipboard.png" />
-      <Resource Include="Images\Commands\PixiEditor\Layer\DuplicateSelectedLayer.png" />
-      <Resource Include="Images\Commands\PixiEditor\Layer\ToggleMask.png" />
-      <Resource Include="Images\Commands\PixiEditor\Layer\ToggleVisible.png" />
-      <Resource Include="Images\Commands\PixiEditor\Links\OpenDocumentation.png" />
-      <Resource Include="Images\Commands\PixiEditor\Links\OpenRepository.png" />
-      <Resource Include="Images\Commands\PixiEditor\Search\Toggle.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\AddToMask.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\Clear.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\CropToSelection.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\IntersectSelectionMask.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\InvertSelection.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\NewToMask.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\SelectAll.png" />
-      <Resource Include="Images\Commands\PixiEditor\Selection\SubtractFromMask.png" />
-      <Resource Include="Images\Commands\PixiEditor\View\ToggleGrid.png" />
-      <Resource Include="Images\Commands\PixiEditor\View\ZoomIn.png" />
-      <Resource Include="Images\Commands\PixiEditor\View\ZoomOut.png" />
-      <Resource Include="Images\Commands\PixiEditor\Window\OpenAboutWindow.png" />
-      <Resource Include="Images\Commands\PixiEditor\Window\OpenNavigationWindow.png" />
-      <Resource Include="Images\Commands\PixiEditor\Window\OpenSettingsWindow.png" />
-      <Resource Include="Images\Commands\PixiEditor\Window\OpenShortcutWindow.png" />
-      <Resource Include="Images\Commands\PixiEditor\Window\OpenStartupWindow.png" />
-      <Resource Include="Images\CopyAdd.png" />
-      <Resource Include="Images\Create-mask.png" />
-      <Resource Include="Images\Crop.png" />
-      <Resource Include="Images\Database.png" />
-      <Resource Include="Images\DiagonalRed.png" />
-      <Resource Include="Images\Download.png" />
-      <Resource Include="Images\Edit.png" />
-      <Resource Include="Images\Eye-off.png" />
-      <Resource Include="Images\Eye.png" />
-      <Resource Include="Images\FlipHorizontal.png" />
-      <Resource Include="Images\FlipVertical.png" />
-      <Resource Include="Images\Folder-add.png" />
-      <Resource Include="Images\Folder.png" />
-      <Resource Include="Images\Globe.png" />
-      <Resource Include="Images\hard-drive.png" />
-      <Resource Include="Images\LanguageFlags\ar.png" />
-      <Resource Include="Images\LanguageFlags\cs.png" />
-      <Resource Include="Images\LanguageFlags\de.png" />
-      <Resource Include="Images\LanguageFlags\en.png" />
-      <Resource Include="Images\LanguageFlags\es.png" />
-      <Resource Include="Images\LanguageFlags\hu.png" />
-      <Resource Include="Images\LanguageFlags\it.png" />
-      <Resource Include="Images\LanguageFlags\pl.png" />
-      <Resource Include="Images\LanguageFlags\pt-br.png" />
-      <Resource Include="Images\LanguageFlags\ru.png" />
-      <Resource Include="Images\LanguageFlags\tr.png" />
-      <Resource Include="Images\LanguageFlags\uk.png" />
-      <Resource Include="Images\LanguageFlags\zh.png" />
-      <Resource Include="Images\Layer-add.png" />
-      <Resource Include="Images\Layout.png" />
-      <Resource Include="Images\Load.png" />
-      <Resource Include="Images\Lock-alpha.png" />
-      <Resource Include="Images\Merge-downwards.png" />
-      <Resource Include="Images\News\Article.png" />
-      <Resource Include="Images\News\Misc.png" />
-      <Resource Include="Images\News\NewVersion.png" />
-      <Resource Include="Images\News\OfficialAnnouncement.png" />
-      <Resource Include="Images\News\YouTube.png" />
-      <Resource Include="Images\penMode.png" />
-      <Resource Include="Images\PixiBotLogo.png" />
-      <Resource Include="Images\PixiEditorLogo.png" />
-      <Resource Include="Images\PixiParserLogo.png" />
-      <Resource Include="Images\Placeholder.png" />
-      <Resource Include="Images\Plus-square.png" />
-      <Resource Include="Images\Processing.gif" />
-      <Resource Include="Images\ReferenceLayerAbove.png" />
-      <Resource Include="Images\ReferenceLayerBelow.png" />
-      <Resource Include="Images\Replace.png" />
-      <Resource Include="Images\Save.png" />
-      <Resource Include="Images\Search.png" />
-      <Resource Include="Images\Settings.png" />
-      <Resource Include="Images\Shuffle.png" />
-      <Resource Include="Images\SocialMedia\Avatars\CPK.png" />
-      <Resource Include="Images\SocialMedia\Avatars\Equbuxu.png" />
-      <Resource Include="Images\SocialMedia\Avatars\flabbet.png" />
-      <Resource Include="Images\SocialMedia\DiscordIcon.png" />
-      <Resource Include="Images\SocialMedia\DonateIcon.png" />
-      <Resource Include="Images\SocialMedia\GitHubIcon.png" />
-      <Resource Include="Images\SocialMedia\RedditIcon.png" />
-      <Resource Include="Images\SocialMedia\SteamIcon.png" />
-      <Resource Include="Images\SocialMedia\WebsiteIcon.png" />
-      <Resource Include="Images\SocialMedia\YouTubeIcon.png" />
-      <Resource Include="Images\Star-filled.png" />
-      <Resource Include="Images\Star.png" />
-      <Resource Include="Images\SymmetryHorizontal.png" />
-      <Resource Include="Images\SymmetryVertical.png" />
-      <Resource Include="Images\TemplateLogos\Aseprite-Hover.png" />
-      <Resource Include="Images\TemplateLogos\Aseprite.png" />
-      <Resource Include="Images\Tools\BrightnessImage.png" />
-      <Resource Include="Images\Tools\ColorPickerImage.png" />
-      <Resource Include="Images\Tools\EllipseImage.png" />
-      <Resource Include="Images\Tools\EraserImage.png" />
-      <Resource Include="Images\Tools\FloodFillImage.png" />
-      <Resource Include="Images\Tools\LassoImage.png" />
-      <Resource Include="Images\Tools\LineImage.png" />
-      <Resource Include="Images\Tools\MagicWandImage.png" />
-      <Resource Include="Images\Tools\MoveImage.png" />
-      <Resource Include="Images\Tools\MoveViewportImage.png" />
-      <Resource Include="Images\Tools\PenImage.png" />
-      <Resource Include="Images\Tools\RectangleImage.png" />
-      <Resource Include="Images\Tools\RotateViewportImage.png" />
-      <Resource Include="Images\Tools\SelectImage.png" />
-      <Resource Include="Images\Tools\ZoomImage.png" />
-      <Resource Include="Images\Trash.png" />
+      <AvaloniaResource Include="Images\**"/>
+      <AvaloniaResource Include="Fonts\**"/>
+    </ItemGroup>
+  
+    <ItemGroup>
+      <UpToDateCheckInput Remove="Fonts\feather.ttf" />
     </ItemGroup>
   
 </Project>

+ 5 - 0
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/ViewModels/SubViewModels/ClipboardViewModel.cs

@@ -4,6 +4,7 @@ using System.Threading.Tasks;
 using Avalonia;
 using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Input;
+using Avalonia.Input.Platform;
 using Avalonia.Media;
 using PixiEditor.AvaloniaUI.Helpers;
 using PixiEditor.AvaloniaUI.Helpers.Extensions;
@@ -22,6 +23,10 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
     public ClipboardViewModel(ViewModelMain owner)
         : base(owner)
     {
+        Application.Current.ForDesktopMainWindow((mainWindow) =>
+        {
+            ClipboardController.Initialize(mainWindow.Clipboard);
+        });
     }
 
     [Command.Basic("PixiEditor.Clipboard.Cut", "CUT", "CUT_DESCRIPTIVE", CanExecute = "PixiEditor.Selection.IsNotEmpty", Key = Key.X, Modifiers = KeyModifiers.Control)]

+ 1 - 1
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Views/Main/MainTitleBar.axaml

@@ -49,7 +49,7 @@
                                         
                                         <TextBlock Text="{Binding FilePath}"/>
                                         <TextBlock Grid.Column="1" Margin="20,0,0,0" VerticalAlignment="Center">
-                                            <Button Foreground="#FFF" FontFamily="{StaticResource Feather}"
+                                            <Button Foreground="#FFF" FontFamily="{DynamicResource Feather}"
                                                        Command="{xaml:Command Name=PixiEditor.File.RemoveRecent, UseProvided=True}"
                                                        CommandParameter="{Binding FilePath}"></Button>
                                         </TextBlock>

+ 5 - 0
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Views/MainView.axaml

@@ -7,6 +7,11 @@
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PixiEditor.AvaloniaUI.Views.MainView"
              x:DataType="viewModels1:ViewModelMain" Background="{DynamicResource ThemeBackgroundBrush}">
+    <Interaction.Behaviors>
+        <EventTriggerBehavior EventName="Loaded">
+            <InvokeCommandAction Command="{Binding StartupCommand}"/>
+        </EventTriggerBehavior>
+    </Interaction.Behaviors>
     <Grid>
         <Grid.RowDefinitions>
             <RowDefinition Height="25"/>

+ 3 - 3
src/PixiEditor.Avalonia/PixiEditor.AvaloniaUI/Views/Windows/HelloTherePopup.axaml

@@ -56,7 +56,7 @@
                                 <StackPanel.Background>
                                     <VisualBrush>
                                         <VisualBrush.Visual>
-                                            <Ellipse Fill="{StaticResource ThemeBackgroundBrush}" Width="20" Height="20"/>
+                                            <Ellipse Fill="{DynamicResource ThemeBackgroundBrush}" Width="20" Height="20"/>
                                         </VisualBrush.Visual>
                                     </VisualBrush>
                                 </StackPanel.Background>
@@ -235,7 +235,7 @@
                                                             <Button Command="{xaml:Command Name=PixiEditor.File.RemoveRecent, UseProvided=True}"
                                                                     CommandParameter="{Binding FilePath}"
                                                                     ToolTip.Tip="Remove from list">
-                                                                <TextBlock Text="" FontFamily="{StaticResource Feather}"
+                                                                <TextBlock Text="" FontFamily="{DynamicResource Feather}"
                                                                            TextAlignment="Center" FontSize="20"/>
                                                             </Button>
                                                         </StackPanel>
@@ -295,7 +295,7 @@
 
         <ScrollViewer Grid.Row="1" Grid.Column="1"
                       IsVisible="{Binding !NewsPanelCollapsed}">
-            <Border Padding="5" BorderThickness="3 0 0 0" BorderBrush="{StaticResource MainColor}">
+            <Border Padding="5" BorderThickness="3 0 0 0" BorderBrush="{StaticResource ThemeBackgroundBrush}">
                 <Grid>
                     <indicators1:LoadingIndicator IsVisible="{Binding IsFetchingNews}"/>
                     <TextBlock ui:Translator.Key="FAILED_FETCH_NEWS" Foreground="White" FontSize="20"

+ 1 - 0
src/PixiEditor.UI.Common/Accents/Base.axaml

@@ -75,6 +75,7 @@
             <system:Double x:Key="DockFontSizeNormal">12</system:Double>
 
             <FontFamily x:Key="ContentControlThemeFontFamily">fonts:Inter#Inter, $Default</FontFamily>
+            <FontFamily x:Key="Feather">avares://PixiEditor.UI.Common;/Fonts/feather.tff</FontFamily>
             <system:Double x:Key="FontSizeSmall">10</system:Double>
             <system:Double x:Key="FontSizeNormal">12</system:Double>
             <system:Double x:Key="FontSizeLarge">16</system:Double>

+ 0 - 0
src/PixiEditor.UI.Common/Fonts/feather.ttf


+ 1 - 0
src/PixiEditor.UI.Common/PixiEditor.UI.Common.csproj

@@ -10,6 +10,7 @@
     <ItemGroup>
       <AvaloniaResource Include="Assets\PixiEditorLogo.png" />
       <AvaloniaResource Include="Assets\Processing.gif" />
+      <AvaloniaResource Include="Fonts\feather.ttf" />
       <None Remove="Assets\Fonts\Oxygen-Bold.ttf" />
       <None Remove="Assets\Fonts\Oxygen-Light.ttf" />
       <None Remove="Assets\Fonts\Oxygen-Regular.ttf" />