Skip to content

Commit 5997b5a

Browse files
committed
refactor of installation locators and rough setup popup implementation
1 parent d80817f commit 5997b5a

14 files changed

Lines changed: 513 additions & 2 deletions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace WheelWizard.DolphinManagent.Abstractions;
2+
3+
public record DolphinInstallation(string DisplayName, string LaunchTarget, bool Found);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace WheelWizard.DolphinManagent.Abstractions;
2+
3+
public interface IDolphinInstaller
4+
{
5+
IReadOnlyList<DolphinInstallation> AvailableInstallationMethods();
6+
//bool InstallDolphin(DolphinInstallation method);
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace WheelWizard.DolphinManagent.Abstractions;
2+
3+
public interface IDolphinLocator
4+
{
5+
IReadOnlyList<DolphinInstallation> DetectInstallations();
6+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using WheelWizard.DolphinManagent.Abstractions;
2+
using WheelWizard.DolphinManagent.Linux;
3+
4+
namespace WheelWizard.DolphinManagent;
5+
6+
public static class DolphinManagmentExtensions
7+
{
8+
public static IServiceCollection AddDolphinManagement(this IServiceCollection services)
9+
{
10+
#if LINUX
11+
services.AddSingleton<ILinuxCommandEnvironment, LinuxCommandEnvironment>();
12+
services.AddSingleton<ILinuxProcessService, LinuxProcessService>();
13+
//services.AddSingleton<IDolphinInstaller, LinuxDolphinInstaller>();
14+
services.AddSingleton<IDolphinLocator, LinuxDolphinLocator>();
15+
#endif
16+
return services;
17+
}
18+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using WheelWizard.Helpers;
2+
3+
namespace WheelWizard.DolphinManagent.Linux;
4+
5+
public interface ILinuxCommandEnvironment
6+
{
7+
bool IsCommandAvailable(string command);
8+
string DetectPackageManagerInstallCommand();
9+
}
10+
11+
public sealed class LinuxCommandEnvironment : ILinuxCommandEnvironment
12+
{
13+
public bool IsCommandAvailable(string command)
14+
{
15+
return EnvHelper.IsValidUnixCommand(command);
16+
}
17+
18+
public string DetectPackageManagerInstallCommand()
19+
{
20+
return EnvHelper.DetectLinuxPackageManagerInstallCommand();
21+
}
22+
}

WheelWizard/Features/DolphinManagent/Linux/LinuxDolphinInstaller.cs

Whitespace-only changes.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using WheelWizard.DolphinManagent.Abstractions;
2+
3+
namespace WheelWizard.DolphinManagent.Linux;
4+
5+
public sealed class LinuxDolphinLocator(ILinuxCommandEnvironment commandEnvironment, ILinuxProcessService processService) : IDolphinLocator
6+
{
7+
private bool IsDolphinInstalledInFlatpak()
8+
{
9+
const string dolphinAppId = "org.DolphinEmu.dolphin-emu";
10+
var processResult = processService.Run("flatpak", "list --app --columns=application", out var stdOut, out _);
11+
12+
return processResult.IsSuccess && processResult.Value == 0 && stdOut.Split('\n').Any(line => line == dolphinAppId);
13+
}
14+
15+
private bool IsDolphinInstalledNative()
16+
{
17+
if (!commandEnvironment.IsCommandAvailable("dolphin-emu"))
18+
{
19+
return false;
20+
}
21+
var processResult = processService.Run("dolphin-emu", "--version");
22+
return processResult.IsSuccess && processResult.Value == 0;
23+
}
24+
25+
public IReadOnlyList<DolphinInstallation> DetectInstallations()
26+
{
27+
return
28+
[
29+
new("Flatpak", "flatpak run org.DolphinEmu.dolphin-emu", IsDolphinInstalledInFlatpak()),
30+
new("Native", "dolphin-emu", IsDolphinInstalledNative()),
31+
];
32+
}
33+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using System.Diagnostics;
2+
using System.Text.RegularExpressions;
3+
4+
namespace WheelWizard.DolphinManagent.Linux;
5+
6+
public interface ILinuxProcessService
7+
{
8+
OperationResult<int> Run(string fileName, string arguments, out string stdOut, out string stdErr);
9+
OperationResult<int> Run(string fileName, string arguments);
10+
Task<OperationResult<int>> RunWithProgressAsync(string fileName, string arguments, IProgress<int>? progress = null);
11+
Task<OperationResult> LaunchAndStopAsync(string fileName, string arguments, TimeSpan duration);
12+
}
13+
14+
public sealed class LinuxProcessService : ILinuxProcessService
15+
{
16+
public OperationResult<int> Run(string fileName, string arguments, out string stdOut, out string stdErr)
17+
{
18+
var localStdOut = "";
19+
var localStdErr = "";
20+
var result = TryCatch(
21+
() =>
22+
{
23+
var processInfo = new ProcessStartInfo
24+
{
25+
FileName = fileName,
26+
Arguments = arguments,
27+
RedirectStandardOutput = true,
28+
RedirectStandardError = true,
29+
UseShellExecute = false,
30+
CreateNoWindow = true,
31+
};
32+
33+
using var process = Process.Start(processInfo);
34+
if (process == null)
35+
return -1;
36+
37+
localStdOut = process.StandardOutput.ReadToEnd();
38+
localStdErr = process.StandardError.ReadToEnd();
39+
process.WaitForExit();
40+
return process.ExitCode;
41+
},
42+
$"Failed to run process: {fileName} {arguments}"
43+
);
44+
45+
stdOut = localStdOut;
46+
stdErr = localStdErr;
47+
return result;
48+
}
49+
50+
public OperationResult<int> Run(string fileName, string arguments)
51+
{
52+
return Run(fileName, arguments, out _, out _);
53+
}
54+
55+
public async Task<OperationResult<int>> RunWithProgressAsync(string fileName, string arguments, IProgress<int>? progress = null)
56+
{
57+
return await TryCatch(
58+
async () =>
59+
{
60+
var processInfo = new ProcessStartInfo
61+
{
62+
FileName = fileName,
63+
Arguments = arguments,
64+
RedirectStandardOutput = true,
65+
RedirectStandardError = true,
66+
UseShellExecute = false,
67+
CreateNoWindow = true,
68+
};
69+
70+
using var process = Process.Start(processInfo);
71+
if (process == null)
72+
return -1;
73+
74+
process.OutputDataReceived += (_, eventArgs) => ReportProgress(eventArgs.Data, progress);
75+
process.ErrorDataReceived += (_, eventArgs) => ReportProgress(eventArgs.Data, progress);
76+
77+
process.BeginOutputReadLine();
78+
process.BeginErrorReadLine();
79+
await process.WaitForExitAsync();
80+
return process.ExitCode;
81+
},
82+
$"Failed to run process: {fileName} {arguments}"
83+
);
84+
}
85+
86+
public async Task<OperationResult> LaunchAndStopAsync(string fileName, string arguments, TimeSpan duration)
87+
{
88+
return await TryCatch(
89+
async () =>
90+
{
91+
using var process = new Process
92+
{
93+
StartInfo = new()
94+
{
95+
FileName = fileName,
96+
Arguments = arguments,
97+
RedirectStandardOutput = true,
98+
RedirectStandardError = true,
99+
UseShellExecute = false,
100+
CreateNoWindow = true,
101+
},
102+
};
103+
104+
process.Start();
105+
await Task.Delay(duration);
106+
107+
if (!process.HasExited)
108+
process.Kill();
109+
},
110+
$"Failed to run process: {fileName} {arguments}"
111+
);
112+
}
113+
114+
private static void ReportProgress(string? output, IProgress<int>? progress)
115+
{
116+
if (string.IsNullOrWhiteSpace(output))
117+
return;
118+
119+
var match = Regex.Match(output, @"(\d+)%");
120+
if (match.Success && int.TryParse(match.Groups[1].Value, out var percent))
121+
progress?.Report(percent);
122+
}
123+
}

WheelWizard/Services/Storage/FilePickerHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public static async Task<List<string>> OpenFilePickerAsync(
4747
if (storageProvider == null)
4848
return null;
4949

50-
var topLevel = TopLevel.GetTopLevel(storageProvider.MainWindow);
50+
var topLevel = TopLevel.GetTopLevel(storageProvider.MainWindow); // Makes file picker popup not work when called from popup
5151
if (topLevel?.StorageProvider == null)
5252
return null;
5353

WheelWizard/SetupExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using WheelWizard.CustomCharacters;
88
using WheelWizard.CustomDistributions;
99
using WheelWizard.DolphinInstaller;
10+
using WheelWizard.DolphinManagent;
1011
using WheelWizard.Features.Archives;
1112
using WheelWizard.Features.Patches;
1213
using WheelWizard.GameBanana;
@@ -33,7 +34,7 @@ public static class SetupExtensions
3334
public static void AddWheelWizardServices(this IServiceCollection services)
3435
{
3536
// Features
36-
services.AddDolphinInstaller();
37+
services.AddDolphinManagement();
3738
services.AddLocalization();
3839
services.AddSettings();
3940
services.AddCustomCharacters();

0 commit comments

Comments
 (0)