Ver código fonte

Basic Api with window creation

Krzysztof Krysiński 2 anos atrás
pai
commit
b459b6fbe1

+ 4 - 7
src/PixiEditor.Extensions/Extension.cs

@@ -1,4 +1,5 @@
 using System.Reflection;
+using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Extensions.Metadata;
 
 namespace PixiEditor.Extensions;
@@ -8,14 +9,9 @@ namespace PixiEditor.Extensions;
 /// </summary>
 public abstract class Extension
 {
+    public ExtensionServices Api { get; private set; }
     public ExtensionMetadata Metadata { get; private set; }
 
-    public Action<string, string> NoticeDialogImpl { get; set; }
-    public void NoticeDialog(string message, string title)
-    {
-        NoticeDialogImpl?.Invoke(message, title);
-    }
-
     public void ProvideMetadata(ExtensionMetadata metadata)
     {
         if (Metadata != null)
@@ -26,8 +22,9 @@ public abstract class Extension
         Metadata = metadata;
     }
 
-    public void Load()
+    public void Load(ExtensionServices api)
     {
+        Api = api;
         OnLoaded();
     }
 

+ 16 - 0
src/PixiEditor.Extensions/ExtensionServices.cs

@@ -0,0 +1,16 @@
+using Microsoft.Extensions.DependencyInjection;
+using PixiEditor.Extensions.Windowing;
+
+namespace PixiEditor.Extensions;
+
+public class ExtensionServices
+{
+    public ServiceProvider Services { get; private set; }
+
+    public IWindowProvider WindowProvider => Services.GetRequiredService<IWindowProvider>();
+
+    public ExtensionServices(ServiceProvider services)
+    {
+        Services = services;
+    }
+}

+ 5 - 0
src/PixiEditor.Extensions/PixiEditor.Extensions.csproj

@@ -6,4 +6,9 @@
         <Nullable>enable</Nullable>
     </PropertyGroup>
 
+    <ItemGroup>
+      <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
+      <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
+    </ItemGroup>
+
 </Project>

+ 8 - 0
src/PixiEditor.Extensions/Windowing/IPopupWindow.cs

@@ -0,0 +1,8 @@
+namespace PixiEditor.Extensions;
+
+public interface IPopupWindow
+{
+    public string Title { get; set; }
+    public void Show();
+    public bool? ShowDialog();
+}

+ 6 - 0
src/PixiEditor.Extensions/Windowing/IWindowProvider.cs

@@ -0,0 +1,6 @@
+namespace PixiEditor.Extensions.Windowing;
+
+public interface IWindowProvider
+{
+    public PopupWindow CreatePopupWindow(string title, string bodyXaml);
+}

+ 21 - 0
src/PixiEditor.Extensions/Windowing/PopupWindow.cs

@@ -0,0 +1,21 @@
+namespace PixiEditor.Extensions.Windowing;
+
+public class PopupWindow : IPopupWindow
+{
+    private IPopupWindow _underlyingWindow;
+
+    public PopupWindow(IPopupWindow basicPopup)
+    {
+        _underlyingWindow = basicPopup;
+    }
+
+    public string Title
+    {
+        get => _underlyingWindow.Title;
+        set => _underlyingWindow.Title = value;
+    }
+
+    public void Show() => _underlyingWindow.Show();
+
+    public bool? ShowDialog() => _underlyingWindow.ShowDialog();
+}

+ 4 - 1
src/PixiEditor/App.xaml.cs

@@ -2,6 +2,8 @@
 using System.Text.RegularExpressions;
 using System.Windows;
 using System.Windows.Media;
+using Microsoft.Extensions.DependencyInjection;
+using PixiEditor.Extensions;
 using PixiEditor.Models.AppExtensions;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
@@ -49,7 +51,8 @@ internal partial class App : Application
 
         AddNativeAssets();
 
-        ExtensionLoader loader = new ExtensionLoader();
+        var services = new ServiceCollection().AddExtensionServices().BuildServiceProvider();
+        ExtensionLoader loader = new ExtensionLoader(new ExtensionServices(services));
         loader.LoadExtensions();
 
         MainWindow = new MainWindow();

+ 6 - 0
src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs

@@ -1,4 +1,7 @@
 using Microsoft.Extensions.DependencyInjection;
+using PixiEditor.Extensions;
+using PixiEditor.Extensions.Windowing;
+using PixiEditor.Models.AppExtensions.Services;
 using PixiEditor.Models.Commands;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataProviders;
@@ -73,4 +76,7 @@ internal static class ServiceCollectionHelpers
         .AddSingleton<PaletteFileParser, PixiPaletteParser>()
         // Palette data sources
         .AddSingleton<PaletteListDataSource, LocalPalettesFetcher>();
+
+    public static IServiceCollection AddExtensionServices(this IServiceCollection collection) =>
+        collection.AddSingleton<IWindowProvider, WindowProvider>();
 }

+ 12 - 0
src/PixiEditor/Helpers/Extensions/WindowExtensions.cs

@@ -0,0 +1,12 @@
+using System.Reflection;
+using System.Windows;
+
+namespace PixiEditor.Helpers.Extensions;
+
+public static class WindowExtensions
+{
+    public static bool IsModal(this Window window)
+    {
+        return (bool)typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(window);
+    }
+}

+ 5 - 3
src/PixiEditor/Models/AppExtensions/ExtensionLoader.cs

@@ -1,6 +1,7 @@
 using System.IO;
 using System.Reflection;
 using System.Windows;
