Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Left menu button styles #2455

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/NexusMods.App.UI/LeftMenu/Items/INewLeftMenuItemViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Reactive;
using NexusMods.Abstractions.UI;
using NexusMods.App.UI.Controls.Navigation;
using NexusMods.Icons;
using ReactiveUI;

namespace NexusMods.App.UI.LeftMenu.Items;

public interface INewLeftMenuItemViewModel : IViewModelInterface,
// TODO: Remove this this after all old left menu items are replaced, used to allow using either in the meantime
ILeftMenuItemViewModel
{
public string Text { get; set; }

public IconValue Icon { get; set; }

public ReactiveCommand<NavigationInformation, Unit> NavigateCommand { get; }

public bool IsActive { get; }

public bool IsSelected { get; }

}
18 changes: 18 additions & 0 deletions src/NexusMods.App.UI/LeftMenu/Items/LeftMenuItemDesignViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Reactive;
using NexusMods.Abstractions.UI;
using NexusMods.App.UI.Controls.Navigation;
using NexusMods.Icons;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;

namespace NexusMods.App.UI.LeftMenu.Items;

public class LeftMenuItemDesignViewModel : AViewModel<INewLeftMenuItemViewModel>, INewLeftMenuItemViewModel
{
[Reactive] public string Text { get; set; } = "Design Item";
[Reactive] public IconValue Icon { get; set; } = IconValues.Settings;
public ReactiveCommand<NavigationInformation, Unit> NavigateCommand { get; } =
ReactiveCommand.Create<NavigationInformation>((info) => { });
public bool IsActive { get; } = false;
public bool IsSelected { get; } = false;
}
20 changes: 20 additions & 0 deletions src/NexusMods.App.UI/LeftMenu/Items/LeftMenuItemView.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<reactiveUi:ReactiveUserControl x:TypeArguments="items:INewLeftMenuItemViewModel" 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:items="clr-namespace:NexusMods.App.UI.LeftMenu.Items"
xmlns:navigation="clr-namespace:NexusMods.App.UI.Controls.Navigation"
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="NexusMods.App.UI.LeftMenu.Items.LeftMenuItemView">
<navigation:LeftMenuNavButton x:Name="NavButton" >
<DockPanel>
<icons:UnifiedIcon x:Name="LeftIcon" DockPanel.Dock="Left" />
<TextBlock x:Name="LabelTextBlock"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis" />
</DockPanel>
</navigation:LeftMenuNavButton>
</reactiveUi:ReactiveUserControl>

34 changes: 34 additions & 0 deletions src/NexusMods.App.UI/LeftMenu/Items/LeftMenuItemView.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Reactive.Disposables;
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace NexusMods.App.UI.LeftMenu.Items;

public partial class LeftMenuItemView : ReactiveUserControl<INewLeftMenuItemViewModel>
{
public LeftMenuItemView()
{
InitializeComponent();

this.WhenActivated(d =>
{

this.OneWayBind(ViewModel, vm => vm.Text, view => view.LabelTextBlock.Text)
.DisposeWith(d);

this.OneWayBind(ViewModel, vm => vm.Icon, view => view.LeftIcon.Value)
.DisposeWith(d);

this.BindCommand(ViewModel, vm => vm.NavigateCommand, view => view.NavButton)
.DisposeWith(d);

this.OneWayBind(ViewModel, vm => vm.IsActive, view => view.NavButton.IsActive)
.DisposeWith(d);

this.OneWayBind(ViewModel, vm => vm.IsSelected, view => view.NavButton.IsSelected)
.DisposeWith(d);
}
);
}
}

99 changes: 99 additions & 0 deletions src/NexusMods.App.UI/LeftMenu/Items/LeftMenuItemViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using DynamicData;
using DynamicData.Binding;
using NexusMods.Abstractions.UI;
using NexusMods.App.UI.Controls.Navigation;
using NexusMods.App.UI.WorkspaceSystem;
using NexusMods.Icons;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;

namespace NexusMods.App.UI.LeftMenu.Items;

