Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Avalonia.Input.Platform;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform.Storage;
using UniGetUI.Avalonia.Infrastructure;
using UniGetUI.Avalonia.ViewModels;
using UniGetUI.Avalonia.ViewModels.Pages.SettingsPages;
Expand Down Expand Up @@ -78,7 +79,7 @@ private void BuildPage()

var execHint = new TextBlock
{
Text = CoreTools.Translate("Not finding the file you are looking for? Make sure it has been added to path."),
Text = CoreTools.Translate("Not finding the file you are looking for? Browse to it or make sure it has been added to PATH."),
FontSize = 12,
FontWeight = FontWeight.SemiBold,
Opacity = 0.7,
Expand All @@ -90,14 +91,21 @@ private void BuildPage()
var execCombo = new ComboBox { HorizontalAlignment = HorizontalAlignment.Stretch };
AutomationProperties.SetName(execCombo, CoreTools.Translate("Select the executable to be used. The following list shows the executables found by UniGetUI"));
foreach (var path in manager.FindCandidateExecutableFiles())
execCombo.Items.Add(path);
AddExecutablePathItem(execCombo, path);

string savedPath = CoreSettings.GetDictionaryItem<string, string>(CoreSettings.K.ManagerPaths, manager.Name) ?? "";
if (!string.IsNullOrEmpty(savedPath) && File.Exists(savedPath))
AddExecutablePathItem(execCombo, savedPath);
if (string.IsNullOrEmpty(savedPath))
{
var (found, path) = manager.GetExecutableFile();
savedPath = found ? path : "";
}
else if (!File.Exists(savedPath))
{
var (found, path) = manager.GetExecutableFile();
savedPath = found ? path : "";
}
execCombo.SelectedItem = savedPath;
execCombo.IsEnabled = customPathsAllowed;
execCombo.SelectionChanged += (s, _) =>
Expand All @@ -106,9 +114,37 @@ private void BuildPage()
ViewModel.OnExecutableSelected(selected);
};
Grid.SetRow(execCombo, 1);
Grid.SetColumnSpan(execCombo, 2);
Grid.SetColumn(execCombo, 0);
execGrid.Children.Add(execCombo);

var browseExecutableButton = new Button
{
Content = CoreTools.Translate("Browse..."),
IsEnabled = customPathsAllowed,
Margin = new Thickness(8, 0, 0, 0),
};
browseExecutableButton.Click += async (_, _) =>
{
if (TopLevel.GetTopLevel(this) is not { } topLevel) return;
var files = await topLevel.StorageProvider.OpenFilePickerAsync(
new FilePickerOpenOptions
{
AllowMultiple = false,
Title = CoreTools.Translate("Select executable"),
FileTypeFilter = GetExecutableFileTypeFilter(),
});
if (files is not [{ } file]) return;

string? path = file.TryGetLocalPath();
if (string.IsNullOrWhiteSpace(path)) return;

AddExecutablePathItem(execCombo, path);
execCombo.SelectedItem = path;
};
Grid.SetRow(browseExecutableButton, 1);
Grid.SetColumn(browseExecutableButton, 1);
execGrid.Children.Add(browseExecutableButton);

if (!customPathsAllowed)
{
var securityWarning = new TextBlock
Expand Down Expand Up @@ -342,6 +378,34 @@ private void BuildPage()
}
}

private static IReadOnlyList<FilePickerFileType> GetExecutableFileTypeFilter()
{
if (!OperatingSystem.IsWindows())
{
return [new FilePickerFileType(CoreTools.Translate("All files")) { Patterns = ["*"] }];
}

return
[
new FilePickerFileType(CoreTools.Translate("Executable")) { Patterns = ["*.exe"] },
new FilePickerFileType(CoreTools.Translate("All files")) { Patterns = ["*"] },
];
}

