Dock
This commit is contained in:
parent
b1d3ec73c9
commit
693d12b61c
35 changed files with 389 additions and 269 deletions
|
|
@ -16,6 +16,7 @@
|
|||
<PackageVersion Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)" />
|
||||
<PackageVersion Include="Avalonia.Themes.Simple" Version="11.0.9" />
|
||||
<PackageVersion Include="Dock.Avalonia" Version="11.0.0.5" />
|
||||
<PackageVersion Include="Dock.Model.ReactiveUI" Version="11.0.0.5" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="$(DotNetVersion)" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="$(DotNetVersion)" />
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />
|
||||
<DockFluentTheme />
|
||||
</Application.Styles>
|
||||
|
||||
<Application.Resources>
|
||||
|
|
|
|||
|
|
@ -1,25 +1,17 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Metadata;
|
||||
|
||||
using InkForge.Desktop.ViewModels;
|
||||
using InkForge.Desktop.Views;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
using Splat;
|
||||
using Splat.Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
[assembly: XmlnsPrefix("app:InkForge", "inkforge")]
|
||||
[assembly: XmlnsDefinition("app:InkForge", "InkForge.Desktop.Controls")]
|
||||
[assembly: XmlnsDefinition("app:InkForge", "InkForge.Desktop.MarkupExtensions")]
|
||||
[assembly: XmlnsDefinition("app:InkForge", "InkForge.Desktop.Services")]
|
||||
|
||||
namespace InkForge.Desktop;
|
||||
|
||||
public partial class App : Application
|
||||
|
|
@ -31,21 +23,8 @@ public partial class App : Application
|
|||
|
||||
public IServiceProvider ServiceProvider => GetValue(ServiceProviderProperty);
|
||||
|
||||
public static void Configure(IServiceCollection services, IConfigurationManager configuration)
|
||||
public static void Configure(IServiceCollection services)
|
||||
{
|
||||
configuration.SetBasePath(AppContext.BaseDirectory);
|
||||
configuration.AddJsonFile(
|
||||
new ManifestEmbeddedFileProvider(typeof(App).Assembly),
|
||||
"Properties/appsettings.json", false, false);
|
||||
configuration.AddJsonFile(
|
||||
Path.Combine(
|
||||
Environment.GetFolderPath(
|
||||
Environment.SpecialFolder.ApplicationData,
|
||||
Environment.SpecialFolderOption.DoNotVerify),
|
||||
"InkForge",
|
||||
"usersettings.json"), true, true);
|
||||
configuration.AddJsonFile("appsettings.json", true, true);
|
||||
|
||||
services.UseMicrosoftDependencyResolver();
|
||||
Locator.CurrentMutable.InitializeSplat();
|
||||
Locator.CurrentMutable.InitializeReactiveUI();
|
||||
|
|
@ -60,18 +39,11 @@ public partial class App : Application
|
|||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
// This kills Avalonia VSCode Previewer.
|
||||
var viewModel = ActivatorUtilities.GetServiceOrCreateInstance<AppViewModel>(ServiceProvider);
|
||||
var view = ViewLocator.Current.ResolveView(viewModel)!;
|
||||
view.ViewModel = viewModel;
|
||||
_ = ApplicationLifetime switch
|
||||
{
|
||||
IClassicDesktopStyleApplicationLifetime desktop => desktop.MainWindow = view as Window,
|
||||
ISingleViewApplicationLifetime singleView => singleView.MainView = view as Control,
|
||||
IClassicDesktopStyleApplicationLifetime desktop => desktop.MainWindow = new MainWindow(),
|
||||
_ => throw new NotSupportedException(),
|
||||
};
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
private static IServiceProvider OnServiceProviderChanged(AvaloniaObject @object, IServiceProvider provider)
|
||||
|
|
|
|||
29
app/InkForge.Desktop/Dock/WorkspaceFactory.cs
Normal file
29
app/InkForge.Desktop/Dock/WorkspaceFactory.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using Dock.Model.Controls;
|
||||
using Dock.Model.Core;
|
||||
using Dock.Model.ReactiveUI;
|
||||
|
||||
namespace InkForge.Desktop.Dock;
|
||||
|
||||
public class WorkspaceFactory : Factory
|
||||
{
|
||||
public override IRootDock CreateLayout()
|
||||
{
|
||||
var documents = CreateDocumentDock();
|
||||
documents.Id = "Documents";
|
||||
documents.Title = "Documents";
|
||||
|
||||
var root = CreateRootDock();
|
||||
|
||||
root.VisibleDockables = [documents];
|
||||
root.ActiveDockable = documents;
|
||||
root.DefaultDockable = documents;
|
||||
|
||||
DockableLocator = new Dictionary<string, Func<IDockable?>>
|
||||
{
|
||||
["Root"] = () => root,
|
||||
["Documents"] = () => documents,
|
||||
};
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
<PackageReference Include="Avalonia.ReactiveUI" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" />
|
||||
<PackageReference Include="Dock.Avalonia" />
|
||||
<PackageReference Include="Dock.Model.ReactiveUI" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" />
|
||||
|
|
|
|||
11
app/InkForge.Desktop/Managers/DocumentManager.cs
Normal file
11
app/InkForge.Desktop/Managers/DocumentManager.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace InkForge.Desktop.Managers;
|
||||
|
||||
public class DocumentManager
|
||||
{
|
||||
private readonly WorkspaceManager _workspaceManager;
|
||||
|
||||
public DocumentManager(WorkspaceManager workspaceManager)
|
||||
{
|
||||
_workspaceManager = workspaceManager;
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ public class WorkspaceManager(IServiceProvider serviceProvider) : ReactiveObject
|
|||
|
||||
file.Directory!.Create();
|
||||
IServiceScope? scope = null;
|
||||
IWorkspaceAccessor workspaceAccessor;
|
||||
IWorkspaceContext workspaceContext;
|
||||
try
|
||||
{
|
||||
scope = _serviceProvider.CreateScope();
|
||||
|
|
@ -54,8 +54,8 @@ public class WorkspaceManager(IServiceProvider serviceProvider) : ReactiveObject
|
|||
var options = serviceProvider.GetRequiredService<LocalWorkspaceOptions>();
|
||||
options.DbPath = path;
|
||||
|
||||
workspaceAccessor = serviceProvider.GetRequiredService<IWorkspaceAccessor>();
|
||||
workspaceAccessor.Workspace = new Workspace(scope)
|
||||
workspaceContext = serviceProvider.GetRequiredService<IWorkspaceContext>();
|
||||
workspaceContext.Workspace = new Workspace(scope)
|
||||
{
|
||||
Name = Path.GetFileNameWithoutExtension(file.Name),
|
||||
Options = options,
|
||||
|
|
@ -87,6 +87,6 @@ public class WorkspaceManager(IServiceProvider serviceProvider) : ReactiveObject
|
|||
scope?.Dispose();
|
||||
}
|
||||
|
||||
return workspaceAccessor.Workspace;
|
||||
return workspaceContext.Workspace;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using InkForge.Data;
|
||||
using InkForge.Desktop.Data;
|
||||
using InkForge.Desktop.Data.Options;
|
||||
using InkForge.Desktop.Dock;
|
||||
using InkForge.Desktop.Managers;
|
||||
using InkForge.Desktop.Models;
|
||||
using InkForge.Desktop.ViewModels;
|
||||
|
|
@ -19,13 +20,23 @@ public static class InkForgeServiceCollections
|
|||
{
|
||||
services.AddHttpClient();
|
||||
|
||||
services.AddScoped<IWorkspaceAccessor, WorkspaceAccessor>();
|
||||
services.AddScoped<IDbContextFactory<NoteDbContext>, NoteDbContextFactory>();
|
||||
// Singletons
|
||||
// - Concrete
|
||||
services.AddSingleton<DocumentManager>();
|
||||
services.AddSingleton<WorkspaceFactory>();
|
||||
services.AddSingleton<WorkspaceManager>();
|
||||
services.AddSingleton<WorkspacesViewModel>();
|
||||
|
||||
// Scoped
|
||||
// - Concrete
|
||||
services.AddScoped<LocalWorkspaceOptions>();
|
||||
|
||||
services.AddSingleton<LandingViewModel>();
|
||||
services.AddSingleton<WorkspaceManager>();
|
||||
// - Service
|
||||
services.AddScoped<IDbContextFactory<NoteDbContext>, NoteDbContextFactory>();
|
||||
services.AddScoped<IWorkspaceContext, WorkspaceContext>();
|
||||
|
||||
// - Forwarders
|
||||
services.AddScoped(s => s.GetRequiredService<IWorkspaceContext>().Workspace!);
|
||||
|
||||
Locator.CurrentMutable.RegisterViewsForViewModels(typeof(InkForgeServiceCollections).Assembly);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class TypeFactory
|
||||
{
|
||||
public static T Create<T>(IServiceProvider serviceProvider)
|
||||
{
|
||||
return TypeFactory<EmptyArguments, T>.Create(serviceProvider, default);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeFactory<TArguments, T>
|
||||
where TArguments : IFactoryArguments<TArguments>
|
||||
{
|
||||
|
|
@ -12,6 +20,13 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
}
|
||||
}
|
||||
|
||||
public readonly struct EmptyArguments : IFactoryArguments<EmptyArguments>
|
||||
{
|
||||
public static Type[] Types => [];
|
||||
|
||||
public static implicit operator object[](in EmptyArguments _) => [];
|
||||
}
|
||||
|
||||
public interface IFactoryArguments<T>
|
||||
where T : IFactoryArguments<T>
|
||||
{
|
||||
|
|
|
|||
6
app/InkForge.Desktop/Models/Note.cs
Normal file
6
app/InkForge.Desktop/Models/Note.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace InkForge.Desktop.Models;
|
||||
|
||||
public class Note
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -24,6 +24,15 @@ public sealed class Workspace : IDisposable
|
|||
_dbContextFactory = Services.GetRequiredService<IDbContextFactory<NoteDbContext>>();
|
||||
}
|
||||
|
||||
// public Note AddNote(Note? parent)
|
||||
// {
|
||||
// }
|
||||
|
||||
public T CreateViewModel<T>()
|
||||
{
|
||||
return TypeFactory.Create<T>(Services);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
|
|
@ -34,10 +43,7 @@ public sealed class Workspace : IDisposable
|
|||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
{
|
||||
_scope!.Dispose();
|
||||
}
|
||||
|
||||
_scope!.Dispose();
|
||||
_scope = null;
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
namespace InkForge.Desktop.Models
|
||||
{
|
||||
public interface IWorkspaceAccessor
|
||||
public interface IWorkspaceContext
|
||||
{
|
||||
Workspace? Workspace { get; set; }
|
||||
}
|
||||
|
||||
public class WorkspaceAccessor : IWorkspaceAccessor
|
||||
public class WorkspaceContext : IWorkspaceContext
|
||||
{
|
||||
public Workspace? Workspace { get; set; }
|
||||
}
|
||||
|
|
@ -1,14 +1,18 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Metadata;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
|
||||
using InkForge.Desktop;
|
||||
using InkForge.Desktop.ViewModels;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
|
|
@ -44,7 +48,7 @@ static class Program
|
|||
configuration = new();
|
||||
ServiceCollection services = [];
|
||||
services.AddSingleton<IConfiguration>(configuration);
|
||||
App.Configure(services, configuration);
|
||||
App.Configure(services);
|
||||
|
||||
builder.AfterSetup(services.SetupApp);
|
||||
return builder;
|
||||
|
|
@ -58,18 +62,18 @@ static class Program
|
|||
private class ServiceProviderDisposer
|
||||
{
|
||||
private readonly ServiceProvider _serviceProvider;
|
||||
private readonly TaskCompletionSource<ValueTask> _shutdownTask = new();
|
||||
private ValueTask? _shutdownTask;
|
||||
|
||||
public ServiceProviderDisposer(ServiceProvider serviceProvider, Dispatcher dispatcher)
|
||||
{
|
||||
dispatcher.ShutdownStarted += OnShutdownStarted;
|
||||
dispatcher.ShutdownFinished += OnShutdownFinished;
|
||||
dispatcher.ShutdownStarted += OnShutdownStarted;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
private void OnShutdownFinished(object? sender, EventArgs e)
|
||||
{
|
||||
if (_shutdownTask.Task.Result is { IsCompleted: false } disposeTask)
|
||||
if (_shutdownTask is { IsCompleted: false } disposeTask)
|
||||
{
|
||||
disposeTask.GetAwaiter().GetResult();
|
||||
}
|
||||
|
|
@ -78,7 +82,7 @@ static class Program
|
|||
private void OnShutdownStarted(object? sender, EventArgs e)
|
||||
{
|
||||
#pragma warning disable CA2012 // This will only ever be awaited once in ShutdownFinished
|
||||
_shutdownTask.SetResult(_serviceProvider.DisposeAsync());
|
||||
_shutdownTask = _serviceProvider.DisposeAsync();
|
||||
#pragma warning restore CA2012
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
app/InkForge.Desktop/Properties/AssemblyInfo.cs
Normal file
6
app/InkForge.Desktop/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
using Avalonia.Metadata;
|
||||
|
||||
[assembly: XmlnsPrefix("app:InkForge", "inkforge")]
|
||||
[assembly: XmlnsDefinition("app:InkForge", "InkForge.Desktop.Controls")]
|
||||
[assembly: XmlnsDefinition("app:InkForge", "InkForge.Desktop.MarkupExtensions")]
|
||||
[assembly: XmlnsDefinition("app:InkForge", "InkForge.Desktop.Services")]
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
namespace InkForge.Desktop.Services;
|
||||
|
||||
public class WorkspaceContext
|
||||
{
|
||||
public string DbPath { get; set; }
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
using InkForge.Desktop.Managers;
|
||||
using InkForge.Desktop.Models;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
namespace InkForge.Desktop.ViewModels;
|
||||
|
||||
public class AppViewModel : ReactiveObject
|
||||
{
|
||||
private readonly LandingViewModel _landingViewModel;
|
||||
private readonly WorkspaceManager _workspace;
|
||||
private object _view;
|
||||
|
||||
public object View
|
||||
{
|
||||
get => _view;
|
||||
set => this.RaiseAndSetIfChanged(ref _view, value);
|
||||
}
|
||||
|
||||
public AppViewModel(WorkspaceManager workspace, LandingViewModel landingViewModel)
|
||||
{
|
||||
_workspace = workspace;
|
||||
_landingViewModel = landingViewModel;
|
||||
|
||||
this.WhenAnyValue(v => v._workspace.Workspace).Subscribe(OnWorkspaceChanged);
|
||||
}
|
||||
|
||||
private void OnWorkspaceChanged(Workspace workspace)
|
||||
{
|
||||
View = workspace switch
|
||||
{
|
||||
null => _landingViewModel,
|
||||
{ } => new WorkspaceViewModel(workspace) // scoped?
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,28 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Reactive;
|
||||
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
using Dock.Model.ReactiveUI.Controls;
|
||||
|
||||
using InkForge.Desktop.Managers;
|
||||
using InkForge.Desktop.Services;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
namespace InkForge.Desktop.ViewModels;
|
||||
namespace InkForge.Desktop.ViewModels.Documents;
|
||||
|
||||
public class LandingViewModel : ReactiveObject
|
||||
public class WelcomePageDocumentViewModel : Document
|
||||
{
|
||||
private ReadOnlyObservableCollection<RecentItemViewModel> _recentItems;
|
||||
private readonly WorkspaceManager _workspaceController;
|
||||
|
||||
public ReactiveCommand<Unit, Unit> CreateNew { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> OpenNew { get; }
|
||||
|
||||
public ReadOnlyObservableCollection<RecentItemViewModel> RecentItems => _recentItems;
|
||||
|
||||
public LandingViewModel(WorkspaceManager workspaceController)
|
||||
public WelcomePageDocumentViewModel(WorkspaceManager workspaceController)
|
||||
{
|
||||
Title = "Welcome";
|
||||
|
||||
_workspaceController = workspaceController;
|
||||
CreateNew = ReactiveCommand.CreateFromTask(OnCreateNew);
|
||||
OpenNew = ReactiveCommand.CreateFromTask(OnOpenNew);
|
||||
23
app/InkForge.Desktop/ViewModels/DocumentsViewModel.cs
Normal file
23
app/InkForge.Desktop/ViewModels/DocumentsViewModel.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using Dock.Model.Controls;
|
||||
|
||||
using InkForge.Desktop.Dock;
|
||||
using InkForge.Desktop.Managers;
|
||||
using InkForge.Desktop.ViewModels.Documents;
|
||||
|
||||
namespace InkForge.Desktop.ViewModels;
|
||||
|
||||
public class DocumentsViewModel
|
||||
{
|
||||
private readonly WorkspaceFactory _workspaceFactory;
|
||||
|
||||
public IRootDock Layout { get; }
|
||||
|
||||
public DocumentsViewModel(WorkspaceFactory workspaceFactory, WorkspaceManager workspaceManager)
|
||||
{
|
||||
_workspaceFactory = workspaceFactory;
|
||||
|
||||
Layout = workspaceFactory.CreateLayout();
|
||||
var documents = workspaceFactory.GetDockable<IDocumentDock>("Documents")!;
|
||||
workspaceFactory.AddDockable(documents, new WelcomePageDocumentViewModel(workspaceManager));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
using InkForge.Desktop.Models;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
namespace InkForge.Desktop.ViewModels;
|
||||
|
||||
public class WorkspaceViewModel : ReactiveObject
|
||||
{
|
||||
private readonly Workspace _workspace;
|
||||
private readonly ObservableAsPropertyHelper<string> _workspaceNameProperty;
|
||||
|
||||
public string WorkspaceName => _workspaceNameProperty.Value;
|
||||
|
||||
public WorkspaceViewModel(Workspace workspace)
|
||||
{
|
||||
_workspace = workspace;
|
||||
_workspaceNameProperty = this.WhenAnyValue(v => v._workspace.Name).ToProperty(this, nameof(WorkspaceName));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using InkForge.Desktop.Models;
|
||||
|
||||
namespace InkForge.Desktop.ViewModels.Workspaces;
|
||||
|
||||
public class WorkspaceViewModel(Workspace workspace)
|
||||
{
|
||||
// private readonly Workspace _workspace;
|
||||
// private readonly ObservableAsPropertyHelper<string> _workspaceNameProperty;
|
||||
|
||||
// public string WorkspaceName => _workspaceNameProperty.Value;
|
||||
|
||||
// public ReactiveCommand<Unit, Unit> AddDocument { get; }
|
||||
|
||||
// public WorkspacesViewModel(Workspace workspace)
|
||||
// {
|
||||
// _workspace = workspace;
|
||||
// _workspaceNameProperty = this.WhenAnyValue(v => v._workspace.Name).ToProperty(this, nameof(WorkspaceName));
|
||||
|
||||
// AddDocument = ReactiveCommand.Create(OnAddDocument);
|
||||
// }
|
||||
|
||||
// private void OnAddDocument()
|
||||
// {
|
||||
|
||||
// }
|
||||
}
|
||||
24
app/InkForge.Desktop/ViewModels/WorkspacesViewModel.cs
Normal file
24
app/InkForge.Desktop/ViewModels/WorkspacesViewModel.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using InkForge.Desktop.Managers;
|
||||
using InkForge.Desktop.ViewModels.Workspaces;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
namespace InkForge.Desktop.ViewModels;
|
||||
|
||||
public class WorkspacesViewModel : ReactiveObject
|
||||
{
|
||||
private readonly WorkspaceManager _workspaceManager;
|
||||
private WorkspaceViewModel? _workspace;
|
||||
|
||||
public WorkspaceViewModel? Workspace
|
||||
{
|
||||
get => _workspace;
|
||||
private set => this.RaiseAndSetIfChanged(ref _workspace, value);
|
||||
}
|
||||
|
||||
public WorkspacesViewModel(WorkspaceManager workspaceManager)
|
||||
{
|
||||
_workspaceManager = workspaceManager;
|
||||
workspaceManager.WhenAnyValue(v => v.Workspace, v => v is null ? null : new WorkspaceViewModel(v)).BindTo(this, v => v.Workspace);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:InkForge.Desktop.ViewModels.Documents"
|
||||
xmlns:inkforge="app:InkForge"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="InkForge.Desktop.Views.Documents.WelcomePageDocument"
|
||||
x:DataType="vm:WelcomePageDocumentViewModel"
|
||||
inkforge:TopLevels.Register="{CompiledBinding}">
|
||||
Welcome to Avalonia!
|
||||
</UserControl>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using Avalonia.ReactiveUI;
|
||||
|
||||
using InkForge.Desktop.ViewModels.Documents;
|
||||
|
||||
namespace InkForge.Desktop.Views.Documents;
|
||||
|
||||
public partial class WelcomePageDocument : ReactiveUserControl<WelcomePageDocumentViewModel>
|
||||
{
|
||||
public WelcomePageDocument()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
12
app/InkForge.Desktop/Views/DocumentsView.axaml
Normal file
12
app/InkForge.Desktop/Views/DocumentsView.axaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:inkforge="using:InkForge.Desktop.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="InkForge.Desktop.Views.DocumentsView"
|
||||
x:DataType="inkforge:DocumentsViewModel">
|
||||
<DockControl Layout="{CompiledBinding Layout}" />
|
||||
</UserControl>
|
||||
24
app/InkForge.Desktop/Views/DocumentsView.axaml.cs
Normal file
24
app/InkForge.Desktop/Views/DocumentsView.axaml.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
|
||||
using InkForge.Desktop.ViewModels;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace InkForge.Desktop.Views;
|
||||
|
||||
public partial class DocumentsView : UserControl
|
||||
{
|
||||
public DocumentsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = CreateViewModel();
|
||||
}
|
||||
|
||||
private static DocumentsViewModel CreateViewModel()
|
||||
{
|
||||
return ActivatorUtilities.CreateInstance<DocumentsViewModel>(
|
||||
Application.Current!.GetValue(App.ServiceProviderProperty)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:reactiveui="http://reactiveui.net"
|
||||
xmlns:vm="using:InkForge.Desktop.ViewModels"
|
||||
xmlns:inkforge="app:InkForge"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="InkForge.Desktop.Views.LandingView"
|
||||
x:DataType="vm:LandingViewModel"
|
||||
inkforge:TopLevels.Register="{CompiledBinding}">
|
||||
<Grid RowDefinitions="Auto, *, Auto">
|
||||
<Label Content="Open Recent"
|
||||
Grid.Row="0" />
|
||||
|
||||
<DataGrid IsEnabled="False"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{CompiledBinding RecentItems}"
|
||||
Grid.Row="1">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Created"
|
||||
Binding="{CompiledBinding Created, StringFormat={}{0:d}}" />
|
||||
<DataGridTextColumn Header="Name"
|
||||
Width="*"
|
||||
Binding="{CompiledBinding Name}" />
|
||||
<DataGridTextColumn Header="Last Used"
|
||||
Binding="{CompiledBinding LastUsed, StringFormat={}{0:d}}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<Menu Grid.Row="2">
|
||||
<MenuItem Header="Create New"
|
||||
Command="{CompiledBinding CreateNew}" />
|
||||
<MenuItem Header="Open"
|
||||
IsEnabled="False" />
|
||||
<MenuItem Header="Open File"
|
||||
Command="{CompiledBinding OpenNew}" />
|
||||
</Menu>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Avalonia.ReactiveUI;
|
||||
|
||||
using InkForge.Desktop.ViewModels;
|
||||
|
||||
namespace InkForge.Desktop.Views;
|
||||
|
||||
public partial class LandingView : ReactiveUserControl<LandingViewModel>
|
||||
{
|
||||
public LandingView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,26 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:reactiveui="http://reactiveui.net"
|
||||
xmlns:inkforge="app:InkForge"
|
||||
xmlns:vm="using:InkForge.Desktop.ViewModels"
|
||||
xmlns:local="using:InkForge.Desktop.Views"
|
||||
mc:Ignorable="d"
|
||||
Width="800"
|
||||
Height="450"
|
||||
x:Class="InkForge.Desktop.Views.MainWindow"
|
||||
x:DataType="vm:AppViewModel"
|
||||
Title="MainWindow"
|
||||
inkforge:TopLevels.Register="{CompiledBinding}">
|
||||
<DockPanel>
|
||||
<NativeMenuBar />
|
||||
Title="MainWindow">
|
||||
<NativeMenu.Menu>
|
||||
<NativeMenu />
|
||||
</NativeMenu.Menu>
|
||||
|
||||
<reactiveui:ViewModelViewHost ViewModel="{CompiledBinding View}" />
|
||||
<DockPanel>
|
||||
<NativeMenuBar DockPanel.Dock="Top" />
|
||||
|
||||
<SplitView IsPaneOpen="true"
|
||||
DisplayMode="Inline">
|
||||
<SplitView.Pane>
|
||||
<local:WorkspacesView />
|
||||
</SplitView.Pane>
|
||||
|
||||
<local:DocumentsView />
|
||||
</SplitView>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
|
|
@ -1,11 +1,8 @@
|
|||
using Avalonia.Input;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
using InkForge.Desktop.ViewModels;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace InkForge.Desktop.Views;
|
||||
|
||||
public partial class MainWindow : ReactiveWindow<AppViewModel>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:reactiveui="http://reactiveui.net"
|
||||
xmlns:inkforge="app:InkForge"
|
||||
xmlns:vm="using:InkForge.Desktop.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="InkForge.Desktop.Views.WorkspaceView"
|
||||
x:DataType="vm:WorkspaceViewModel"
|
||||
inkforge:TopLevels.Register="{CompiledBinding}">
|
||||
<SplitView IsPaneOpen="true"
|
||||
DisplayMode="Inline"
|
||||
OpenPaneLength="300">
|
||||
<SplitView.Pane>
|
||||
<DockPanel x:Name="FilesView"
|
||||
Background="Transparent">
|
||||
<Grid ColumnDefinitions="*, Auto"
|
||||
DockPanel.Dock="Top">
|
||||
<TextBlock Text="Notes"
|
||||
FontWeight="Bold"
|
||||
Margin="3"
|
||||
Grid.Column="0" />
|
||||
|
||||
<StackPanel x:Name="ToolBar"
|
||||
Orientation="Horizontal"
|
||||
Spacing="3"
|
||||
Grid.Column="1">
|
||||
<Button>
|
||||
<inkforge:FluentSymbolIcon Symbol="document_add" />
|
||||
</Button>
|
||||
<Button>
|
||||
<inkforge:FluentSymbolIcon Symbol="arrow_clockwise" />
|
||||
</Button>
|
||||
<Button>
|
||||
<inkforge:FluentSymbolIcon Symbol="subtract_square_multiple" />
|
||||
</Button>
|
||||
|
||||
<StackPanel.Styles>
|
||||
<Style Selector="#ToolBar > :is(TemplatedControl)">
|
||||
<Setter Property="Background"
|
||||
Value="Transparent" />
|
||||
<Setter Property="Padding"
|
||||
Value="1" />
|
||||
<Setter Property="VerticalAlignment"
|
||||
Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="#FilesView:not(:pointerover) StackPanel">
|
||||
<Setter Property="IsVisible"
|
||||
Value="False" />
|
||||
</Style>
|
||||
</StackPanel.Styles>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<TreeView ScrollViewer.VerticalScrollBarVisibility="Visible" />
|
||||
</DockPanel>
|
||||
</SplitView.Pane>
|
||||
|
||||
<TabControl>
|
||||
<TabItem Header="Some Note.md">
|
||||
Hello There!
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</SplitView>
|
||||
</UserControl>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Avalonia.ReactiveUI;
|
||||
|
||||
using InkForge.Desktop.ViewModels;
|
||||
|
||||
namespace InkForge.Desktop.Views;
|
||||
|
||||
public partial class WorkspaceView : ReactiveUserControl<WorkspaceViewModel>
|
||||
{
|
||||
public WorkspaceView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:InkForge.Desktop.ViewModels.Workspaces"
|
||||
xmlns:inkforge="app:InkForge"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="InkForge.Desktop.Views.Workspaces.WorkspaceViewModel"
|
||||
x:DataType="vm:WorkspaceViewModel">
|
||||
|
||||
<Grid ColumnDefinitions="*, Auto"
|
||||
RowDefinitions="Auto, *">
|
||||
<TextBlock Grid.Column="0"
|
||||
Grid.Row="0" />
|
||||
|
||||
<StackPanel Classes="WorkspaceToolbar"
|
||||
Orientation="Horizontal"
|
||||
Spacing="3"
|
||||
Grid.Column="1"
|
||||
Grid.Row="0">
|
||||
<Button>
|
||||
<inkforge:FluentSymbolIcon Symbol="document_add" />
|
||||
</Button>
|
||||
<Button>
|
||||
<inkforge:FluentSymbolIcon Symbol="arrow_clockwise" />
|
||||
</Button>
|
||||
<Button>
|
||||
<inkforge:FluentSymbolIcon Symbol="subtract_square_multiple" />
|
||||
</Button>
|
||||
|
||||
<!-- <StackPanel.Styles>
|
||||
<Style Selector="#ToolBar > :is(TemplatedControl)">
|
||||
<Setter Property="Background"
|
||||
Value="Transparent" />
|
||||
<Setter Property="Padding"
|
||||
Value="1" />
|
||||
<Setter Property="VerticalAlignment"
|
||||
Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="#FilesView:not(:pointerover) StackPanel">
|
||||
<Setter Property="IsVisible"
|
||||
Value="False" />
|
||||
</Style>
|
||||
</StackPanel.Styles> -->
|
||||
</StackPanel>
|
||||
|
||||
<TreeView Grid.ColumnSpan="2"
|
||||
Grid.Row="1" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
13
app/InkForge.Desktop/Views/Workspaces/WorkspaceViewModel.cs
Normal file
13
app/InkForge.Desktop/Views/Workspaces/WorkspaceViewModel.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace InkForge.Desktop.Views.Workspaces;
|
||||
|
||||
public partial class WorkspaceViewModel : UserControl
|
||||
{
|
||||
public WorkspaceViewModel()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
33
app/InkForge.Desktop/Views/WorkspacesView.axaml
Normal file
33
app/InkForge.Desktop/Views/WorkspacesView.axaml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:reactiveui="http://reactiveui.net"
|
||||
xmlns:local="using:InkForge.Desktop.Views"
|
||||
xmlns:inkforge="app:InkForge"
|
||||
xmlns:vm="using:InkForge.Desktop.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="InkForge.Desktop.Views.WorkspacesView"
|
||||
x:DataType="vm:WorkspacesViewModel"
|
||||
Classes.HasWorkspace="{CompiledBinding Workspace}">
|
||||
|
||||
<UserControl.Styles>
|
||||
<Style Selector="local|WorkspacesView">
|
||||
<Style Selector="^:not(.HasWorkspace)">
|
||||
<Setter Property="Content">
|
||||
<Template>
|
||||
<TextBlock>
|
||||
No workspace selected.
|
||||
</TextBlock>
|
||||
</Template>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style Selector="^.HasWorkspace">
|
||||
<Setter Property="Content"
|
||||
Value="{CompiledBinding Workspace}" />
|
||||
</Style>
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
</UserControl>
|
||||
16
app/InkForge.Desktop/Views/WorkspacesView.axaml.cs
Normal file
16
app/InkForge.Desktop/Views/WorkspacesView.axaml.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
using InkForge.Desktop.ViewModels;
|
||||
|
||||
using Splat;
|
||||
|
||||
namespace InkForge.Desktop.Views;
|
||||
|
||||
public partial class WorkspacesView : UserControl
|
||||
{
|
||||
public WorkspacesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Locator.Current.GetService<WorkspacesViewModel>();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue