Skip to content

Commit 8765b34

Browse files
Move the Catalog Editor out of the sidebar and behind its own setting (#5587)
1 parent 0def3dc commit 8765b34

20 files changed

Lines changed: 181 additions & 57 deletions

‎src/Languages/lang_en.json‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@
113113
"Enable Software Catalog in Experimental settings and developer options, then restart UniGetUI.": "Enable Software Catalog in Experimental settings and developer options, then restart UniGetUI.",
114114
"The software catalog could not be loaded. Ask an administrator to check {0}, then try again.": "The software catalog could not be loaded. Ask an administrator to check {0}, then try again.",
115115
"Edit software catalog": "Edit software catalog",
116+
"Back to {0}": "Back to {0}",
117+
"Create a catalog": "Create a catalog",
118+
"Create a new catalog or open a catalog file": "Create a new catalog or open a catalog file",
119+
"Enable the Catalog Editor": "Enable the Catalog Editor",
120+
"Catalog Editor is disabled": "Catalog Editor is disabled",
121+
"Enable the Catalog Editor in Experimental settings and developer options, then restart UniGetUI.": "Enable the Catalog Editor in Experimental settings and developer options, then restart UniGetUI.",
116122
"Software Catalog": "Software Catalog",
117123
"Software selected for you, ready to install.": "Software selected for you, ready to install.",
118124
"Refresh software catalog": "Refresh software catalog",

‎src/UniGetUI.Avalonia/Infrastructure/AvaloniaBootstrapper.cs‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,14 @@ private static IpcAppInfo GetAppInfo()
257257
CanNavigate = window is not null,
258258
CanQuit = true,
259259
CurrentPage = window is null ? "" : IpcAppPages.ToPageName(window.CurrentPage.ToString()),
260-
SupportedPages = window is { SoftwareCatalogEnabled: true }
261-
? IpcAppPages.SupportedPages
262-
: IpcAppPages.SupportedPages.Where(page => page is not ("catalog" or "catalog-editor")).ToArray(),
260+
SupportedPages = IpcAppPages.SupportedPages
261+
.Where(page => page switch
262+
{
263+
"catalog" => window is { SoftwareCatalogEnabled: true },
264+
"catalog-editor" => window is { CatalogEditorEnabled: true },
265+
_ => true,
266+
})
267+
.ToArray(),
263268
SystemRestartPending = PendingRebootStore.HasPending,
264269
SystemRestartPendingPackages = PendingRebootStore.PendingCount,
265270
};
@@ -298,6 +303,8 @@ private static IpcCommandResult NavigateApp(IpcAppNavigateRequest request)
298303
case "catalog-editor":
299304
if (!window.SoftwareCatalogEnabled)
300305
throw new InvalidOperationException("Software Catalog is disabled. Enable it in Experimental settings and developer options, then restart UniGetUI.");
306+
if (page == "catalog-editor" && !window.CatalogEditorEnabled)
307+
throw new InvalidOperationException("Catalog Editor is disabled. Enable it in Experimental settings and developer options, then restart UniGetUI.");
301308
window.Navigate(page == "catalog-editor" ? PageType.CatalogEditor : PageType.Catalog);
302309
break;
303310
case "settings":

‎src/UniGetUI.Avalonia/Infrastructure/NavigationPageOrder.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace UniGetUI.Avalonia.Infrastructure;
66
internal static class NavigationPageOrder
77
{
88
public static PageType[] DefaultPages(bool catalogEnabled) => catalogEnabled
9-
? [PageType.Catalog, PageType.Discover, PageType.Updates, PageType.Installed, PageType.Bundles, PageType.CatalogEditor]
9+
? [PageType.Catalog, PageType.Discover, PageType.Updates, PageType.Installed, PageType.Bundles]
1010
: [PageType.Discover, PageType.Updates, PageType.Installed, PageType.Bundles];
1111

1212
public static PageType[] Get(bool catalogEnabled)

‎src/UniGetUI.Avalonia/ViewModels/DialogPages/CatalogEditorViewModel.cs‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public partial class CatalogEditorViewModel : ViewModelBase
5555
private string _query = "";
5656

5757
[ObservableProperty]
58-
private string _filePath = SoftwareCatalog.FilePath;
58+
private string _filePath = "";
5959

6060
private string _message = "";
6161

@@ -110,14 +110,15 @@ public Task<bool> EnsureLoadedAsync()
110110
return _initialLoad ??= LoadOrStartAsync(FilePath);
111111
}
112112

