diff --git a/Directory.Packages.props b/Directory.Packages.props index 634d3512d..fd3dfb6b9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,6 +13,7 @@ + diff --git a/SukiUI.Demo/Common/StorageService.cs b/SukiUI.Demo/Common/StorageService.cs new file mode 100644 index 000000000..5c1435794 --- /dev/null +++ b/SukiUI.Demo/Common/StorageService.cs @@ -0,0 +1,45 @@ +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform.Storage; +using Avalonia.VisualTree; + +namespace SukiUI.Demo.Common +{ + internal static class StorageService + { + public static FilePickerFileType All { get; } = new("All") + { + Patterns = ["*.*"], + MimeTypes = ["*/*"] + }; + + public static FilePickerFileType Json { get; } = new("Json") + { + Patterns = ["*.json"], + AppleUniformTypeIdentifiers = ["public.json"], + MimeTypes = ["application/json"] + }; + + public static IStorageProvider? GetStorageProvider() + { + if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } window }) + { + return window.StorageProvider; + } + + if (Avalonia.Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime + { + MainView: { } mainView + }) + { + var visualRoot = mainView.GetVisualRoot(); + if (visualRoot is TopLevel topLevel) + { + return topLevel.StorageProvider; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/SukiUI.Demo/Features/ControlsLibrary/DockControls/DockFactory.cs b/SukiUI.Demo/Features/ControlsLibrary/DockControls/DockFactory.cs index 70516629a..0de38ec92 100644 --- a/SukiUI.Demo/Features/ControlsLibrary/DockControls/DockFactory.cs +++ b/SukiUI.Demo/Features/ControlsLibrary/DockControls/DockFactory.cs @@ -6,11 +6,10 @@ namespace SukiUI.Demo.Features.ControlsLibrary.DockControls { - public class DockFactory(object context) : Factory + public class DockFactory(DockMvvmViewModel context) : Factory { - private readonly object _context = context; + private readonly DockMvvmViewModel _context = context; private IRootDock? _rootDock; - private IDocumentDock? _documentDock; public override IRootDock CreateLayout() { @@ -37,7 +36,7 @@ public override IRootDock CreateLayout() { ActiveDockable = solutionExploreTool, VisibleDockables = CreateList(solutionExploreTool), - Alignment = Alignment.Left + Alignment = Alignment.Left, } ) }; @@ -64,7 +63,7 @@ public override IRootDock CreateLayout() { ActiveDockable = propertiesTool, VisibleDockables = CreateList(propertiesTool), - Alignment = Alignment.Top, + Alignment = Alignment.Right, } ) }; @@ -80,7 +79,7 @@ public override IRootDock CreateLayout() { ActiveDockable = outputTool, VisibleDockables = CreateList(errorListTool, outputTool), - Alignment = Alignment.Top, + Alignment = Alignment.Bottom, } ) }; @@ -123,8 +122,7 @@ public override IRootDock CreateLayout() rootDock.ActiveDockable = homeView; rootDock.DefaultDockable = homeView; rootDock.VisibleDockables = CreateList(homeView); - - _documentDock = documentDock; + _rootDock = rootDock; return rootDock; @@ -146,14 +144,12 @@ public override void InitLayout(IDockable layout) { ContextLocator = new Dictionary> { - ["Dashboard"] = () => layout, ["Home"] = () => _context }; DockableLocator = new Dictionary>() { - ["Root"] = () => _rootDock, - ["Documents"] = () => _documentDock + ["Home"] = () => _rootDock, }; HostWindowLocator = new Dictionary> diff --git a/SukiUI.Demo/Features/ControlsLibrary/DockMvvmView.axaml b/SukiUI.Demo/Features/ControlsLibrary/DockMvvmView.axaml index 85040674e..6a4479793 100644 --- a/SukiUI.Demo/Features/ControlsLibrary/DockMvvmView.axaml +++ b/SukiUI.Demo/Features/ControlsLibrary/DockMvvmView.axaml @@ -3,11 +3,50 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controlsLibrary="clr-namespace:SukiUI.Demo.Features.ControlsLibrary" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:DataType="controlsLibrary:DockMvvmViewModel" x:Class="SukiUI.Demo.Features.ControlsLibrary.DockMvvmView"> - + + + + + + + + + diff --git a/SukiUI.Demo/Features/ControlsLibrary/DockMvvmViewModel.cs b/SukiUI.Demo/Features/ControlsLibrary/DockMvvmViewModel.cs index 94124668d..192b21ffa 100644 --- a/SukiUI.Demo/Features/ControlsLibrary/DockMvvmViewModel.cs +++ b/SukiUI.Demo/Features/ControlsLibrary/DockMvvmViewModel.cs @@ -1,41 +1,119 @@ using System.Diagnostics; -using System.Windows.Input; +using Avalonia.Collections; +using Avalonia.Platform.Storage; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Dock.Model.Controls; using Dock.Model.Core; +using Dock.Serializer; using Material.Icons; +using SukiUI.Demo.Common; using SukiUI.Demo.Features.ControlsLibrary.DockControls; namespace SukiUI.Demo.Features.ControlsLibrary { public partial class DockMvvmViewModel : DemoPageBase { - private readonly IFactory? _factory; + private readonly IDockSerializer _serializer; + private readonly IFactory _factory; [ObservableProperty] private IRootDock? _layout; - public ICommand NewLayout { get; } - public DockMvvmViewModel() : base("DockMvvm", MaterialIconKind.DockTop) { - _factory = new DockFactory(new object()); - + _serializer = new DockSerializer(typeof(AvaloniaList<>)); + _factory = new DockFactory(this); DebugFactoryEvents(_factory); - Layout = _factory?.CreateLayout(); + Layout = _factory.CreateLayout(); + + if (Layout is null) + { + return; + } + + _factory.InitLayout(Layout); + + if (Layout is { } root) + { + root.Navigate.Execute("Home"); + } + } + + [RelayCommand] + private async Task SaveLayout() + { + var storageProvider = StorageService.GetStorageProvider(); - if (Layout is { }) + var file = await storageProvider!.SaveFilePickerAsync(new FilePickerSaveOptions { - _factory?.InitLayout(Layout); + Title = "Save layout", + FileTypeChoices = GetOpenLayoutFileTypes(), + SuggestedFileName = "layout", + DefaultExtension = "json", + ShowOverwritePrompt = true + }); - if (Layout is { } root) + if (file is not null) + { + try + { + await using var stream = await file.OpenWriteAsync(); + + if (Layout is not null) + { + _serializer.Save(stream, Layout); + } + } + catch (Exception e) { - root.Navigate.Execute("Home"); + Console.WriteLine(e); } } + } + + [RelayCommand] + private async Task OpenLayout() + { + var storageProvider = StorageService.GetStorageProvider(); + + var result = await storageProvider!.OpenFilePickerAsync( + new FilePickerOpenOptions + { + Title = "Open layout", + FileTypeFilter = GetOpenLayoutFileTypes(), + AllowMultiple = false + }); + + var file = result.FirstOrDefault(); + + if (file is not null) + { + try + { + await using var stream = await file.OpenReadAsync(); + using var reader = new StreamReader(stream); + + var layout = _serializer.Load(stream); - NewLayout = new RelayCommand(ResetLayout); + if (layout is not null) + { + _factory!.InitLayout(layout); + Layout = layout; + } + } + catch (Exception e) + { + Console.WriteLine(e); + } + } } + + private static List GetOpenLayoutFileTypes() + => + [ + StorageService.Json, + StorageService.All + ]; private static void DebugFactoryEvents(IFactory factory) { @@ -136,31 +214,5 @@ private static void DebugFactoryEvents(IFactory factory) $"[WindowMoveDragEnd] Title='{args.Window?.Title}', X='{args.Window?.X}', Y='{args.Window?.Y}"); }; } - - public void CloseLayout() - { - if (Layout is IDock dock && dock.Close.CanExecute(null)) - { - dock.Close.Execute(null); - } - } - - public void ResetLayout() - { - if (Layout is not null && Layout.Close.CanExecute(null)) - { - Layout.Close.Execute(null); - } - - var layout = _factory?.CreateLayout(); - - if (layout is null) - { - return; - } - - Layout = layout; - _factory?.InitLayout(layout); - } } } \ No newline at end of file diff --git a/SukiUI.Demo/Program.cs b/SukiUI.Demo/Program.cs index 4ded44565..ff6965435 100644 --- a/SukiUI.Demo/Program.cs +++ b/SukiUI.Demo/Program.cs @@ -24,7 +24,10 @@ public static AppBuilder BuildAvaloniaApp() .UseXamlDisplay(); if (OperatingSystem.IsWindows() || OperatingSystem.IsMacOS() || OperatingSystem.IsLinux()) - app.UseManagedSystemDialogs(); + { + //app.UseManagedSystemDialogs(); + } + return app; } } \ No newline at end of file diff --git a/SukiUI.Demo/SukiUI.Demo.csproj b/SukiUI.Demo/SukiUI.Demo.csproj index 9c62f3928..64c8b6f3a 100644 --- a/SukiUI.Demo/SukiUI.Demo.csproj +++ b/SukiUI.Demo/SukiUI.Demo.csproj @@ -27,6 +27,7 @@ +