private static void AddExecutablePathItem(ComboBox comboBox, string path)
{
if (string.IsNullOrWhiteSpace(path))
return;

foreach (object? item in comboBox.Items)
{
if (string.Equals(item?.ToString(), path, StringComparison.OrdinalIgnoreCase))
return;
}

comboBox.Items.Add(path);
}

private void BuildExtraControls(CheckboxCard_Dict disableNotifsCard)
{
ExtraControls.Children.Clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,16 @@ private void _logManagerInfo()
public Tuple<bool, string> GetExecutableFile()
{
var candidates = FindCandidateExecutableFiles();
if (candidates.Count == 0)
{
// No paths were found
return new(false, "");
}

// If custom package manager paths are DISABLED, get the first one (as old UniGetUI did) and return it.
if (!SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths))
{
if (candidates.Count == 0)
{
// No paths were found
return new(false, "");
}

return new(true, candidates[0]);
}
else
Expand All @@ -214,32 +215,33 @@ public Tuple<bool, string> GetExecutableFile()
// If there is no executable selection for this package manager
if (string.IsNullOrEmpty(exeSelection))
{
if (candidates.Count == 0)
{
// No paths were found
return new(false, "");
}

return new(true, candidates[0]);
}
else if (!File.Exists(exeSelection))
{
Logger.Error(
$"The selected executable path {exeSelection} for manager {Name} does not exist, the default one will be used..."
$"The selected executable path {exeSelection} for manager {Name} does not exist, the default one will be used if available..."
);
return new(true, candidates[0]);
}

// While technically executables that are not in the path should work,
// since detection of executables will be performed on the found paths, it is more consistent
// to throw an error when a non-found executable is used. Furthermore, doing this we can filter out
// any invalid paths or files.
if (candidates.Select(x => x.ToLower()).Contains(exeSelection.ToLower()))
else
{
return new(true, exeSelection);
}
else

if (candidates.Count == 0)
{
Logger.Error(
$"The selected executable path {exeSelection} for manager {Name} was not found among the candidates "
+ $"(executables found are [{string.Join(',', candidates)}]), the default will be used..."
);
return new(true, candidates[0]);
// No paths were found
return new(false, "");
}

return new(true, candidates[0]);
}
}

Expand Down
19 changes: 17 additions & 2 deletions src/UniGetUI.PackageEngine.Tests/PackageManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ public void GetExecutableFileReturnsFalseWhenNoCandidatesExist()
Assert.Equal(string.Empty, executable.Item2);
}

[Fact]
public void GetExecutableFileUsesSavedPathWhenNoCandidatesExistAndCustomPathsAreEnabled()
{
var manager = CreateManager();
var customPath = CreateExecutable("custom-only.exe");
manager.SetCandidateExecutableFiles();
EnableCustomManagerPaths();
Settings.SetDictionaryItem<string, string>(Settings.K.ManagerPaths, manager.Name, customPath);

var executable = manager.GetExecutableFile();

Assert.True(executable.Item1);
Assert.Equal(customPath, executable.Item2);
}

[Fact]
public void GetExecutableFileIgnoresSavedPathWhenCustomPathsAreDisabled()
{
Expand Down Expand Up @@ -197,7 +212,7 @@ public void GetExecutableFileFallsBackWhenSavedPathDoesNotExist()
}

[Fact]
public void GetExecutableFileFallsBackWhenSavedPathIsNotACandidate()
public void GetExecutableFileUsesSavedPathWhenSavedPathIsNotACandidate()
{
var manager = CreateManager();
var first = CreateExecutable("outside-a.exe");
Expand All @@ -214,7 +229,7 @@ public void GetExecutableFileFallsBackWhenSavedPathIsNotACandidate()
var executable = manager.GetExecutableFile();

Assert.True(executable.Item1);
Assert.Equal(first, executable.Item2);
Assert.Equal(outsideCandidateList, executable.Item2);
}