113-
// No catalog deployed yet: start an empty document that saves to that path, so a first
114-
// catalog can be created there instead of the editor opening disabled.
113+
// The editor starts on an untitled, empty document rather than the deployed catalog, so nobody
114+
// edits what this device installs from by accident; New catalog or Open file is the first step.
115+
// A path set beforehand that does not exist yet also starts empty, and saves there.
115116
private Task<bool> LoadOrStartAsync(string path)
116117
{
117-
if (!IsMissing(path)) return LoadAsync(path);
118+
if (path.Length > 0 && !IsMissing(path)) return LoadAsync(path);
118119
SelectedCatalog = null;
119120
Catalogs.Clear();
120-
FilePath = Path.GetFullPath(path);
121+
FilePath = path.Length > 0 ? Path.GetFullPath(path) : "";
121122
_savedCatalogs = [];
122123
IsLoaded = true;
123124
IsDirty = false;

‎src/UniGetUI.Avalonia/ViewModels/MainWindowViewModel.cs‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ public MainWindowViewModel()
433433
RegisterBannerToast(TelemetryWarner);
434434
RegisterBannerToast(PortableImportBanner);
435435

436-
CatalogEditor = Sidebar.SoftwareCatalogEnabled ? new CatalogEditorViewModel() : null;
436+
CatalogEditor = Sidebar.CatalogEditorEnabled ? new CatalogEditorViewModel() : null;
437437
DiscoverPage = new DiscoverSoftwarePage(CatalogEditor);
438438
UpdatesPage = new SoftwareUpdatesPage();
439439
InstalledPage = new InstalledPackagesPage();
@@ -669,7 +669,7 @@ public void LoadDefaultPage()
669669
"installed" => PageType.Installed,
670670
"bundles" => PageType.Bundles,
671671
"catalog" when Sidebar.SoftwareCatalogEnabled => PageType.Catalog,
672-
"catalog-editor" when Sidebar.SoftwareCatalogEnabled => PageType.CatalogEditor,
672+
"catalog-editor" when Sidebar.CatalogEditorEnabled => PageType.CatalogEditor,
673673
"settings" => PageType.Settings,
674674
// A usable admin-curated catalog is the simplest starting point, so it wins over the default pages.
675675
_ when Sidebar.HasUsableCatalog => PageType.Catalog,
@@ -743,6 +743,15 @@ public async Task<bool> NavigateToAsync(
743743
MainWindow.RuntimeNotificationLevel.Error);
744744
return false;
745745
}
746+
if (newPage_t is PageType.CatalogEditor && !Sidebar.CatalogEditorEnabled)
747+
{
748+
Logger.Warn("Catalog Editor navigation was rejected because the editor is disabled.");
749+
MainWindow.Instance?.ShowBanner(
750+
CoreTools.Translate("Catalog Editor is disabled"),
751+
CoreTools.Translate("Enable the Catalog Editor in Experimental settings and developer options, then restart UniGetUI."),
752+
MainWindow.RuntimeNotificationLevel.Error);
753+
return false;
754+
}
746755
if (newPage_t is PageType.About) { _ = ShowAboutDialog(); return true; }
747756
if (newPage_t is PageType.Quit) { MainWindow.Instance?.QuitApplication(); return true; }
748757

@@ -840,6 +849,13 @@ public async Task<bool> NavigateToAsync(
840849
_ => CoreTools.Translate("UniGetUI"),
841850
};
842851

852+
/// <summary>Opens the Catalog Editor on a new catalog file, for the Software Catalog's New catalog actions.</summary>
853+
public async Task StartNewCatalogAsync()
854+
{
855+
if (!await NavigateToAsync(PageType.CatalogEditor)) return;
856+
if (_catalogEditorPage is { } editor) await editor.StartNewCatalogAsync();
857+
}
858+
843859
public void NavigateBack() => _ = NavigateBackAsync();
844860

845861
public async Task<bool> NavigateBackAsync(CancellationToken cancellationToken = default)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
12
using CommunityToolkit.Mvvm.Input;
23
using UniGetUI.Avalonia.ViewModels;
4+
using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings;
35

46
namespace UniGetUI.Avalonia.ViewModels.Pages.SettingsPages;
57

68
public partial class ExperimentalViewModel : ViewModelBase
79
{
810
public bool IsWindows { get; } = OperatingSystem.IsWindows();
911

12+
// The Catalog Editor is a sub-option of the Software Catalog.
13+
[ObservableProperty]
14+
private bool _isSoftwareCatalogEnabled = CoreSettings.Get(CoreSettings.K.EnableSoftwareCatalog);
15+
1016
public event EventHandler? RestartRequired;
1117

1218
[RelayCommand]
1319
private void ShowRestartRequired() => RestartRequired?.Invoke(this, EventArgs.Empty);
20+
21+
[RelayCommand]
22+
private void SoftwareCatalogChanged()
23+
{
24+
IsSoftwareCatalogEnabled = CoreSettings.Get(CoreSettings.K.EnableSoftwareCatalog);
25+
ShowRestartRequired();
26+
}
1427
}

