diff --git a/src/Artemis.Core/Plugins/Abstract/Module.cs b/src/Artemis.Core/Plugins/Abstract/Module.cs index 244e83ce6..9050f9646 100644 --- a/src/Artemis.Core/Plugins/Abstract/Module.cs +++ b/src/Artemis.Core/Plugins/Abstract/Module.cs @@ -20,6 +20,12 @@ namespace Artemis.Core.Plugins.Abstract /// public string DisplayName { get; protected set; } + /// + /// The modules display icon that's shown in the menu see for available + /// icons + /// + public string DisplayIcon { get; set; } + /// /// Whether or not this module expands upon the main data model. If set to true any data in main data model can be /// accessed by profiles in this module diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs index c807b6878..c9a225ca3 100644 --- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -14,6 +14,7 @@ namespace Artemis.Plugins.Modules.General { _settings = settings; DisplayName = "General"; + DisplayIcon = "AllInclusive"; ExpandsMainDataModel = true; var testSetting = _settings.GetSetting("TestSetting", DateTime.Now); diff --git a/src/Artemis.UI/App.xaml b/src/Artemis.UI/App.xaml index 2497d359f..c46f01392 100644 --- a/src/Artemis.UI/App.xaml +++ b/src/Artemis.UI/App.xaml @@ -2,8 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="https://github.com/canton7/Stylet" - xmlns:local="clr-namespace:Artemis.UI" - xmlns:dragablz="http://dragablz.net/winfx/xaml/dragablz"> + xmlns:local="clr-namespace:Artemis.UI"> @@ -13,62 +12,26 @@ - - - - - - - - + + + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - Home - - - - - - News - - - - - - Workshop - - - - - - Surface Editor - - - - - - Settings - - - - - - - Modules - - - - - - - - - - - - - - + - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs index b2619e9cf..7746d7f43 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs @@ -11,7 +11,7 @@ using Stylet; namespace Artemis.UI.Screens.Settings.Debug { - public class DebugViewModel : Screen, IScreenViewModel + public class DebugViewModel : Screen { private readonly ICoreService _coreService; private readonly IRgbService _rgbService; diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs index 1dd6095b6..86e82a38e 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs @@ -3,12 +3,13 @@ using Artemis.Core.Services.Storage.Interfaces; using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.Settings.Debug; using Artemis.UI.Screens.Settings.Tabs.Devices; +using MaterialDesignThemes.Wpf; using Ninject; using Stylet; namespace Artemis.UI.Screens.Settings { - public class SettingsViewModel : Screen, IScreenViewModel + public class SettingsViewModel : MainScreenViewModel { private readonly IDeviceSettingsViewModelFactory _deviceSettingsViewModelFactory; private readonly IKernel _kernel; @@ -22,6 +23,10 @@ namespace Artemis.UI.Screens.Settings ISettingsService settingsService, IDeviceSettingsViewModelFactory deviceSettingsViewModelFactory) { + DisplayName = "Settings"; + DisplayIcon = PackIconKind.Settings; + DisplayOrder = 5; + _kernel = kernel; _surfaceService = surfaceService; _windowManager = windowManager; diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs index 34acc4f45..4dd7be456 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs @@ -31,8 +31,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices { _deviceService.IdentifyDevice(Device); } - - + public void ShowDeviceDebugger() { } diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml b/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml new file mode 100644 index 000000000..17c80b091 --- /dev/null +++ b/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml @@ -0,0 +1,31 @@ + + + + + + + Active module + + + Profile 1 + Profile 2 + Profile 3 + Profile 4 + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml.cs b/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml.cs new file mode 100644 index 000000000..f76766c07 --- /dev/null +++ b/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Artemis.UI.Screens.Sidebar +{ + /// + /// Interaction logic for SidebarView.xaml + /// + public partial class SidebarView : UserControl + { + public SidebarView() + { + InitializeComponent(); + } + } +} diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs new file mode 100644 index 000000000..fe0372c42 --- /dev/null +++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.Events; +using Artemis.Core.Services.Interfaces; +using Artemis.UI.Ninject.Factories; +using MaterialDesignExtensions.Controls; +using MaterialDesignExtensions.Model; +using MaterialDesignThemes.Wpf; +using Stylet; + +namespace Artemis.UI.Screens.Sidebar +{ + public class SidebarViewModel : PropertyChangedBase + { + private readonly IModuleViewModelFactory _moduleViewModelFactory; + private readonly IPluginService _pluginService; + + public SidebarViewModel(List defaultSidebarItems, IModuleViewModelFactory moduleViewModelFactory, IPluginService pluginService) + { + _moduleViewModelFactory = moduleViewModelFactory; + _pluginService = pluginService; + + DefaultSidebarItems = defaultSidebarItems; + SidebarItemObjects = new Dictionary(); + SidebarItems = new BindableCollection(); + + SetupSidebar(); + _pluginService.PluginEnabled += PluginServiceOnPluginEnabled; + _pluginService.PluginDisabled += PluginServiceOnPluginDisabled; + } + + public List DefaultSidebarItems { get; set; } + public BindableCollection SidebarItems { get; set; } + public Dictionary SidebarItemObjects { get; set; } + public IScreen SelectedItem { get; set; } + + public void SetupSidebar() + { + SidebarItems.Clear(); + SidebarItemObjects.Clear(); + + // Add all default sidebar items + SidebarItems.Add(new DividerNavigationItem()); + foreach (var screen in DefaultSidebarItems.OrderBy(d => d.DisplayOrder)) + { + var sidebarItem = new FirstLevelNavigationItem {Icon = screen.DisplayIcon, Label = screen.DisplayName}; + SidebarItems.Add(sidebarItem); + SidebarItemObjects.Add(sidebarItem, screen); + } + + // Add all activated modules + SidebarItems.Add(new DividerNavigationItem()); + SidebarItems.Add(new SubheaderNavigationItem {Subheader = "Modules"}); + var modules = _pluginService.GetPluginsOfType().ToList(); + foreach (var module in modules) + AddModule(module); + + // Select the top item, which will be one of the defaults + SidebarItems[1].IsSelected = true; + SelectedItem = (IScreen) SidebarItemObjects[SidebarItems[1]]; + } + + // ReSharper disable once UnusedMember.Global - Called by view + public void SelectItem(WillSelectNavigationItemEventArgs args) + { + if (args.NavigationItemToSelect == null) + { + SelectedItem = null; + return; + } + + var sidebarItemObject = SidebarItemObjects[args.NavigationItemToSelect]; + // The default items are singleton screens, simply set it as the selected item + if (sidebarItemObject is IScreen screen) + SelectedItem = screen; + // Modules have a VM that must be created, use a factory and set the result as the selected item + else if (sidebarItemObject is Core.Plugins.Abstract.Module module) + SelectedItem = _moduleViewModelFactory.Create(module); + } + + public void AddModule(Core.Plugins.Abstract.Module module) + { + // Ensure the module is not already in the list + if (SidebarItemObjects.Any(io => io.Value == module)) + return; + + // Icon is provided as string to avoid having to reference MaterialDesignThemes + var parsedIcon = System.Enum.TryParse(module.DisplayIcon, true, out var iconEnum); + if (parsedIcon == false) + iconEnum = PackIconKind.QuestionMarkCircle; + var sidebarItem = new FirstLevelNavigationItem { Icon = iconEnum, Label = module.DisplayName }; + SidebarItems.Add(sidebarItem); + SidebarItemObjects.Add(sidebarItem, module); + } + + public void RemoveModule(Core.Plugins.Abstract.Module module) + { + // If not in the list there's nothing to do + if (SidebarItemObjects.All(io => io.Value != module)) + return; + + var existing = SidebarItemObjects.First(io => io.Value == module); + SidebarItems.Remove(existing.Key); + SidebarItemObjects.Remove(existing.Key); + } + + #region Event handlers + + private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) + { + if (e.PluginInfo.Instance is Core.Plugins.Abstract.Module module) + AddModule(module); + } + + private void PluginServiceOnPluginDisabled(object sender, PluginEventArgs e) + { + if (e.PluginInfo.Instance is Core.Plugins.Abstract.Module module) + RemoveModule(module); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Splash/SplashView.xaml b/src/Artemis.UI/Screens/Splash/SplashView.xaml index edf44348c..e26961e6f 100644 --- a/src/Artemis.UI/Screens/Splash/SplashView.xaml +++ b/src/Artemis.UI/Screens/Splash/SplashView.xaml @@ -1,21 +1,17 @@ - @@ -31,4 +27,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml b/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml index 3e438a194..74df39c6d 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml +++ b/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml @@ -6,47 +6,19 @@ xmlns:s="https://github.com/canton7/Stylet" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Dialogs" - xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" mc:Ignorable="d" d:DesignHeight="351.305" d:DesignWidth="262.163" d:DataContext="{d:DesignInstance {x:Type surfaceEditor:SurfaceDeviceConfigViewModel}}"> + + - - - - - - - - - - - + + +