1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

UI - Implemented routing

This commit is contained in:
Robert 2021-10-11 22:56:42 +02:00
parent 5d8a541624
commit d062ceaf05
38 changed files with 343 additions and 207 deletions

View File

@ -2,25 +2,23 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Artemis.UI.Avalonia" xmlns:local="using:Artemis.UI.Avalonia"
xmlns:sty="using:FluentAvalonia.Styling" xmlns:sty="using:FluentAvalonia.Styling"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:uip="using:FluentAvalonia.UI.Controls.Primitives"
x:Class="Artemis.UI.Avalonia.App"> x:Class="Artemis.UI.Avalonia.App">
<Application.DataTemplates> <Application.DataTemplates>
<local:ViewLocator/> <local:ViewLocator />
</Application.DataTemplates> </Application.DataTemplates>
<Application.Styles> <Application.Styles>
<!-- Third party styles --> <!-- Third party styles -->
<sty:FluentAvaloniaTheme RequestedTheme="Dark" CustomAccentColor="#4db6ac"/> <sty:FluentAvaloniaTheme RequestedTheme="Dark" CustomAccentColor="#4db6ac" />
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml"/> <StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />
<!-- Grab the window styling from Avalonia --> <!-- Grab the window styling from Avalonia -->
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Window.xaml" /> <StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Window.xaml" />
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TitleBar.xaml" /> <StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TitleBar.xaml" />
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml" /> <StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml" />
<!-- Global styles --> <!-- Global styles -->
<StyleInclude Source="/Styles/Button.axaml"></StyleInclude> <StyleInclude Source="/Styles/Button.axaml" />
<StyleInclude Source="/Styles/Sidebar.axaml"></StyleInclude> <StyleInclude Source="/Styles/Sidebar.axaml" />
</Application.Styles> </Application.Styles>
</Application> </Application>

View File