[Fact]
Expand Down
13 changes: 11 additions & 2 deletions src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,23 @@
FontSize="12"
FontWeight="SemiBold"
Opacity="0.7"
Text="Not finding the file you are looking for? Make sure it has been added to path."
Text="Not finding the file you are looking for? Browse to it or make sure it has been added to PATH."
/>
<ComboBox
x:Name="ExecutableComboBox"
Grid.Row="1"
Grid.ColumnSpan="2"
Grid.Column="0"
HorizontalAlignment="Stretch"
/>
<Button
x:Name="BrowseExecutableButton"
Grid.Row="1"
Grid.Column="1"
Padding="12,4"
Click="BrowseExecutableButton_Click"
>
<widgets:TranslatedTextBlock Text="Browse..." />
</Button>
<widgets:TranslatedTextBlock
x:Name="ExeFileWarningText"
Grid.Row="2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
ExecutableComboBox.IsEnabled = SecureSettings.Get(
SecureSettings.K.AllowCustomManagerPaths
);
BrowseExecutableButton.IsEnabled = SecureSettings.Get(
SecureSettings.K.AllowCustomManagerPaths
);

InstallOptionsPanel.Description = new InstallOptions_Manager(Manager);
InstallOptionsPanel.Padding = new(18, 24, 18, 24);
Expand Down Expand Up @@ -613,16 +616,26 @@ void ApplyManagerState(bool ShowVersion = false)
ExecutableComboBox.Items.Clear();
foreach (var path in Manager.FindCandidateExecutableFiles())
{
ExecutableComboBox.Items.Add(path);
AddExecutableComboBoxItem(path);
}
string selectedValue =
string configuredValue =
Settings.GetDictionaryItem<string, string>(Settings.K.ManagerPaths, Manager.Name)
?? "";
string selectedValue = configuredValue;
if (!string.IsNullOrEmpty(configuredValue) && File.Exists(configuredValue))
{
AddExecutableComboBoxItem(configuredValue);
}
if (string.IsNullOrEmpty(selectedValue))
{
var exe = Manager.GetExecutableFile();
selectedValue = exe.Item1 ? exe.Item2 : "";
}
else if (!File.Exists(selectedValue))
{
var exe = Manager.GetExecutableFile();
selectedValue = exe.Item1 ? exe.Item2 : "";
}

ExecutableComboBox.SelectedValue = selectedValue;
ExecutableComboBox.SelectionChanged += ExecutableComboBox_SelectionChanged;
Expand Down Expand Up @@ -699,17 +712,50 @@ private void ManagerLogs_Click(object sender, RoutedEventArgs e)

private void ExecutableComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (string.IsNullOrEmpty(ExecutableComboBox.SelectedValue.ToString()))
if (ExecutableComboBox.SelectedValue?.ToString() is not { Length: > 0 } selectedValue)
return;

Settings.SetDictionaryItem(
Settings.K.ManagerPaths,
Manager!.Name,
ExecutableComboBox.SelectedValue.ToString()
selectedValue
);
_ = ReloadPackageManager();
}

private void BrowseExecutableButton_Click(object sender, RoutedEventArgs e) =>
_ = _browseExecutableButton_Click();

private async Task _browseExecutableButton_Click()
{
if (Manager is null)
return;

ExternalLibraries.Pickers.FileOpenPicker picker = new(
MainApp.Instance.MainWindow.GetWindowHandle()
);
string file = picker.Show(["*.exe"]);
if (file == string.Empty)
return;

Settings.SetDictionaryItem(Settings.K.ManagerPaths, Manager.Name, file);
await ReloadPackageManager();
}

private void AddExecutableComboBoxItem(string path)
{
if (string.IsNullOrWhiteSpace(path))
return;

foreach (object? item in ExecutableComboBox.Items)
{
if (string.Equals(item?.ToString(), path, StringComparison.OrdinalIgnoreCase))
return;
}

ExecutableComboBox.Items.Add(path);
}

private void GoToSecureSettingsBtn_Click(object sender, RoutedEventArgs e)
{
MainApp.Instance.MainWindow.NavigationPage.OpenSettingsPage(typeof(Administrator));
Expand Down
Loading