diff --git a/src/Artemis.UI/Routing/RouteViewModel.cs b/src/Artemis.UI/Routing/RouteViewModel.cs
new file mode 100644
index 000000000..5ecc0f356
--- /dev/null
+++ b/src/Artemis.UI/Routing/RouteViewModel.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Artemis.UI.Routing;
+
+public class RouteViewModel
+{
+ public RouteViewModel(string path, string name)
+ {
+ Path = path;
+ Name = name;
+ }
+
+ public string Path { get; }
+ public string Name { get; }
+
+ public bool Matches(string path)
+ {
+ return path.StartsWith(Path, StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ ///
+ public override string ToString()
+ {
+ return Name;
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Routing/Routes.cs b/src/Artemis.UI/Routing/Routes.cs
index ba0949669..4baf359a6 100644
--- a/src/Artemis.UI/Routing/Routes.cs
+++ b/src/Artemis.UI/Routing/Routes.cs
@@ -8,6 +8,8 @@ using Artemis.UI.Screens.SurfaceEditor;
using Artemis.UI.Screens.Workshop;
using Artemis.UI.Screens.Workshop.Home;
using Artemis.UI.Screens.Workshop.Layout;
+using Artemis.UI.Screens.Workshop.Library;
+using Artemis.UI.Screens.Workshop.Library.Tabs;
using Artemis.UI.Screens.Workshop.Profile;
using Artemis.UI.Shared.Routing;
@@ -28,7 +30,12 @@ public static class Routes
new RouteRegistration("profiles/{page:int}"),
new RouteRegistration("profiles/{entryId:guid}"),
new RouteRegistration("layouts/{page:int}"),
- new RouteRegistration("layouts/{entryId:guid}")
+ new RouteRegistration("layouts/{entryId:guid}"),
+ new RouteRegistration("library") {Children = new List()
+ {
+ new RouteRegistration("installed"),
+ new RouteRegistration("submissions"),
+ }}
}
},
#endif
diff --git a/src/Artemis.UI/Screens/Settings/SettingsTab.cs b/src/Artemis.UI/Screens/Settings/SettingsTab.cs
deleted file mode 100644
index f25200fca..000000000
--- a/src/Artemis.UI/Screens/Settings/SettingsTab.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Artemis.UI.Screens.Settings;
-
-public class SettingsTab
-{
- public SettingsTab(string path, string name)
- {
- Path = path;
- Name = name;
- }
-
- public string Path { get; set; }
- public string Name { get; set; }
-
- public bool Matches(string path)
- {
- return path.StartsWith($"settings/{Path}", StringComparison.InvariantCultureIgnoreCase);
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs
index 2a747e5f9..561c4e3d6 100644
--- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
+using Artemis.UI.Routing;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
using ReactiveUI;
@@ -13,30 +14,30 @@ namespace Artemis.UI.Screens.Settings;
public class SettingsViewModel : RoutableScreen, IMainScreenViewModel
{
private readonly IRouter _router;
- private SettingsTab? _selectedTab;
+ private RouteViewModel? _selectedTab;
public SettingsViewModel(IRouter router)
{
_router = router;
- SettingTabs = new ObservableCollection
+ SettingTabs = new ObservableCollection
{
- new("general", "General"),
- new("plugins", "Plugins"),
- new("devices", "Devices"),
- new("releases", "Releases"),
- new("about", "About"),
+ new("settings/general", "General"),
+ new("settings/plugins", "Plugins"),
+ new("settings/devices", "Devices"),
+ new("settings/releases", "Releases"),
+ new("settings/about", "About"),
};
// Navigate on tab change
this.WhenActivated(d => this.WhenAnyValue(vm => vm.SelectedTab)
.WhereNotNull()
- .Subscribe(s => _router.Navigate($"settings/{s.Path}", new RouterNavigationOptions {IgnoreOnPartialMatch = true}))
+ .Subscribe(s => _router.Navigate(s.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true}))
.DisposeWith(d));
}
- public ObservableCollection SettingTabs { get; }
+ public ObservableCollection SettingTabs { get; }
- public SettingsTab? SelectedTab
+ public RouteViewModel? SelectedTab
{
get => _selectedTab;
set => RaiseAndSetIfChanged(ref _selectedTab, value);
@@ -52,6 +53,6 @@ public class SettingsViewModel : RoutableScreen, IMain
// Always show a tab, if there is none forward to the first
if (SelectedTab == null)
- await _router.Navigate($"settings/{SettingTabs.First().Path}");
+ await _router.Navigate(SettingTabs.First().Path);
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml
new file mode 100644
index 000000000..af75201c2
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml
@@ -0,0 +1,8 @@
+
+ Welcome to Avalonia!
+
diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml.cs
new file mode 100644
index 000000000..b228f4b0f
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogView.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace Artemis.UI.Screens.Workshop.Entries;
+
+public partial class EntryInstallationDialogView : UserControl
+{
+ public EntryInstallationDialogView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogViewModel.cs
new file mode 100644
index 000000000..7b7cbca67
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryInstallationDialogViewModel.cs
@@ -0,0 +1,8 @@
+using Artemis.UI.Shared;
+
+namespace Artemis.UI.Screens.Workshop.Entries;
+
+public class EntryInstallationDialogViewModel : ContentDialogViewModelBase
+{
+
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml
index 0695a7554..c3b4593f6 100644
--- a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml
+++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml
@@ -41,14 +41,6 @@
-
-
+
+
+
+
diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledView.axaml
new file mode 100644
index 000000000..208718542
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledView.axaml
@@ -0,0 +1,8 @@
+
+ Installed entries management here 🫡
+
diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledView.axaml.cs
new file mode 100644
index 000000000..b98518ae5
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledView.axaml.cs
@@ -0,0 +1,14 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.ReactiveUI;
+
+namespace Artemis.UI.Screens.Workshop.Library.Tabs;
+
+public partial class LibraryInstalledView : ReactiveUserControl
+{
+ public LibraryInstalledView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledViewModel.cs
new file mode 100644
index 000000000..b615c18b1
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibraryInstalledViewModel.cs
@@ -0,0 +1,8 @@
+using Artemis.UI.Shared;
+
+namespace Artemis.UI.Screens.Workshop.Library.Tabs;
+
+public class LibraryInstalledViewModel : ActivatableViewModelBase
+{
+
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsView.axaml
new file mode 100644
index 000000000..4ab44f1fc
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsView.axaml
@@ -0,0 +1,8 @@
+
+ Submission management here 😗
+
diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsView.axaml.cs
new file mode 100644
index 000000000..baf08341b
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsView.axaml.cs
@@ -0,0 +1,14 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.ReactiveUI;
+
+namespace Artemis.UI.Screens.Workshop.Library.Tabs;
+
+public partial class LibrarySubmissionsView : ReactiveUserControl
+{
+ public LibrarySubmissionsView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsViewModel.cs
new file mode 100644
index 000000000..cbb98d615
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/LibrarySubmissionsViewModel.cs
@@ -0,0 +1,8 @@
+using Artemis.UI.Shared;
+
+namespace Artemis.UI.Screens.Workshop.Library.Tabs;
+
+public class LibrarySubmissionsViewModel : ActivatableViewModelBase
+{
+
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml
new file mode 100644
index 000000000..f6e2f5740
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml.cs
new file mode 100644
index 000000000..f2faa7e5a
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryVIew.axaml.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Reactive.Disposables;
+using Artemis.UI.Shared;
+using Avalonia.ReactiveUI;
+using Avalonia.Threading;
+using FluentAvalonia.UI.Media.Animation;
+using FluentAvalonia.UI.Navigation;
+using ReactiveUI;
+
+namespace Artemis.UI.Screens.Workshop.Library;
+
+public partial class WorkshopLibraryView : ReactiveUserControl
+{
+ private int _lastIndex;
+
+ public WorkshopLibraryView()
+ {
+ InitializeComponent();
+ this.WhenActivated(d => { ViewModel.WhenAnyValue(vm => vm.Screen).WhereNotNull().Subscribe(Navigate).DisposeWith(d); });
+ }
+
+ private void Navigate(ViewModelBase viewModel)
+ {
+ Dispatcher.UIThread.Invoke(() =>
+ {
+ if (ViewModel == null)
+ return;
+
+ SlideNavigationTransitionInfo transitionInfo = new()
+ {
+ Effect = ViewModel.Tabs.IndexOf(ViewModel.SelectedTab) > _lastIndex ? SlideNavigationTransitionEffect.FromRight : SlideNavigationTransitionEffect.FromLeft
+ };
+ TabFrame.NavigateFromObject(viewModel, new FrameNavigationOptions {TransitionInfoOverride = transitionInfo});
+ _lastIndex = ViewModel.Tabs.IndexOf(ViewModel.SelectedTab);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryViewModel.cs
new file mode 100644
index 000000000..707d22cde
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/Library/WorkshopLibraryViewModel.cs
@@ -0,0 +1,50 @@
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive.Disposables;
+using System.Threading;
+using System.Threading.Tasks;
+using Artemis.UI.Routing;
+using Artemis.UI.Shared;
+using Artemis.UI.Shared.Routing;
+using Artemis.WebClient.Workshop;
+using ReactiveUI;
+using System;
+
+namespace Artemis.UI.Screens.Workshop.Library;
+
+public class WorkshopLibraryViewModel : RoutableScreen, IWorkshopViewModel
+{
+ private RouteViewModel? _selectedTab;
+
+ ///
+ public WorkshopLibraryViewModel(IRouter router)
+ {
+ Tabs = new ObservableCollection
+ {
+ new("workshop/library/installed", "Installed"),
+ new("workshop/library/submissions", "Submissions")
+ };
+
+ // Navigate on tab change
+ this.WhenActivated(d => this.WhenAnyValue(vm => vm.SelectedTab)
+ .WhereNotNull()
+ .Subscribe(s => router.Navigate(s.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true}))
+ .DisposeWith(d));
+ }
+
+ public EntryType? EntryType => null;
+ public ObservableCollection Tabs { get; }
+
+ public RouteViewModel? SelectedTab
+ {
+ get => _selectedTab;
+ set => RaiseAndSetIfChanged(ref _selectedTab, value);
+ }
+
+ public override async Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken)
+ {
+ SelectedTab = Tabs.FirstOrDefault(t => t.Matches(args.Path));
+ if (SelectedTab == null)
+ await args.Router.Navigate(Tabs.First().Path);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs
index f15ca7cf6..83e5280f3 100644
--- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs
@@ -23,14 +23,16 @@ public class ProfileDetailsViewModel : RoutableScreen _updatedAt;
private IGetEntryById_Entry? _entry;
- public ProfileDetailsViewModel(IWorkshopClient client, ProfileEntryDownloadHandler downloadHandler, INotificationService notificationService)
+ public ProfileDetailsViewModel(IWorkshopClient client, ProfileEntryDownloadHandler downloadHandler, INotificationService notificationService, IWindowService windowService)
{
_client = client;
_downloadHandler = downloadHandler;
_notificationService = notificationService;
+ _windowService = windowService;
_updatedAt = this.WhenAnyValue(vm => vm.Entry).Select(e => e?.LatestRelease?.CreatedAt ?? e?.CreatedAt).ToProperty(this, vm => vm.UpdatedAt);
DownloadLatestRelease = ReactiveCommand.CreateFromTask(ExecuteDownloadLatestRelease);
@@ -65,6 +67,10 @@ public class ProfileDetailsViewModel : RoutableScreen result = await _downloadHandler.InstallProfileAsync(Entry.LatestRelease.Id, new Progress(), cancellationToken);
if (result.IsSuccess)
_notificationService.CreateNotification().WithTitle("Profile installed").WithSeverity(NotificationSeverity.Success).Show();