@ -1,76 +1,72 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Controls\" /> <Folder Include="Controls\" />
<Folder Include="Models\" /> <Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" /> <AvaloniaResource Include="Assets\**" />
<Folder Include="Screens\Home\Views" /> </ItemGroup>
<Folder Include="Screens\Settings\Views" /> <ItemGroup>
<Folder Include="Screens\SurfaceEditor\Views" /> <PackageReference Include="Avalonia" Version="0.10.7" />
<Folder Include="Screens\Workshop\Views" /> <PackageReference Include="Avalonia.Desktop" Version="0.10.7" />
</ItemGroup> <PackageReference Include="Avalonia.Diagnostics" Version="0.10.7" />
<ItemGroup> <PackageReference Include="Avalonia.ReactiveUI" Version="0.10.7" />
<PackageReference Include="Avalonia" Version="0.10.7" /> <PackageReference Include="Avalonia.Svg.Skia" Version="0.10.7.2" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.7" /> <PackageReference Include="FluentAvaloniaUI" Version="1.1.3" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.7" /> <PackageReference Include="Live.Avalonia" Version="1.3.1" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.7" /> <PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.7.2" /> <PackageReference Include="Splat.Ninject" Version="13.1.22" />
<PackageReference Include="FluentAvaloniaUI" Version="1.1.3" /> </ItemGroup>
<PackageReference Include="Live.Avalonia" Version="1.3.1" /> <ItemGroup>
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" /> <ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
<PackageReference Include="Splat.Ninject" Version="13.1.22" /> <ProjectReference Include="..\Artemis.UI.Avalonia.Shared\Artemis.UI.Avalonia.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" /> <Compile Update="MainWindow.axaml.cs">
<ProjectReference Include="..\Artemis.UI.Avalonia.Shared\Artemis.UI.Avalonia.Shared.csproj" /> <DependentUpon>%(Filename)</DependentUpon>
</ItemGroup> </Compile>
<ItemGroup> <Compile Update="Screens\Root\Views\SidebarCategoryView.axaml.cs">
<Compile Update="MainWindow.axaml.cs"> <DependentUpon>%(Filename)</DependentUpon>
<DependentUpon>%(Filename)</DependentUpon> </Compile>
</Compile> <Compile Update="Screens\Root\Views\SidebarProfileConfigurationView.axaml.cs">
<Compile Update="Screens\Root\Views\SidebarCategoryView.axaml.cs"> <DependentUpon>%(Filename)</DependentUpon>
<DependentUpon>%(Filename)</DependentUpon> </Compile>
</Compile> <Compile Update="Screens\Root\Views\SidebarScreenView.axaml.cs">
<Compile Update="Screens\Root\Views\SidebarProfileConfigurationView.axaml.cs"> <DependentUpon>%(Filename)</DependentUpon>
<DependentUpon>%(Filename)</DependentUpon> </Compile>
</Compile> <Compile Update="Screens\Root\Views\SidebarView.axaml.cs">
<Compile Update="Screens\Root\Views\SidebarScreenView.axaml.cs"> <DependentUpon>%(Filename)</DependentUpon>
<DependentUpon>%(Filename)</DependentUpon> </Compile>
</Compile> <Compile Update="Screens\Sidebar\Views\SidebarView.axaml.cs">
<Compile Update="Screens\Root\Views\SidebarView.axaml.cs"> <DependentUpon>SidebarView.axaml</DependentUpon>
<DependentUpon>%(Filename)</DependentUpon> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Update="Screens\Sidebar\Views\SidebarView.axaml.cs"> <Compile Update="Screens\Root\Views\RootView.axaml.cs">
<DependentUpon>SidebarView.axaml</DependentUpon> <DependentUpon>RootView.axaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Update="Screens\Root\Views\RootView.axaml.cs"> </ItemGroup>
<DependentUpon>RootView.axaml</DependentUpon> <ItemGroup>
<SubType>Code</SubType> <UpToDateCheckInput Remove="Views\MainWindow.axaml" />
</Compile> </ItemGroup>
</ItemGroup> <ItemGroup>
<ItemGroup> <Content Include="Assets\Images\Logo\bow-black.ico" />
<UpToDateCheckInput Remove="Views\MainWindow.axaml" /> <Content Include="Assets\Images\Logo\bow-white.ico" />
</ItemGroup> <Content Include="Assets\Images\Logo\bow.ico" />
<ItemGroup> </ItemGroup>
<Content Include="Assets\Images\Logo\bow-black.ico" /> <ItemGroup>
<Content Include="Assets\Images\Logo\bow-white.ico" /> <Reference Include="RGB.NET.Core">
<Content Include="Assets\Images\Logo\bow.ico" /> <HintPath>..\..\..\RGB.NET\bin\net5.0\RGB.NET.Core.dll</HintPath>
</ItemGroup> </Reference>
<ItemGroup> </ItemGroup>
<Reference Include="RGB.NET.Core"> <ItemGroup>
<HintPath>..\..\..\RGB.NET\bin\net5.0\RGB.NET.Core.dll</HintPath> <Resource Include="Assets\Images\Logo\bow-black.ico" />
</Reference> <Resource Include="Assets\Images\Logo\bow-white.ico" />
</ItemGroup> <Resource Include="Assets\Images\Logo\bow-white.svg" />
<ItemGroup> <Resource Include="Assets\Images\Logo\bow.ico" />
<Resource Include="Assets\Images\Logo\bow-black.ico" /> <Resource Include="Assets\Images\Logo\bow.svg" />
<Resource Include="Assets\Images\Logo\bow-white.ico" /> </ItemGroup>
<Resource Include="Assets\Images\Logo\bow-white.svg" />
<Resource Include="Assets\Images\Logo\bow.ico" />
<Resource Include="Assets\Images\Logo\bow.svg" />
</ItemGroup>
</Project> </Project>

View File

@ -14,7 +14,6 @@ namespace Artemis.UI.Avalonia.Converters
/// <inheritdoc /> /// <inheritdoc />
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
return new SolidColorBrush(!(value is RGBColor color) return new SolidColorBrush(!(value is RGBColor color)
? new Color(0, 0, 0, 0) ? new Color(0, 0, 0, 0)
: new Color((byte) color.A, (byte) color.R, (byte) color.G, (byte) color.B)); : new Color((byte) color.A, (byte) color.R, (byte) color.G, (byte) color.B));