public class LeftMenuItemViewModel : AViewModel<INewLeftMenuItemViewModel>, INewLeftMenuItemViewModel
{
[Reactive] public string Text { get; set; } = "";
[Reactive] public IconValue Icon { get; set; } = new();
public ReactiveCommand<NavigationInformation, Unit> NavigateCommand { get; }

[Reactive] public bool IsActive { get; private set; }
[Reactive] public bool IsSelected { get; private set; }

public LeftMenuItemViewModel(
IWorkspaceController workspaceController,
WorkspaceId workspaceId,
PageData pageData
)
{
IsActive = false;
IsSelected = false;

NavigateCommand = ReactiveCommand.Create<NavigationInformation>((info) =>
{
var behavior = workspaceController.GetOpenPageBehavior(pageData, info);
workspaceController.OpenPage(workspaceId, pageData, behavior);
}
);

var workspaceIsActiveObservable = workspaceController
.WhenAnyValue(controller => controller.ActiveWorkspace)
.Where(workspace => workspace.Id == workspaceId);

var isActiveObservable = workspaceIsActiveObservable
.Select(workspace =>
workspace.Panels.ToObservableChangeSet()
.FilterOnObservable(panel =>
panel.WhenAnyValue(p => p.SelectedTab.Contents)
.Select(selectedTabContents =>
{
// The SelectedTab Contents can be null at startup
// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
var context = selectedTabContents?.PageData?.Context;
var pageId = selectedTabContents?.PageData?.FactoryId;
// ReSharper restore ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
return pageData.FactoryId == pageId && pageData.Context.Equals(context);
}
)
)
.QueryWhenChanged(matchingPanels => matchingPanels.Count != 0)
.DistinctUntilChanged()
)
.Switch();

var workspaceHasSinglePanelObservable = workspaceIsActiveObservable
.Select(workspace => workspace.WhenAnyValue(w => w.Panels.Count))
.Switch()
.Select(panelCount => panelCount == 1)
.DistinctUntilChanged()
.Prepend(workspaceController.ActiveWorkspace.Panels.Count == 1);

var isSelectedObservable = workspaceIsActiveObservable
.Select(workspace => workspace.WhenAnyValue(w => w.SelectedTab.Contents))
.Switch()
.Select(selectedTabContents =>
{
// The SelectedTab Contents can apparently be null at startup
var context = selectedTabContents?.PageData?.Context;
var pageId = selectedTabContents?.PageData?.FactoryId;
return pageData.FactoryId == pageId && pageData.Context.Equals(context);
}
)
.DistinctUntilChanged()
.Prepend(pageData.Context.Equals(workspaceController.ActiveWorkspace.SelectedTab?.Contents?.PageData?.Context))
// No Selected state if there is only one panel in the workspace
.CombineLatest(workspaceHasSinglePanelObservable, (isSelected, hasSinglePanel) => isSelected && !hasSinglePanel)
.DistinctUntilChanged();

this.WhenActivated(d =>
{
isActiveObservable.Subscribe(isActive => IsActive = isActive)
.DisposeWith(d);

isSelectedObservable.Subscribe(isSelected => IsSelected = isSelected)
.DisposeWith(d);
}
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@ namespace NexusMods.App.UI.LeftMenu.Loadout;
public interface ILoadoutLeftMenuViewModel : ILeftMenuViewModel
{
public IApplyControlViewModel ApplyControlViewModel { get; }

public INewLeftMenuItemViewModel LeftMenuItemLibrary { get; }

public INewLeftMenuItemViewModel LeftMenuItemLoadout { get; }

public INewLeftMenuItemViewModel LeftMenuItemHealthCheck { get; }
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Collections.ObjectModel;
using NexusMods.Abstractions.UI;
using NexusMods.App.UI.LeftMenu.Items;
using NexusMods.App.UI.Resources;
using NexusMods.App.UI.WorkspaceSystem;
using NexusMods.Icons;
using ReactiveUI;

namespace NexusMods.App.UI.LeftMenu.Loadout;

Expand All @@ -13,19 +13,36 @@ public class LoadoutLeftMenuDesignViewModel : AViewModel<ILoadoutLeftMenuViewMod
public WorkspaceId WorkspaceId { get; } = new();
public IApplyControlViewModel ApplyControlViewModel { get; } = new ApplyControlDesignViewModel();

public INewLeftMenuItemViewModel LeftMenuItemLibrary { get; } = new LeftMenuItemDesignViewModel
{
Text = Language.LibraryPageTitle,
Icon = IconValues.LibraryOutline,
};
public INewLeftMenuItemViewModel LeftMenuItemLoadout { get; } = new LeftMenuItemDesignViewModel
{
Text = Language.LoadoutView_Title_Installed_Mods,
Icon = IconValues.Mods,
};
public INewLeftMenuItemViewModel LeftMenuItemHealthCheck { get; } = new LeftMenuItemDesignViewModel
{
Text = Language.LoadoutLeftMenuViewModel_LoadoutLeftMenuViewModel_Diagnostics,
Icon = IconValues.Cardiology,
};

public LoadoutLeftMenuDesignViewModel()
{
Items = new ReadOnlyObservableCollection<ILeftMenuItemViewModel>([

new IconViewModel
{
Name = "My Mods",
Name = "My Collection",
Icon = IconValues.Collections,
},

new IconViewModel
{
Name = "Diagnostics",
Icon = IconValues.Cardiology,
Name = "Stardew Valley Very Expanded",
Icon = IconValues.Collections,
},
]
);
Expand Down
42 changes: 29 additions & 13 deletions src/NexusMods.App.UI/LeftMenu/Loadout/LoadoutLeftMenuView.axaml
Original file line number Diff line number Diff line change
@@ -1,29 +1,45 @@
<reactiveUi:ReactiveUserControl x:TypeArguments="left:ILoadoutLeftMenuViewModel" xmlns="https://github.com/avaloniaui"
<reactiveUi:ReactiveUserControl x:TypeArguments="leftMenu:ILoadoutLeftMenuViewModel" 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:left="clr-namespace:NexusMods.App.UI.LeftMenu.Loadout"
xmlns:leftMenu="clr-namespace:NexusMods.App.UI.LeftMenu.Loadout"
xmlns:items="clr-namespace:NexusMods.App.UI.LeftMenu.Items"
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="450"
x:Class="NexusMods.App.UI.LeftMenu.Loadout.LoadoutLeftMenuView">
<Design.DataContext>
<left:LoadoutLeftMenuDesignViewModel />
<leftMenu:LoadoutLeftMenuDesignViewModel />
</Design.DataContext>

<Grid RowDefinitions="*,Auto"
Margin="16,0,16,12">
<Grid RowDefinitions="*, Auto" Margin="12,0,12,12">
<StackPanel Grid.Row="0" Orientation="Vertical">
<items:LeftMenuItemView x:Name="LibraryItem" />

<StackPanel>
<Separator />
<TextBlock>INSTALL MODS</TextBlock>
</StackPanel>

<items:LeftMenuItemView x:Name="LoadoutItem" />

<ItemsControl Grid.Row="0" x:Name="MenuItemsControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Spacing="{StaticResource Spacing-1}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl x:Name="MenuItemsControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Spacing="{StaticResource Spacing-1}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

<StackPanel>
<Separator />
<TextBlock>UTILITIES</TextBlock>
</StackPanel>

<items:LeftMenuItemView x:Name="HealthCheckItem" />
</StackPanel>

<reactiveUi:ViewModelViewHost Grid.Row="1" x:Name="ApplyControlViewHost" />
</Grid>


</reactiveUi:ReactiveUserControl>

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ public LoadoutLeftMenuView()
{
this.OneWayBind(ViewModel, vm => vm.ApplyControlViewModel, view => view.ApplyControlViewHost.ViewModel)
.DisposeWith(disposables);

this.OneWayBind(ViewModel, vm => vm.LeftMenuItemLibrary, view => view.LibraryItem.ViewModel)
.DisposeWith(disposables);

this.OneWayBind(ViewModel, vm => vm.LeftMenuItemLoadout, view => view.LoadoutItem.ViewModel)
.DisposeWith(disposables);

this.OneWayBind(ViewModel, vm => vm.LeftMenuItemHealthCheck, view => view.HealthCheckItem.ViewModel)
.DisposeWith(disposables);

this.WhenAnyValue(x => x.ViewModel!.Items)
.BindTo(this, x => x.MenuItemsControl.ItemsSource)
Expand Down
Loading
Loading