mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Sidebar - Added subitems support
This commit is contained in:
1 parent
229d93901b
commit
99a365be0b
33 files changed
+572
-162
No files matched your search
@@ -99,7 +99,6 @@
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox.sidebar-listbox ListBoxItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="(i:Interaction.Behaviors)">
|
||||
<i:BehaviorCollectionTemplate>
|
||||
<i:BehaviorCollection>
|
||||
|
||||
@@ -76,8 +76,8 @@
|
||||
x:Name="ProfileIcon"
|
||||
VerticalAlignment="Center"
|
||||
ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Width="22"
|
||||
Height="22"
|
||||
Margin="0 0 5 0">
|
||||
<shared:ProfileConfigurationIcon.Transitions>
|
||||
<Transitions>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:vm="clr-namespace:Artemis.UI.Screens.Sidebar;assembly=Artemis.UI"
|
||||
x:DataType="vm:SidebarScreenViewModel"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Sidebar.SidebarScreenView">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Width="16" Height="16" />
|
||||
<TextBlock FontSize="12" Margin="10 0" VerticalAlignment="Center" Text="{CompiledBinding DisplayName}" />
|
||||
x:Class="Artemis.UI.Screens.Sidebar.SidebarScreenView"
|
||||
x:DataType="vm:SidebarScreenViewModel">
|
||||
<StackPanel Orientation="Horizontal" Background="Transparent" PointerReleased="InputElement_OnPointerReleased" DoubleTapped="InputElement_OnDoubleTapped">
|
||||
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Width="18" Height="18" />
|
||||
<TextBlock Margin="10 0" VerticalAlignment="Center" FontSize="13" Text="{CompiledBinding DisplayName}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,13 +1,25 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar;
|
||||
|
||||
public partial class SidebarScreenView : UserControl
|
||||
public partial class SidebarScreenView : ReactiveUserControl<SidebarScreenViewModel>
|
||||
{
|
||||
public SidebarScreenView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
// if (ViewModel != null)
|
||||
// ViewModel.IsExpanded = !ViewModel.IsExpanded;
|
||||
}
|
||||
|
||||
private void InputElement_OnDoubleTapped(object? sender, TappedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Avalonia.Threading;
|
||||
using Material.Icons;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar;
|
||||
|
||||
public class SidebarScreenViewModel : ViewModelBase
|
||||
{
|
||||
public SidebarScreenViewModel(MaterialIconKind icon, string displayName, string path)
|
||||
private bool _isExpanded;
|
||||
|
||||
public SidebarScreenViewModel(MaterialIconKind icon, string displayName, string path, string? rootPath = null, ObservableCollection<SidebarScreenViewModel>? screens = null)
|
||||
{
|
||||
Icon = icon;
|
||||
Path = path;
|
||||
RootPath = rootPath ?? path;
|
||||
DisplayName = displayName;
|
||||
Screens = screens ?? new ObservableCollection<SidebarScreenViewModel>();
|
||||
}
|
||||
|
||||
|
||||
public MaterialIconKind Icon { get; }
|
||||
public string Path { get; }
|
||||
public string RootPath { get; }
|
||||
|
||||
public ObservableCollection<SidebarScreenViewModel> Screens { get; }
|
||||
|
||||
public bool IsExpanded
|
||||
{
|
||||
get => _isExpanded;
|
||||
set => RaiseAndSetIfChanged(ref _isExpanded, value);
|
||||
}
|
||||
|
||||
public bool Matches(string? path)
|
||||
{
|
||||
if (path == null)
|
||||
return false;
|
||||
return path.StartsWith(Path, StringComparison.InvariantCultureIgnoreCase);
|
||||
return path.StartsWith(RootPath, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public SidebarScreenViewModel? GetMatch(string path)
|
||||
{
|
||||
foreach (SidebarScreenViewModel sidebarScreenViewModel in Screens)
|
||||
{
|
||||
SidebarScreenViewModel? match = sidebarScreenViewModel.GetMatch(path);
|
||||
if (match != null)
|
||||
return match;
|
||||
}
|
||||
|
||||
return Screens.FirstOrDefault(s => s.Matches(path));
|
||||
}
|
||||
|
||||
public void ExpandIfRequired(SidebarScreenViewModel selected)
|
||||
{
|
||||
if (selected == this && Screens.Any())
|
||||
{
|
||||
IsExpanded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Screens.Contains(selected))
|
||||
IsExpanded = true;
|
||||
|
||||
foreach (SidebarScreenViewModel sidebarScreenViewModel in Screens)
|
||||
sidebarScreenViewModel.ExpandIfRequired(selected);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:sidebar="clr-namespace:Artemis.UI.Screens.Sidebar"
|
||||
mc:Ignorable="d" d:DesignWidth="240" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Sidebar.SidebarView"
|
||||
@@ -20,11 +20,23 @@
|
||||
</Grid>
|
||||
|
||||
<!-- Built-in screens -->
|
||||
<ListBox Classes="sidebar-listbox"
|
||||
Grid.Row="1"
|
||||
Margin="10 2"
|
||||
ItemsSource="{CompiledBinding SidebarScreens}"
|
||||
SelectedItem="{CompiledBinding SelectedSidebarScreen}" />
|
||||
<TreeView Grid.Row="1"
|
||||
Margin="10 2"
|
||||
ItemsSource="{CompiledBinding SidebarScreen.Screens}"
|
||||
SelectedItem="{CompiledBinding SelectedScreen}"
|
||||
ItemContainerTheme="{StaticResource MenuTreeViewItem}">
|
||||
<TreeView.Styles>
|
||||
<Style Selector="TreeViewItem">
|
||||
<Setter Property="IsExpanded" Value="{CompiledBinding IsExpanded, Mode=TwoWay, DataType=sidebar:SidebarScreenViewModel}" />
|
||||
</Style>
|
||||
</TreeView.Styles>
|
||||
<TreeView.ItemTemplate>
|
||||
<TreeDataTemplate ItemsSource="{CompiledBinding Screens}">
|
||||
<ContentControl Content="{CompiledBinding}" />
|
||||
</TreeDataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
|
||||
<Border Grid.Row="2" Margin="8" Height="1" Background="{DynamicResource ButtonBorderBrush}"></Border>
|
||||
|
||||
<!-- Categories -->
|
||||
@@ -41,51 +53,51 @@
|
||||
<!-- Bottom buttons -->
|
||||
<Border Grid.Row="4" Margin="8" Height="1" Background="{DynamicResource ButtonBorderBrush}"></Border>
|
||||
<WrapPanel Grid.Row="5" Orientation="Horizontal" HorizontalAlignment="Left" Margin="5 0 5 5">
|
||||
<controls:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View website"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=sidebar">
|
||||
<ui:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View website"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=sidebar">
|
||||
<avalonia:MaterialIcon Kind="Web" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
<controls:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View GitHub repository"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://github.com/Artemis-RGB/Artemis">
|
||||
</ui:HyperlinkButton>
|
||||
<ui:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View GitHub repository"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://github.com/Artemis-RGB/Artemis">
|
||||
<avalonia:MaterialIcon Kind="Github" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
<controls:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View Wiki"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://wiki.artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=sidebar">
|
||||
</ui:HyperlinkButton>
|
||||
<ui:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View Wiki"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://wiki.artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=sidebar">
|
||||
<avalonia:MaterialIcon Kind="BookOpenOutline" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
<controls:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="Join our Discord"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://discord.gg/S3MVaC9">
|
||||
</ui:HyperlinkButton>
|
||||
<ui:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="Join our Discord"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://discord.gg/S3MVaC9">
|
||||
<avalonia:MaterialIcon Kind="Chat" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
<controls:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View donation options"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://wiki.artemis-rgb.com/en/donating?mtm_campaign=artemis&mtm_kwd=sidebar">
|
||||
</ui:HyperlinkButton>
|
||||
<ui:HyperlinkButton Classes="icon-button"
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View donation options"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://wiki.artemis-rgb.com/en/donating?mtm_campaign=artemis&mtm_kwd=sidebar">
|
||||
<avalonia:MaterialIcon Kind="Gift" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
</ui:HyperlinkButton>
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
@@ -23,34 +24,38 @@ namespace Artemis.UI.Screens.Sidebar;
|
||||
|
||||
public class SidebarViewModel : ActivatableViewModelBase
|
||||
{
|
||||
public const string ROOT_SCREEN = "root";
|
||||
|
||||
private readonly IRouter _router;
|
||||
private readonly IWindowService _windowService;
|
||||
private SidebarScreenViewModel? _selectedSidebarScreen;
|
||||
private ReadOnlyObservableCollection<SidebarCategoryViewModel> _sidebarCategories = new(new ObservableCollection<SidebarCategoryViewModel>());
|
||||
private SidebarScreenViewModel? _selectedScreen;
|
||||
|
||||
public SidebarViewModel(IRouter router, IProfileService profileService, IWindowService windowService, ISidebarVmFactory sidebarVmFactory)
|
||||
{
|
||||
_router = router;
|
||||
_windowService = windowService;
|
||||
|
||||
SidebarScreens = new ObservableCollection<SidebarScreenViewModel>
|
||||
SidebarScreen = new SidebarScreenViewModel(MaterialIconKind.Abacus, ROOT_SCREEN, "", null, new ObservableCollection<SidebarScreenViewModel>()
|
||||
{
|
||||
new(MaterialIconKind.Home, "Home", "home"),
|
||||
#if DEBUG
|
||||
new(MaterialIconKind.TestTube, "Workshop", "workshop"),
|
||||
#endif
|
||||
new(MaterialIconKind.HomeOutline, "Home", "home"),
|
||||
new(MaterialIconKind.TestTube, "Workshop", "workshop", null, new ObservableCollection<SidebarScreenViewModel>
|
||||
{
|
||||
new(MaterialIconKind.FolderVideo, "Profiles", "workshop/profiles/1", "workshop/profiles"),
|
||||
new(MaterialIconKind.KeyboardVariant, "Layouts", "workshop/layouts/1", "workshop/layouts"),
|
||||
}),
|
||||
new(MaterialIconKind.Devices, "Surface Editor", "surface-editor"),
|
||||
new(MaterialIconKind.Cog, "Settings", "settings")
|
||||
};
|
||||
new(MaterialIconKind.SettingsOutline, "Settings", "settings")
|
||||
});
|
||||
|
||||
AddCategory = ReactiveCommand.CreateFromTask(ExecuteAddCategory);
|
||||
this.WhenAnyValue(vm => vm.SelectedScreen).WhereNotNull().Subscribe(NavigateToScreen);
|
||||
this.WhenAnyValue(vm => vm.SelectedScreen).WhereNotNull().Subscribe(s => SidebarScreen.ExpandIfRequired(s));
|
||||
|
||||
SourceList<ProfileCategory> profileCategories = new();
|
||||
|
||||
this.WhenAnyValue(vm => vm.SelectedSidebarScreen).WhereNotNull().Subscribe(NavigateToScreen);
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
_router.CurrentPath.WhereNotNull().Subscribe(r => SelectedSidebarScreen = SidebarScreens.FirstOrDefault(s => s.Matches(r))).DisposeWith(d);
|
||||
_router.CurrentPath.WhereNotNull().Subscribe(r => SelectedScreen = SidebarScreen.GetMatch(r)).DisposeWith(d);
|
||||
|
||||
Observable.FromEventPattern<ProfileCategoryEventArgs>(x => profileService.ProfileCategoryAdded += x, x => profileService.ProfileCategoryAdded -= x)
|
||||
.Subscribe(e => profileCategories.Add(e.EventArgs.ProfileCategory))
|
||||
@@ -75,11 +80,17 @@ public class SidebarViewModel : ActivatableViewModelBase
|
||||
.DisposeWith(d);
|
||||
|
||||
SidebarCategories = categoryViewModels;
|
||||
SelectedSidebarScreen = SidebarScreens.First();
|
||||
});
|
||||
SelectedScreen = SidebarScreen.Screens.First();
|
||||
}
|
||||
|
||||
public ObservableCollection<SidebarScreenViewModel> SidebarScreens { get; }
|
||||
public SidebarScreenViewModel SidebarScreen { get; }
|
||||
|
||||
public SidebarScreenViewModel? SelectedScreen
|
||||
{
|
||||
get => _selectedScreen;
|
||||
set => RaiseAndSetIfChanged(ref _selectedScreen, value);
|
||||
}
|
||||
|
||||
public ReadOnlyObservableCollection<SidebarCategoryViewModel> SidebarCategories
|
||||
{
|
||||
@@ -87,12 +98,6 @@ public class SidebarViewModel : ActivatableViewModelBase
|
||||
set => RaiseAndSetIfChanged(ref _sidebarCategories, value);
|
||||
}
|
||||
|
||||
public SidebarScreenViewModel? SelectedSidebarScreen
|
||||
{
|
||||
get => _selectedSidebarScreen;
|
||||
set => RaiseAndSetIfChanged(ref _selectedSidebarScreen, value);
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> AddCategory { get; }
|
||||
|
||||
private async Task ExecuteAddCategory()
|
||||
@@ -112,7 +117,7 @@ public class SidebarViewModel : ActivatableViewModelBase
|
||||
{
|
||||
try
|
||||
{
|
||||
await _router.Navigate(sidebarScreenViewModel.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true});
|
||||
await _router.Navigate(sidebarScreenViewModel.Path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user