View File

@ -8,19 +8,8 @@ using Avalonia.Markup.Xaml;
namespace Artemis.UI.Avalonia.Converters namespace Artemis.UI.Avalonia.Converters
{ {
public class EnumToCollectionConverter : MarkupExtension, IValueConverter public class EnumToCollectionConverter : MarkupExtension, IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GetAllValuesAndDescriptions(value.GetType());
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
public override object ProvideValue(IServiceProvider serviceProvider) public override object ProvideValue(IServiceProvider serviceProvider)
{ {
return this; return this;
@ -44,5 +33,15 @@ namespace Artemis.UI.Avalonia.Converters
return Enum.GetValues(t).Cast<Enum>().Select(e => new Tuple<object, object>(e, Description(e))).ToList(); return Enum.GetValues(t).Cast<Enum>().Select(e => new Tuple<object, object>(e, Description(e))).ToList();
} }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GetAllValuesAndDescriptions(value.GetType());
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
} }
} }

View File

@ -8,7 +8,6 @@ namespace Artemis.UI.Avalonia.Converters
{ {
public class ValuesAdditionConverter : IMultiValueConverter public class ValuesAdditionConverter : IMultiValueConverter
{ {
/// <inheritdoc /> /// <inheritdoc />
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture) public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
{ {

View File

@ -2,7 +2,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveUi="http://reactiveui.net"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.MainWindow" x:Class="Artemis.UI.Avalonia.MainWindow"
Icon="/Assets/avalonia-logo.ico" Icon="/Assets/avalonia-logo.ico"

View File

@ -5,7 +5,7 @@ using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia namespace Artemis.UI.Avalonia
{ {
public partial class MainWindow : ReactiveWindow<RootViewModel> public class MainWindow : ReactiveWindow<RootViewModel>
{ {
public MainWindow() public MainWindow()
{ {

View File

@ -1,5 +1,6 @@
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Avalonia.Screens.Root.ViewModels; using Artemis.UI.Avalonia.Screens.Root.ViewModels;
using ReactiveUI;
namespace Artemis.UI.Avalonia.Ninject.Factories namespace Artemis.UI.Avalonia.Ninject.Factories
{ {
@ -9,6 +10,7 @@ namespace Artemis.UI.Avalonia.Ninject.Factories
public interface ISidebarVmFactory : IVmFactory public interface ISidebarVmFactory : IVmFactory
{ {
SidebarViewModel SidebarViewModel(IScreen hostScreen);
SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory); SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory);
SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration); SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration);
} }

View File

@ -1,29 +1,29 @@
using System; using Avalonia;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Ninject; using Ninject;
using ReactiveUI;
using Splat;
using Splat.Ninject;
namespace Artemis.UI.Avalonia namespace Artemis.UI.Avalonia
{ {
class Program internal class Program
{ {
private static StandardKernel _kernel; private static StandardKernel _kernel;
// Initialization code. Don't use any Avalonia, third-party APIs or any // Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break. // yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp() public static void Main(string[] args)
.StartWithClassicDesktopLifetime(args); {
BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}
// Avalonia configuration, don't remove; also used by visual designer. // Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() {
return AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.LogToTrace() .LogToTrace()
.UseReactiveUI(); .UseReactiveUI();
}
} }
} }

View File

@ -4,14 +4,9 @@ namespace Artemis.UI.Avalonia.Screens.Home.ViewModels
{ {
public class HomeViewModel : MainScreenViewModel public class HomeViewModel : MainScreenViewModel
{ {
public HomeViewModel(IScreen hostScreens) : base(hostScreens, "home") public HomeViewModel(IScreen hostScreen) : base(hostScreen, "home")
{ {
DisplayName = "Home"; DisplayName = "Home";
} }
public void OpenUrl(string url)
{
Core.Utilities.OpenUrl(url);
}
} }
} }

View File

@ -0,0 +1,8 @@
<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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.Screens.Home.Views.HomeView">
Home :>
</UserControl>

View File

@ -0,0 +1,19 @@
using Artemis.UI.Avalonia.Screens.Home.ViewModels;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.Home.Views
{
public class HomeView : ReactiveUserControl<HomeViewModel>
{
public HomeView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -2,7 +2,7 @@
namespace Artemis.UI.Avalonia.Screens namespace Artemis.UI.Avalonia.Screens
{ {
public abstract class MainScreenViewModel : ViewModelBase, IRoutableViewModel public abstract class MainScreenViewModel : ActivatableViewModelBase, IRoutableViewModel
{ {
protected MainScreenViewModel(IScreen hostScreen, string urlPathSegment) protected MainScreenViewModel(IScreen hostScreen, string urlPathSegment)
{ {

View File

@ -0,0 +1,6 @@
namespace Artemis.UI.Avalonia.Screens.ProfileEditor.ViewModels
{
public class ProfileEditorViewModel : ActivatableViewModelBase
{
}
}

View File

@ -0,0 +1,8 @@
<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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.Screens.ProfileEditor.Views.ProfileEditorView">
Welcome to Avalonia!
</UserControl>

View File

@ -0,0 +1,19 @@
using Artemis.UI.Avalonia.Screens.ProfileEditor.ViewModels;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.ProfileEditor.Views
{
public class ProfileEditorView : ReactiveUserControl<ProfileEditorViewModel>
{
public ProfileEditorView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -1,19 +1,17 @@
using System; using Artemis.Core.Services;
using System.Reactive; using Artemis.UI.Avalonia.Ninject.Factories;
using Artemis.Core.Services;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.Root.ViewModels namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
{ {
public class RootViewModel : ViewModelBase, IScreen, IActivatableViewModel public class RootViewModel : ActivatableViewModelBase, IScreen
{ {
private readonly ICoreService _coreService; private readonly ICoreService _coreService;
public RootViewModel(ICoreService coreService, SidebarViewModel sidebarViewModel) public RootViewModel(ICoreService coreService, ISidebarVmFactory sidebarVmFactory)
{ {
Router = new RoutingState(); Router = new RoutingState();
SidebarViewModel = sidebarViewModel; SidebarViewModel = sidebarVmFactory.SidebarViewModel(this);
SidebarViewModel.Router = Router;
_coreService = coreService; _coreService = coreService;
_coreService.Initialize(); _coreService.Initialize();
@ -21,9 +19,6 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
public SidebarViewModel SidebarViewModel { get; } public SidebarViewModel SidebarViewModel { get; }
/// <inheritdoc />
public ViewModelActivator Activator { get; } = new();
/// <inheritdoc /> /// <inheritdoc />
public RoutingState Router { get; } public RoutingState Router { get; }
} }

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Reactive.Linq;
using Material.Icons; using Material.Icons;
using Ninject; using Ninject;
using Ninject.Parameters;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.Root.ViewModels namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
@ -12,9 +12,11 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
{ {
} }
public override MainScreenViewModel CreateInstance(IKernel kernel) public override Type ScreenType => typeof(T);
public override MainScreenViewModel CreateInstance(IKernel kernel, IScreen screen)
{ {
return kernel.Get<T>(); return kernel.Get<T>(new ConstructorArgument("hostScreen", screen));
} }
} }
@ -29,7 +31,8 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
public MaterialIconKind Icon { get; } public MaterialIconKind Icon { get; }
public string DisplayName { get; } public string DisplayName { get; }
public abstract MainScreenViewModel CreateInstance(IKernel kernel); public abstract Type ScreenType { get; }
public abstract MainScreenViewModel CreateInstance(IKernel kernel, IScreen screen);
public bool IsActive(IObservable<IRoutableViewModel?> routerCurrentViewModel) public bool IsActive(IObservable<IRoutableViewModel?> routerCurrentViewModel)
{ {

View File

@ -1,5 +1,7 @@
using System.Collections.ObjectModel; using System;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Avalonia.Ninject.Factories; using Artemis.UI.Avalonia.Ninject.Factories;
@ -14,20 +16,19 @@ using RGB.NET.Core;
namespace Artemis.UI.Avalonia.Screens.Root.ViewModels namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
{ {
public class SidebarViewModel : ViewModelBase public class SidebarViewModel : ActivatableViewModelBase
{ {
private readonly IKernel _kernel; private readonly IScreen _hostScreen;
private readonly IProfileService _profileService; private readonly IProfileService _profileService;
private readonly IRgbService _rgbService; private readonly IRgbService _rgbService;
private readonly ISidebarVmFactory _sidebarVmFactory; private readonly ISidebarVmFactory _sidebarVmFactory;
private ArtemisDevice? _headerDevice; private ArtemisDevice? _headerDevice;
private SidebarScreenViewModel _selectedSidebarScreen; private SidebarScreenViewModel? _selectedSidebarScreen;
private RoutingState _router;
public SidebarViewModel(IKernel kernel, IProfileService profileService, IRgbService rgbService, ISidebarVmFactory sidebarVmFactory) public SidebarViewModel(IScreen hostScreen, IKernel kernel, IProfileService profileService, IRgbService rgbService, ISidebarVmFactory sidebarVmFactory)
{ {
_kernel = kernel; _hostScreen = hostScreen;
_profileService = profileService; _profileService = profileService;
_rgbService = rgbService; _rgbService = rgbService;
_sidebarVmFactory = sidebarVmFactory; _sidebarVmFactory = sidebarVmFactory;
@ -43,6 +44,17 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
UpdateProfileCategories(); UpdateProfileCategories();
UpdateHeaderDevice(); UpdateHeaderDevice();
this.WhenActivated(disposables =>
{
this.WhenAnyObservable(vm => vm._hostScreen.Router.CurrentViewModel)
.WhereNotNull()
.Subscribe(c => SelectedSidebarScreen = SidebarScreens.FirstOrDefault(s => s.ScreenType == c.GetType()))
.DisposeWith(disposables);
this.WhenAnyValue(vm => vm.SelectedSidebarScreen)
.WhereNotNull()
.Subscribe(s => _hostScreen.Router.Navigate.Execute(s.CreateInstance(kernel, _hostScreen)));
});
} }
public ObservableCollection<SidebarScreenViewModel> SidebarScreens { get; } public ObservableCollection<SidebarScreenViewModel> SidebarScreens { get; }
@ -54,21 +66,10 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
set => this.RaiseAndSetIfChanged(ref _headerDevice, value); set => this.RaiseAndSetIfChanged(ref _headerDevice, value);
} }
public SidebarScreenViewModel SelectedSidebarScreen public SidebarScreenViewModel? SelectedSidebarScreen
{ {
get => _selectedSidebarScreen; get => _selectedSidebarScreen;
set set => this.RaiseAndSetIfChanged(ref _selectedSidebarScreen, value);
{
this.RaiseAndSetIfChanged(ref _selectedSidebarScreen, value);
// if (!SelectedSidebarScreen.IsActive(Router.CurrentViewModel))
// Router.Navigate.Execute(SelectedSidebarScreen.CreateInstance(_kernel)).Subscribe();
}
}
public RoutingState Router
{
get => _router;
set => this.RaiseAndSetIfChanged(ref _router, value);
} }
public SidebarCategoryViewModel AddProfileCategoryViewModel(ProfileCategory profileCategory) public SidebarCategoryViewModel AddProfileCategoryViewModel(ProfileCategory profileCategory)

View File

@ -23,6 +23,11 @@
</ExperimentalAcrylicBorder> </ExperimentalAcrylicBorder>
<Border Grid.Column="1" Background="#101010" IsHitTestVisible="False" /> <Border Grid.Column="1" Background="#101010" IsHitTestVisible="False" />
<reactiveUi:RoutedViewHost Grid.Column="1" Router="{Binding Router}" Margin="0 20 0 0" Padding="15" />
<reactiveUi:RoutedViewHost Grid.Column="1" Margin="0 20 0 0" Padding="15" Router="{Binding Router}">
<reactiveUi:RoutedViewHost.PageTransition>
<CrossFade Duration="0.1" />
</reactiveUi:RoutedViewHost.PageTransition>
</reactiveUi:RoutedViewHost>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -8,10 +8,10 @@
x:Class="Artemis.UI.Avalonia.Screens.Root.Views.SidebarCategoryView"> x:Class="Artemis.UI.Avalonia.Screens.Root.Views.SidebarCategoryView">
<UserControl.Styles> <UserControl.Styles>
<Style Selector=":is(Button).category-button"> <Style Selector=":is(Button).category-button">
<Setter Property="IsVisible" Value="False"></Setter> <Setter Property="IsVisible" Value="False" />
</Style> </Style>
<Style Selector="Grid#ContainerGrid:pointerover :is(Button).category-button"> <Style Selector="Grid#ContainerGrid:pointerover :is(Button).category-button">
<Setter Property="IsVisible" Value="True"></Setter> <Setter Property="IsVisible" Value="True" />
</Style> </Style>
<Style Selector="avalonia|MaterialIcon.chevron-collapsed"> <Style Selector="avalonia|MaterialIcon.chevron-collapsed">

View File

@ -73,12 +73,11 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<controls:ProfileConfigurationIcon Grid.Column="0" <controls:ProfileConfigurationIcon Grid.Column="0"
x:Name="ProfileIcon" x:Name="ProfileIcon"
VerticalAlignment="Center" VerticalAlignment="Center"
ConfigurationIcon="{Binding ProfileConfiguration.Icon}" ConfigurationIcon="{Binding ProfileConfiguration.Icon}"
Width="20" Width="20"
Height="20"> Height="20" />
</controls:ProfileConfigurationIcon>
<TextBlock Grid.Column="1" <TextBlock Grid.Column="1"
x:Name="ProfileName" x:Name="ProfileName"
@ -111,7 +110,7 @@
Grid.Column="2" Grid.Column="2"
ToolTip.Tip="View properties" ToolTip.Tip="View properties"
HorizontalAlignment="Right"> HorizontalAlignment="Right">
<avalonia:MaterialIcon Kind="Cog"/> <avalonia:MaterialIcon Kind="Cog" />
</Button> </Button>
<ToggleButton Classes="icon-button icon-button-small" <ToggleButton Classes="icon-button icon-button-small"
Grid.Column="3" Grid.Column="3"

View File

@ -5,8 +5,8 @@
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.Screens.Root.Views.SidebarScreenView"> x:Class="Artemis.UI.Avalonia.Screens.Root.Views.SidebarScreenView">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<avalonia:MaterialIcon Kind="{Binding Icon}" Width="16" Height="16" /> <avalonia:MaterialIcon Kind="{Binding Icon}" Width="16" Height="16" />
<TextBlock FontSize="12" Margin="10 0" VerticalAlignment="Center" Text="{Binding DisplayName}" /> <TextBlock FontSize="12" Margin="10 0" VerticalAlignment="Center" Text="{Binding DisplayName}" />
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -26,26 +26,26 @@
<Border Grid.Column="0" <Border Grid.Column="0"
Grid.ColumnSpan="2"> Grid.ColumnSpan="2">
<shared:DeviceVisualizer Device="{Binding HeaderDevice}" <shared:DeviceVisualizer Device="{Binding HeaderDevice}"
ShowColors="True" ShowColors="True"
VerticalAlignment="Center" VerticalAlignment="Center"
HorizontalAlignment="Center"> HorizontalAlignment="Center">
<shared:DeviceVisualizer.RenderTransform> <shared:DeviceVisualizer.RenderTransform>
<TransformGroup> <TransformGroup>
<RotateTransform Angle="20" /> <RotateTransform Angle="20" />
<ScaleTransform ScaleX="2" ScaleY="2" /> <ScaleTransform ScaleX="2" ScaleY="2" />
</TransformGroup> </TransformGroup>
</shared:DeviceVisualizer.RenderTransform> </shared:DeviceVisualizer.RenderTransform>
</shared:DeviceVisualizer> </shared:DeviceVisualizer>
<Border.OpacityMask> <Border.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,60"> <LinearGradientBrush StartPoint="0,0" EndPoint="0,60">
<GradientStop Color="White" Offset="0"></GradientStop> <GradientStop Color="White" Offset="0" />
<GradientStop Color="Transparent" Offset="1"></GradientStop> <GradientStop Color="Transparent" Offset="1" />
</LinearGradientBrush> </LinearGradientBrush>
</Border.OpacityMask> </Border.OpacityMask>
</Border> </Border>
<Image Grid.Column="0" > <Image Grid.Column="0">
<Image.Source> <Image.Source>
<svg:SvgImage Source="/Assets/Images/Logo/bow.svg" /> <svg:SvgImage Source="/Assets/Images/Logo/bow.svg" />
</Image.Source> </Image.Source>

View File

@ -1,9 +1,10 @@
using Avalonia.Controls; using Artemis.UI.Avalonia.Screens.Root.ViewModels;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.Root.Views namespace Artemis.UI.Avalonia.Screens.Root.Views
{ {
public class SidebarView : UserControl public class SidebarView : ReactiveUserControl<SidebarViewModel>
{ {
public SidebarView() public SidebarView()
{ {

View File

@ -4,7 +4,7 @@ namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
{ {
public class SettingsViewModel : MainScreenViewModel public class SettingsViewModel : MainScreenViewModel
{ {
public SettingsViewModel(IScreen hostScreens) : base(hostScreens, "settings") public SettingsViewModel(IScreen hostScreen) : base(hostScreen, "settings")
{ {
DisplayName = "Settings"; DisplayName = "Settings";
} }

View File

@ -0,0 +1,8 @@
<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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.Screens.Settings.Views.SettingsView">
Settings! :D
</UserControl>

View File

@ -0,0 +1,19 @@
using Artemis.UI.Avalonia.Screens.Settings.ViewModels;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.Settings.Views
{
public class SettingsView : ReactiveUserControl<SettingsViewModel>
{
public SettingsView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -4,7 +4,7 @@ namespace Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels
{ {
public class SurfaceEditorViewModel : MainScreenViewModel public class SurfaceEditorViewModel : MainScreenViewModel
{ {
public SurfaceEditorViewModel(IScreen hostScreens) : base(hostScreens, "surface-editor") public SurfaceEditorViewModel(IScreen hostScreen) : base(hostScreen, "surface-editor")
{ {
DisplayName = "Surface Editor"; DisplayName = "Surface Editor";
} }

View File

@ -0,0 +1,8 @@
<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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.Screens.SurfaceEditor.Views.SurfaceEditorView">
Surface editor c:
</UserControl>

View File

@ -0,0 +1,19 @@
using Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.SurfaceEditor.Views
{
public class SurfaceEditorView : ReactiveUserControl<SurfaceEditorViewModel>
{
public SurfaceEditorView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -4,7 +4,7 @@ namespace Artemis.UI.Avalonia.Screens.Workshop.ViewModels
{ {
public class WorkshopViewModel : MainScreenViewModel public class WorkshopViewModel : MainScreenViewModel
{ {
public WorkshopViewModel(IScreen hostScreens) : base(hostScreens, "workshop") public WorkshopViewModel(IScreen hostScreen) : base(hostScreen, "workshop")
{ {
DisplayName = "Workshop"; DisplayName = "Workshop";
} }

View File

@ -0,0 +1,8 @@
<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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.Screens.Workshop.Views.WorkshopView">
Workshop!! :3
</UserControl>

View File

@ -0,0 +1,19 @@
using Artemis.UI.Avalonia.Screens.Workshop.ViewModels;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.Workshop.Views
{
public class WorkshopView : ReactiveUserControl<WorkshopViewModel>
{
public WorkshopView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -2,23 +2,23 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"> xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
<!-- Preview --> <!-- Preview -->
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20"> <Border Padding="20">
<StackPanel> <StackPanel>
<TextBlock Margin="0 5 0 0">Button.icon-button</TextBlock> <TextBlock Margin="0 5 0 0">Button.icon-button</TextBlock>
<Button Classes="icon-button"> <Button Classes="icon-button">
<avalonia:MaterialIcon Kind="Cog"></avalonia:MaterialIcon> <avalonia:MaterialIcon Kind="Cog" />
</Button> </Button>
<TextBlock Margin="0 5 0 0">Button.icon-button icon-button-small</TextBlock> <TextBlock Margin="0 5 0 0">Button.icon-button icon-button-small</TextBlock>
<Button Classes="icon-button icon-button-small"> <Button Classes="icon-button icon-button-small">
<avalonia:MaterialIcon Kind="Cog"></avalonia:MaterialIcon> <avalonia:MaterialIcon Kind="Cog" />
</Button> </Button>
<TextBlock Margin="0 5 0 0">ToggleButton.icon-button</TextBlock> <TextBlock Margin="0 5 0 0">ToggleButton.icon-button</TextBlock>
<ToggleButton Classes="icon-button"> <ToggleButton Classes="icon-button">
<avalonia:MaterialIcon Kind="Cog"></avalonia:MaterialIcon> <avalonia:MaterialIcon Kind="Cog" />
</ToggleButton> </ToggleButton>
<TextBlock Margin="0 5 0 0">HyperlinkButton.icon-button</TextBlock> <TextBlock Margin="0 5 0 0">HyperlinkButton.icon-button</TextBlock>
@ -36,17 +36,17 @@
<!-- Styles --> <!-- Styles -->
<Style Selector=":is(Button).icon-button"> <Style Selector=":is(Button).icon-button">
<Setter Property="BorderBrush" Value="Transparent"></Setter> <Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent" />
<Setter Property="Padding" Value="5.5"/> <Setter Property="Padding" Value="5.5" />
</Style> </Style>
<Style Selector=":is(Button).icon-button-small"> <Style Selector=":is(Button).icon-button-small">
<Setter Property="Padding" Value="2"/> <Setter Property="Padding" Value="2" />
</Style> </Style>
<Style Selector=":is(Button).icon-button-small avalonia|MaterialIcon"> <Style Selector=":is(Button).icon-button-small avalonia|MaterialIcon">
<Setter Property="Width" Value="14"></Setter> <Setter Property="Width" Value="14" />
<Setter Property="Height" Value="14"></Setter> <Setter Property="Height" Value="14" />
</Style> </Style>
<Style Selector="controls|HyperlinkButton.icon-button"> <Style Selector="controls|HyperlinkButton.icon-button">

View File

@ -1,6 +1,5 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:views="clr-namespace:Artemis.UI.Avalonia.Screens.Root.Views">
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20"> <Border Padding="20">
<ListBox Classes="sidebar-listbox"> <ListBox Classes="sidebar-listbox">
@ -14,7 +13,7 @@
<!-- Add Styles Here --> <!-- Add Styles Here -->
<Style Selector="ListBox.sidebar-listbox ListBoxItem"> <Style Selector="ListBox.sidebar-listbox ListBoxItem">
<Setter Property="Margin" Value="0 2.5"></Setter> <Setter Property="Margin" Value="0 2.5" />
<Setter Property="MinHeight" Value="35"></Setter> <Setter Property="MinHeight" Value="35" />
</Style> </Style>
</Styles> </Styles>

View File

@ -15,7 +15,7 @@ namespace Artemis.UI.Avalonia
if (type != null) if (type != null)
return (Control) Activator.CreateInstance(type)!; return (Control) Activator.CreateInstance(type)!;
return new TextBlock { Text = "Not Found: " + name }; return new TextBlock {Text = "Not Found: " + name};
} }
public bool Match(object data) public bool Match(object data)

View File

@ -2,7 +2,7 @@
namespace Artemis.UI.Avalonia namespace Artemis.UI.Avalonia
{ {
public class ViewModelBase : ReactiveObject public abstract class ViewModelBase : ReactiveObject
{ {
private string? _displayName; private string? _displayName;
@ -12,4 +12,9 @@ namespace Artemis.UI.Avalonia
set => this.RaiseAndSetIfChanged(ref _displayName, value); set => this.RaiseAndSetIfChanged(ref _displayName, value);
} }
} }
public abstract class ActivatableViewModelBase : ViewModelBase, IActivatableViewModel
{
public ViewModelActivator Activator { get; } = new();
}
} }