‎src/UniGetUI.Avalonia/ViewModels/SidebarViewModel.cs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public partial class SidebarViewModel : ViewModelBase
1313
{
1414
public bool SoftwareCatalogEnabled { get; } = Settings.Get(Settings.K.EnableSoftwareCatalog);
1515

16+
// An administrator tool, opened from the catalog page rather than the sidebar; off unless asked for.
17+
public bool CatalogEditorEnabled { get; } =
18+
Settings.Get(Settings.K.EnableSoftwareCatalog) && Settings.Get(Settings.K.EnableCatalogEditor);
19+
1620
// Only a catalog with packages to offer becomes the startup page; an unset or broken one would
1721
// open the app on an empty page. Checked once at startup, like the setting itself.
1822
public bool HasUsableCatalog { get; } =

‎src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ partial void OnIsFilterPaneOpenChanged(bool value)
154154
public bool SimilarSearchEnabled { get; private set; }
155155
public bool InstallerHostColumnVisible { get; }
156156
public bool DownloadSizeColumnVisible { get; }
157-
public readonly string NoPackagesText;
157+
// Settable so a page can say why it is empty; takes effect on the next list update.
158+
public string NoPackagesText { get; set; }
158159
public readonly string NoMatchesText;
159160
public readonly string SearchBoxPlaceholder;
160161
private readonly string _noPackagesSubtitleBase;
@@ -170,6 +171,19 @@ partial void OnIsFilterPaneOpenChanged(bool value)
170171
[ObservableProperty] private string _pageIconPath = "";
171172
[ObservableProperty] private string _subtitle = "";
172173

174+
// A page opened from another one (the Catalog Editor from the Software Catalog) links back to it above its title.
175+
[ObservableProperty]
176+
[NotifyPropertyChangedFor(nameof(HasParentPage))]
177+
[NotifyPropertyChangedFor(nameof(ParentPageLinkName))]
178+
private string _parentPageTitle = "";
179+
180+
public bool HasParentPage => ParentPageTitle.Length > 0;
181+
public string ParentPageLinkName => CoreTools.Translate("Back to {0}", ParentPageTitle);
182+
public Action? ParentPageRequested { get; set; }
183+
184+
[RelayCommand]
185+
private void GoToParentPage() => ParentPageRequested?.Invoke();
186+
173187
// Shown after the subtitle in a secondary tone: when the list was last checked, then the page suffix.
174188
[ObservableProperty] private string _subtitleDetail = "";
175189

‎src/UniGetUI.Avalonia/ViewModels/SoftwarePages/SoftwareCatalogViewModel.cs‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ private void NotifyBackgroundTextChanged()
168168
OnPropertyChanged(nameof(BackgroundText));
169169
OnPropertyChanged(nameof(HasBackgroundText));
170170
OnPropertyChanged(nameof(HasBackgroundDetail));
171+
OnPropertyChanged(nameof(ShowCreateCatalog));
171172
}
172173

173174
private bool IsSelectedByFilters(CatalogTileViewModel tile) =>
@@ -267,22 +268,21 @@ partial void OnErrorMessageChanged(string value)
267268
value, global::Avalonia.Automation.AutomationLiveSetting.Assertive);
268269
}
269270

271+
// Administrators who enabled the Catalog Editor can start a catalog from here; everyone else only installs.
272+
public bool IsEditorEnabled { get; } =
273+
Settings.Get(Settings.K.EnableSoftwareCatalog) && Settings.Get(Settings.K.EnableCatalogEditor);
274+
275+
// On a device with no catalog yet, the empty page offers to create one.
276+
public bool ShowCreateCatalog => IsEditorEnabled && _notConfigured && IsEmpty;
277+
278+
[RelayCommand]
279+
private void OpenEditor() => MainWindow.Instance?.Navigate(PageType.CatalogEditor);
280+
270281
[RelayCommand]
271-
private async Task EditAsync()
282+
private async Task NewCatalogAsync()
272283
{
273-
try
274-
{
275-
var owner = MainWindow.Instance
276-
?? throw new InvalidOperationException("The catalog editor requires an application window.");
277-
owner.Navigate(PageType.CatalogEditor);
278-
await Task.CompletedTask;
279-
}
280-
catch (Exception ex)
281-
{
282-
Logger.Error("Could not open the software catalog editor.");
283-
Logger.Error(ex);
284-
ErrorMessage = CoreTools.Translate("The catalog editor could not be opened: {0}", ex.Message);
285-
}
284+
if (MainWindow.Instance?.DataContext is MainWindowViewModel main)
285+
await main.StartNewCatalogAsync();
286286
}
287287

288288
private bool _waitingForManagers;

‎src/UniGetUI.Avalonia/Views/MainWindow.axaml.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ public enum RuntimeNotificationLevel
194194
private MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext!;
195195
public PageType CurrentPage => ViewModel.CurrentPage_t;
196196
public bool SoftwareCatalogEnabled => ViewModel.Sidebar.SoftwareCatalogEnabled;
197+
public bool CatalogEditorEnabled => ViewModel.Sidebar.CatalogEditorEnabled;
197198

198199
public MainWindow()
199200
{

0 commit comments

Comments
 (0)