+using Microsoft.Extensions.DependencyInjection;
 using Newtonsoft.Json;
 using PixiEditor.Extensions;
 using PixiEditor.Extensions.Metadata;
@@ -12,9 +13,11 @@ namespace PixiEditor.Models.AppExtensions;
 
 internal class ExtensionLoader
 {
+    public ExtensionServices Api { get; }
     private List<Extension> LoadedExtensions { get; } = new();
-    public ExtensionLoader()
+    public ExtensionLoader(ExtensionServices pixiEditorApi)
     {
+        Api = pixiEditorApi;
         ValidateExtensionFolder();
     }
 
@@ -48,8 +51,7 @@ internal class ExtensionLoader
             var metadata = JsonConvert.DeserializeObject<ExtensionMetadata>(json);
             ValidateMetadata(metadata);
             var extension = LoadExtensionEntry(Path.GetDirectoryName(packageJsonPath), metadata);
-            extension.NoticeDialogImpl = (string message, string title) => NoticeDialog.Show(message, title);
-            extension.Load(/*TODO: Inject api*/);
+            extension.Load(Api);
             LoadedExtensions.Add(extension);
         }
         catch (JsonException)

+ 20 - 0
src/PixiEditor/Models/AppExtensions/Services/WindowProvider.cs

@@ -0,0 +1,20 @@
+using System.Windows.Markup;
+using PixiEditor.Extensions;
+using PixiEditor.Extensions.Windowing;
+using PixiEditor.Views.Dialogs;
+
+namespace PixiEditor.Models.AppExtensions.Services;
+
+public class WindowProvider : IWindowProvider
+{
+    public PopupWindow CreatePopupWindow(string title, string bodyXaml)
+    {
+        object body = null;
+        if(bodyXaml is not null)
+        {
+            body = XamlReader.Parse(bodyXaml);
+        }
+
+        return new PopupWindow(new BasicPopup { Title = title, Body = body });
+    }
+}

+ 35 - 0
src/PixiEditor/Views/Dialogs/BasicPopup.xaml

@@ -0,0 +1,35 @@
+<Window x:Class="PixiEditor.Views.Dialogs.BasicPopup"
+        x:ClassModifier="internal"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        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:PixiEditor.Views.Dialogs"
+        xmlns:views="clr-namespace:PixiEditor.Views"
+        xmlns:helpers="clr-namespace:PixiEditor.Helpers"
+        xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+        xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
+        mc:Ignorable="d"
+        WindowStyle="None"
+        d:Title="Notice" Height="250" Width="350"
+        WindowStartupLocation="CenterScreen"
+        x:Name="popup"
+        views:Translator.Key="{Binding ElementName=popup, Path=Title}"
+        FlowDirection="{helpers:Localization FlowDirection}">
+
+    <WindowChrome.WindowChrome>
+        <WindowChrome CaptionHeight="32" GlassFrameThickness="0.1"
+                      ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
+    </WindowChrome.WindowChrome>
+
+    <DockPanel Background="{StaticResource AccentColor}" Focusable="True">
+        <b:Interaction.Behaviors>
+            <behaviours:ClearFocusOnClickBehavior/>
+        </b:Interaction.Behaviors>
+
+        <local:DialogTitleBar DockPanel.Dock="Top"
+                             TitleKey="{Binding ElementName=popup, Path=Title}"
+                             CloseCommand="{Binding DataContext.CancelCommand, ElementName=popup}" />
+        <ContentPresenter DockPanel.Dock="Bottom" Content="{Binding ElementName=popup, Path=DataContext.Body}"/>
+</DockPanel>
+</Window>

+ 37 - 0
src/PixiEditor/Views/Dialogs/BasicPopup.xaml.cs

@@ -0,0 +1,37 @@
+using System.Windows;
+using PixiEditor.Extensions;
+using PixiEditor.Helpers;
+
+namespace PixiEditor.Views.Dialogs;
+
+internal partial class BasicPopup : Window, IPopupWindow
+{
+    public RelayCommand CancelCommand { get; set; }
+
+    public static readonly DependencyProperty BodyProperty = DependencyProperty.Register(
+        nameof(Body), typeof(object), typeof(BasicPopup), new PropertyMetadata(default(object)));
+
+    public object Body
+    {
+        get { return (object)GetValue(BodyProperty); }
+        set { SetValue(BodyProperty, value); }
+    }
+
+    public BasicPopup()
+    {
+        InitializeComponent();
+        CancelCommand = new RelayCommand(Cancel);
+        DataContext = this;
+    }
+
+    private void Cancel(object obj)
+    {
+        if (this.IsModal())
+        {
+            DialogResult = false;
+        }
+
+        Close();
+    }
+}
+

+ 3 - 1
src/SampleExtension/SampleExtension.cs

@@ -10,6 +10,8 @@ public class SampleExtension : Extension
 
     protected override void OnInitialized()
     {
-        NoticeDialog($"Hello from {Metadata.DisplayName}", "SampleExtension");
+        var popup = Api.WindowProvider.CreatePopupWindow("Hello World!",
+            "<TextBlock xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">Hello World!</TextBlock>");
+        popup.ShowDialog();
     }
 }

+ 1 - 0
src/SampleExtension/SampleExtension.csproj

@@ -4,6 +4,7 @@
         <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
+      <OutputPath>..\PixiEditor\bin\Debug\net7.0-windows\Extensions</OutputPath>
     </PropertyGroup>
 
     <ItemGroup>