diff --git a/Assets/LogoWithClosedPackage.ico b/Assets/LogoWithClosedPackage.ico
new file mode 100644
index 0000000..6154297
Binary files /dev/null and b/Assets/LogoWithClosedPackage.ico differ
diff --git a/Assets/LogoWithClosedPackage.svg b/Assets/LogoWithClosedPackage.svg
new file mode 100644
index 0000000..a0a1e6f
--- /dev/null
+++ b/Assets/LogoWithClosedPackage.svg
@@ -0,0 +1,300 @@
+
+
+
diff --git a/PackageInstaller.Core/ModelViews/GettingStartedModelView.cs b/PackageInstaller.Core/ModelViews/GettingStartedModelView.cs
index 9b659c8..eac8e5d 100644
--- a/PackageInstaller.Core/ModelViews/GettingStartedModelView.cs
+++ b/PackageInstaller.Core/ModelViews/GettingStartedModelView.cs
@@ -1,5 +1,6 @@
using System.Reactive;
using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
using ReactiveUI;
using Sextant;
using Shared.Misc;
@@ -32,6 +33,11 @@ IApplicationLifeCycle lifeCycle
LaunchExplorerCommand = ReactiveCommand.CreateFromTask(LaunchExplorerAsync);
LaunchWithFileCommand = ReactiveCommand.CreateFromTask(LaunchWithFileAsync);
ExitCommand = ReactiveCommand.Create(() => _lifeCycle.Exit(0));
+ OpenDefaultAppsSettingsPageCommand = ReactiveCommand.CreateFromTask(
+ _launcher.LaunchDefaultAppsSettingsPageAsync
+ );
+
+ _userShouldCheckFileHandlerRegistrations = false;
}
private async Task LaunchWithFileAsync(string? filePath)
@@ -75,6 +81,17 @@ private async Task PickFilesAsync()
public ReactiveCommand LaunchExplorerCommand { get; }
public ReactiveCommand LaunchWithFileCommand { get; }
public ReactiveCommand ExitCommand { get; }
+ public ReactiveCommand OpenDefaultAppsSettingsPageCommand { get; }
+
+ bool _userShouldCheckFileHandlerRegistrations;
+ public bool UserShouldCheckFileHandlerRegistrations
+ {
+ get { return _userShouldCheckFileHandlerRegistrations; }
+ private set
+ {
+ this.RaiseAndSetIfChanged(ref _userShouldCheckFileHandlerRegistrations, value);
+ }
+ }
public string Id { get; } = nameof(GettingStartedModelView);
@@ -92,6 +109,15 @@ public IObservable WhenNavigatedFrom(INavigationParameter parameter)
public IObservable WhenNavigatingTo(INavigationParameter parameter)
{
- return Observable.Return(Unit.Default);
+ return ProcessAsync().ToObservable(RxApp.MainThreadScheduler);
+ }
+
+ public async Task ProcessAsync()
+ {
+ await Task.Delay(10).ConfigureAwait(true);
+
+ UserShouldCheckFileHandlerRegistrations = !await _launcher
+ .VerifyThatAllFileTypeAssociationsAreRegisteredAsync()
+ .ConfigureAwait(true);
}
}
diff --git a/PackageInstaller.Core/ModelViews/PreparationViewModel.cs b/PackageInstaller.Core/ModelViews/PreparationViewModel.cs
index 9e48137..f59d3da 100644
--- a/PackageInstaller.Core/ModelViews/PreparationViewModel.cs
+++ b/PackageInstaller.Core/ModelViews/PreparationViewModel.cs
@@ -106,7 +106,9 @@ public async Task ProcessAsync(string[] arguments)
private void NavigateToGettingStarted()
{
- _viewStackService.PushPage().Subscribe();
+ _viewStackService
+ .PushPage(new Sextant.NavigationParameter())
+ .Subscribe();
}
private FileSystemPath ParseArguments(string[] arguments)
diff --git a/PackageInstaller/MainWindow.xaml.cs b/PackageInstaller/MainWindow.xaml.cs
index 7ca54fe..52219f7 100644
--- a/PackageInstaller/MainWindow.xaml.cs
+++ b/PackageInstaller/MainWindow.xaml.cs
@@ -1,8 +1,11 @@
using Microsoft.UI.Xaml;
using System;
+using System.IO;
using System.Linq;
using System.Reactive;
using System.Threading;
+using Windows.ApplicationModel;
+using Windows.Storage;
using Community.Sextant.WinUI;
using Community.Sextant.WinUI.Adapters;
using NativeInterop.Win32.Xaml;
@@ -23,24 +26,33 @@ public sealed partial class MainWindow : DesktopWindow
private readonly ThemeManager _themeManager;
private string args = string.Empty;
private readonly IApplicationLifeCycle _lifeCycle;
+ private IPath _path;
public MainWindow(
IParameterViewStackService viewStackService,
INavigationService navigationService,
ThemeManager themeManager,
- IApplicationLifeCycle lifeCycle
+ IApplicationLifeCycle lifeCycle,
+ IPath path
)
{
_viewStackService = viewStackService;
_navigationService = navigationService;
_themeManager = themeManager;
_lifeCycle = lifeCycle;
+ _path = path;
this.InitializeComponent();
Title = "Winstrumenta PackageManager";
ExtendsContentIntoTitleBar = true;
SetTitleBar(DummyTitleBar); // do not set the title bar to use a 100% custom one.
+
+ var iconPath = Path.Combine(Package.Current.InstalledPath, "PackageInstaller.ico");
+ if (File.Exists(iconPath))
+ {
+ _nativeWindow.LoadIcon(iconPath);
+ }
}
public void SetLaunchArgs(string arguments)
diff --git a/PackageInstaller/PackageInstaller.csproj b/PackageInstaller/PackageInstaller.csproj
index a99fdf9..7db1a9e 100644
--- a/PackageInstaller/PackageInstaller.csproj
+++ b/PackageInstaller/PackageInstaller.csproj
@@ -85,6 +85,7 @@
+
@@ -145,6 +146,7 @@
+
diff --git a/PackageInstaller/PackageInstaller.ico b/PackageInstaller/PackageInstaller.ico
new file mode 100644
index 0000000..6154297
Binary files /dev/null and b/PackageInstaller/PackageInstaller.ico differ
diff --git a/PackageInstaller/Pages/GettingStarted.xaml b/PackageInstaller/Pages/GettingStarted.xaml
index 03950fa..079abe8 100644
--- a/PackageInstaller/Pages/GettingStarted.xaml
+++ b/PackageInstaller/Pages/GettingStarted.xaml
@@ -25,6 +25,7 @@
+
- Double click in Windows Explorer to install
+ Double click package files in Windows Explorer to install
-
+
+ Remember to change the default file type associations.
+
+
+
+
+
diff --git a/PackageInstaller/Pages/GettingStarted.xaml.cs b/PackageInstaller/Pages/GettingStarted.xaml.cs
index a582575..47f82b3 100644
--- a/PackageInstaller/Pages/GettingStarted.xaml.cs
+++ b/PackageInstaller/Pages/GettingStarted.xaml.cs
@@ -43,6 +43,21 @@ public GettingStarted()
this.BindCommand(ViewModel, (vm) => vm.ExitCommand, (v) => v.ExitButton)
.DisposeWith(disposable);
+
+ this.BindCommand(
+ ViewModel,
+ (vm) => vm.OpenDefaultAppsSettingsPageCommand,
+ (v) => v.OpenDefaultAppsSettingsPage
+ )
+ .DisposeWith(disposable);
+
+ this.OneWayBind(
+ ViewModel,
+ (vm) => vm.UserShouldCheckFileHandlerRegistrations,
+ (v) => v.DefaultAppsSettingsPageInfo.Visibility,
+ (visible) => visible ? Visibility.Visible : Visibility.Collapsed
+ )
+ .DisposeWith(disposable);
}
);
}
diff --git a/Shared.Services.Implementations.Winui/Launcher.cs b/Shared.Services.Implementations.Winui/Launcher.cs
index 914666d..83a16a9 100644
--- a/Shared.Services.Implementations.Winui/Launcher.cs
+++ b/Shared.Services.Implementations.Winui/Launcher.cs
@@ -14,4 +14,14 @@ public Task LaunchFolderAsync(string folderPath)
{
return Windows.System.Launcher.LaunchFolderPathAsync(folderPath).AsTask();
}
+
+ public Task LaunchDefaultAppsSettingsPageAsync()
+ {
+ return Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:defaultapps")).AsTask();
+ }
+
+ public async Task VerifyThatAllFileTypeAssociationsAreRegisteredAsync()
+ {
+ return false; // not possible to actually check
+ }
}
diff --git a/Shared.Services/ILauncher.cs b/Shared.Services/ILauncher.cs
index 3b35e25..eda2cb7 100644
--- a/Shared.Services/ILauncher.cs
+++ b/Shared.Services/ILauncher.cs
@@ -5,4 +5,6 @@ public interface ILauncher
public Task LaunchAsync(Uri uri);
public Task LaunchFolderAsync(string folderPath);
+ Task LaunchDefaultAppsSettingsPageAsync();
+ Task VerifyThatAllFileTypeAssociationsAreRegisteredAsync();
}
diff --git a/Winstrumenta.Package.Tests/GettingStartedPageTests.cs b/Winstrumenta.Package.Tests/GettingStartedPageTests.cs
index fb86899..4c7b27b 100644
--- a/Winstrumenta.Package.Tests/GettingStartedPageTests.cs
+++ b/Winstrumenta.Package.Tests/GettingStartedPageTests.cs
@@ -8,7 +8,11 @@ public class GettingStartedPageTests : TestSuiteBase
[Test]
public void ShouldShowGettingStartedPageWhenNoArgumentsProvided()
{
- GetSession().FindElementByAccessibilityId("Title").Text.Should().Be("Getting started!");
+ var session = GetSession();
+ session.FindElementByAccessibilityId("Title").Text.Should().Be("Getting started!");
+ session.FindElementByAccessibilityId("Close").Click();
+
+ WaitFor(() => IsAppRunning().Should().BeFalse("App should have been closed by clicking the close button"));
}
[Test]
@@ -33,7 +37,7 @@ public void ShouldOpenExplorerWhenClickedOnLink()
private bool HasExplorerAsChildProcess()
{
- var process = GetProcess();
+ var process = GetAppProcess();
if (process == null)
{
@@ -45,12 +49,4 @@ private bool HasExplorerAsChildProcess()
.Any(childProcess => childProcess.ProcessName == "explorer.exe");
}
- private Process? GetProcess()
- {
- return Process
- .GetProcesses()
- .FirstOrDefault(
- (p) => p.MainWindowHandle.ToString() == GetSession().CurrentWindowHandle
- );
- }
}
diff --git a/Winstrumenta.Package.Tests/TestEnvironment.cs b/Winstrumenta.Package.Tests/TestEnvironment.cs
index 7321130..d038977 100644
--- a/Winstrumenta.Package.Tests/TestEnvironment.cs
+++ b/Winstrumenta.Package.Tests/TestEnvironment.cs
@@ -10,7 +10,7 @@ class TestEnvironment
private TestEnvironmentDetails? _environment;
private string _testBaseDirectory;
- public const string WAD_URL = "127.0.0.1:4723";
+ public const string WAD_URL = "http://127.0.0.1:4723";
private const string WAD_FOLDER_NAME = "wad";
public TestEnvironmentDetails? PreparedEnvDetails => _environment;
diff --git a/Winstrumenta.Package.Tests/TestSuiteBase.cs b/Winstrumenta.Package.Tests/TestSuiteBase.cs
index 01b80e5..0d2cab4 100644
--- a/Winstrumenta.Package.Tests/TestSuiteBase.cs
+++ b/Winstrumenta.Package.Tests/TestSuiteBase.cs
@@ -1,4 +1,5 @@
-using OpenQA.Selenium.Appium;
+using System.Diagnostics;
+using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
namespace Winstrumenta.Package.Tests;
@@ -41,7 +42,7 @@ private void CreateSession(string[] arguments)
opts.AddAdditionalCapability("deviceName", "WindowsPC");
_session = new WindowsDriver(
- new Uri($"http://{TestEnvironment.WAD_URL}/wd/hub"),
+ new Uri($"{TestEnvironment.WAD_URL}/wd/hub"),
opts
);
}
@@ -101,4 +102,50 @@ public void Sleep(int milliseconds)
{
Thread.Sleep(milliseconds);
}
+
+ public void WaitFor(Action check, int timeout = 2_000, int numberOfChecks = 5)
+ {
+ int sleepDuration = timeout / numberOfChecks;
+ Exception? previousException = null;
+
+ while (numberOfChecks > 0)
+ {
+ numberOfChecks--;
+
+ try
+ {
+ check();
+ return;
+ }
+ catch (Exception e)
+ {
+ previousException = e;
+
+ Thread.Sleep(sleepDuration);
+ }
+ }
+
+ throw new Exception("WaitFor: check failed!", previousException);
+ }
+
+ public bool IsAppRunning()
+ {
+ using var proc = GetAppProcess();
+
+ return proc is { HasExited: false };
+ }
+
+ public Process? GetAppProcess()
+ {
+ return Process
+ .GetProcesses()
+ .FirstOrDefault(
+ (p) => p.MainWindowHandle.ToString() == GetSession().CurrentWindowHandle
+ );
+ }
+
+ public byte[] GetFixtureFromFile(string filename)
+ {
+ return File.ReadAllBytes(Path.Combine(TestContext.CurrentContext.TestDirectory, filename));
+ }
}
diff --git a/Winstrumenta.Package.Tests/Winstrumenta.Package.Tests.csproj b/Winstrumenta.Package.Tests/Winstrumenta.Package.Tests.csproj
index 64dc524..6d05153 100644
--- a/Winstrumenta.Package.Tests/Winstrumenta.Package.Tests.csproj
+++ b/Winstrumenta.Package.Tests/Winstrumenta.Package.Tests.csproj
@@ -1,4 +1,4 @@
-
+
net6.0-windows
enable
@@ -10,7 +10,7 @@
-
+
diff --git a/Winstrumenta.msbuildproj b/Winstrumenta.msbuildproj
index f29c2d0..3512f10 100644
--- a/Winstrumenta.msbuildproj
+++ b/Winstrumenta.msbuildproj
@@ -1,4 +1,4 @@
-
+
net46