diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 41058ad..6f8d1b8 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -45,18 +45,19 @@ jobs:
uses: microsoft/setup-msbuild@main
with:
msbuild-architecture: x64
- - name: Setup .NET 8
+ - name: Setup .NET 9
uses: actions/setup-dotnet@main
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
+ dotnet-quality: 'preview'
- name: Setup Windows 11 SDK (10.0.22621.0)
uses: GuillaumeFalourd/setup-windows10-sdk-action@main
with:
sdk-version: 22621
- name: Restore
- run: msbuild SUBSTitute.sln /t:restore
+ run: dotnet restore SUBSTitute.sln
- name: Build
- run: msbuild SUBSTitute.sln /p:Configuration=${{ github.event_name != 'workflow_dispatch' && 'Debug' || inputs.build_configuration }} /p:VersionSuffix=ci /p:RestorePackages=false
+ run: dotnet build SUBSTitute.sln --configuration ${{ github.event_name != 'workflow_dispatch' && 'Debug' || inputs.build_configuration }} --no-restore -p:VersionSuffix=ci
sonarcloud:
name: SonarCloud
runs-on: windows-latest
@@ -66,10 +67,11 @@ jobs:
uses: actions/checkout@main
with:
fetch-depth: 0
- - name: Setup .NET 8
+ - name: Setup .NET 9
uses: actions/setup-dotnet@main
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
+ dotnet-quality: 'preview'
- name: Setup Windows 11 SDK (10.0.22621.0)
uses: GuillaumeFalourd/setup-windows10-sdk-action@main
with:
@@ -109,5 +111,5 @@ jobs:
run: |
.\.sonar\scanner\dotnet-sonarscanner begin /k:"sungaila_SUBSTitute" /o:"sungaila" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml
dotnet restore SUBSTitute.sln
- dotnet build SUBSTitute.sln --configuration ${{ github.event_name != 'workflow_dispatch' && 'Debug' || inputs.build_configuration }} --no-restore
+ dotnet build SUBSTitute.sln --configuration ${{ github.event_name != 'workflow_dispatch' && 'Debug' || inputs.build_configuration }} --no-restore
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
diff --git a/README.md b/README.md
index 323b2e7..1a13002 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,14 @@
# SUBSTitute
A GUI for mapping directories to virtual drives (see *SUBST* command). It is built on top of **.NET 8.0** and **Windows UI Library 3 (WinUI 3)**.
-
+
+
+
+
+
+
+
-
+
diff --git a/etc/screenshot1_de-de.png b/etc/screenshot1_de-de.png
index 30ba67f..4020fb8 100644
Binary files a/etc/screenshot1_de-de.png and b/etc/screenshot1_de-de.png differ
diff --git a/etc/screenshot1_en-us.png b/etc/screenshot1_en-us.png
index 772e86e..8008568 100644
Binary files a/etc/screenshot1_en-us.png and b/etc/screenshot1_en-us.png differ
diff --git a/etc/screenshot2_de-de.png b/etc/screenshot2_de-de.png
index 71a279b..c6c9137 100644
Binary files a/etc/screenshot2_de-de.png and b/etc/screenshot2_de-de.png differ
diff --git a/etc/screenshot2_en-us.png b/etc/screenshot2_en-us.png
index 16570fe..e58c726 100644
Binary files a/etc/screenshot2_en-us.png and b/etc/screenshot2_en-us.png differ
diff --git a/etc/screenshot3_de-de.png b/etc/screenshot3_de-de.png
index 4b19b08..451120f 100644
Binary files a/etc/screenshot3_de-de.png and b/etc/screenshot3_de-de.png differ
diff --git a/etc/screenshot3_en-us.png b/etc/screenshot3_en-us.png
index b86645f..3fbbb74 100644
Binary files a/etc/screenshot3_en-us.png and b/etc/screenshot3_en-us.png differ
diff --git a/etc/screenshot4_de-de.png b/etc/screenshot4_de-de.png
index 860f3c0..7d8be9a 100644
Binary files a/etc/screenshot4_de-de.png and b/etc/screenshot4_de-de.png differ
diff --git a/etc/screenshot4_en-us.png b/etc/screenshot4_en-us.png
index 649fe44..aa7608c 100644
Binary files a/etc/screenshot4_en-us.png and b/etc/screenshot4_en-us.png differ
diff --git a/etc/screenshot5_de-de.png b/etc/screenshot5_de-de.png
index 711122f..5e421c1 100644
Binary files a/etc/screenshot5_de-de.png and b/etc/screenshot5_de-de.png differ
diff --git a/etc/screenshot5_en-us.png b/etc/screenshot5_en-us.png
index 610627d..de0da0d 100644
Binary files a/etc/screenshot5_en-us.png and b/etc/screenshot5_en-us.png differ
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 0000000..7e59a38
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/App.manifest b/src/App.manifest
index 3e66d15..414b90a 100644
--- a/src/App.manifest
+++ b/src/App.manifest
@@ -2,7 +2,7 @@
+ version="2.1.1.0" />
diff --git a/src/App.xaml b/src/App.xaml
index 72ff7c0..2cb626b 100644
--- a/src/App.xaml
+++ b/src/App.xaml
@@ -6,6 +6,7 @@
+
diff --git a/src/Commands/AddDriveCommands.cs b/src/Commands/AddDriveCommands.cs
index fdf38e7..68f2168 100644
--- a/src/Commands/AddDriveCommands.cs
+++ b/src/Commands/AddDriveCommands.cs
@@ -46,7 +46,7 @@ public static class AddDriveCommands
parameter.SelectedLetter = parameter.AvailableLetters.FirstOrDefault();
});
- public static readonly IRelayCommand AddVirtualDrive = new AsyncRelayCommand(async parameter =>
+ public static readonly IRelayCommand AddVirtualDrive = new RelayCommand(parameter =>
{
parameter!.CancelClose = false;
@@ -55,7 +55,7 @@ public static class AddDriveCommands
var selectedPath = Path.GetFullPath(parameter.SelectedPath.Trim('\"'));
- _ = await StorageFolder.GetFolderFromPathAsync(selectedPath);
+ _ = StorageFolder.GetFolderFromPathAsync(selectedPath).GetAwaiter().GetResult();
if (parameter.IsPermanent)
{
diff --git a/src/Commands/MappingCommands.cs b/src/Commands/MappingCommands.cs
index 6bba23f..98da81e 100644
--- a/src/Commands/MappingCommands.cs
+++ b/src/Commands/MappingCommands.cs
@@ -61,21 +61,29 @@ internal static DriveViewModel GetDriveViewModel(MappingViewModel mappingViewMod
Task.Run(async () =>
{
- // get the disk label and file system
+ string? driveName = null;
+ string? driveFormat = null;
+
try
{
- var folder = await StorageFolder.GetFolderFromPathAsync(driveInfo.Name);
- var properties = await folder.GetBasicPropertiesAsync();
- var prop = await properties.RetrievePropertiesAsync(["System.Volume.FileSystem"]);
- var filesystem = prop.First().Value as string;
-
- App.MainWindow?.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
- {
- result.Label = folder.DisplayName;
- result.DriveFormat = filesystem ?? string.Empty;
- });
+ driveName = (await StorageFolder.GetFolderFromPathAsync(driveInfo.Name)).DisplayName;
}
catch { }
+
+ try
+ {
+ driveFormat = driveInfo.DriveFormat;
+ }
+ catch (IOException ex) when (ex.HResult == -2147024875)
+ {
+ // ERROR_NOT_READY: Device not ready
+ }
+
+ App.MainWindow?.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
+ {
+ result.Label = driveName ?? string.Empty;
+ result.DriveFormat = driveFormat ?? string.Empty;
+ });
});
return result;
diff --git a/src/Converters/ElementThemeToIntConverter.cs b/src/Converters/ElementThemeToIntConverter.cs
new file mode 100644
index 0000000..094c071
--- /dev/null
+++ b/src/Converters/ElementThemeToIntConverter.cs
@@ -0,0 +1,35 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Data;
+using System;
+
+namespace Sungaila.SUBSTitute.Converters
+{
+ public partial class ElementThemeToIntConverter : IValueConverter
+ {
+ public object? Convert(object value, Type targetType, object parameter, string language)
+ {
+ if (value is not ElementTheme theme)
+ return DependencyProperty.UnsetValue;
+
+ return theme switch
+ {
+ ElementTheme.Light => 0,
+ ElementTheme.Dark => 1,
+ _ => 2
+ };
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ if (value is not int selectedIndex)
+ return DependencyProperty.UnsetValue;
+
+ return selectedIndex switch
+ {
+ 0 => ElementTheme.Light,
+ 1 => ElementTheme.Dark,
+ _ => ElementTheme.Default
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Extensions/HackedCollectionView.Defer.cs b/src/Extensions/HackedCollectionView.Defer.cs
deleted file mode 100644
index e95605e..0000000
--- a/src/Extensions/HackedCollectionView.Defer.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-
-namespace Sungaila.SUBSTitute.Extensions;
-
-///
-/// A collection view implementation that supports filtering, grouping, sorting and incremental loading
-///
-public partial class HackedCollectionView
-{
- ///
- /// Stops refreshing until it is disposed
- ///
- /// An disposable object
- public IDisposable DeferRefresh()
- {
- return new NotificationDeferrer(this);
- }
-
- ///
- /// Notification deferrer helper class
- ///
-#pragma warning disable CA1063 // Implement IDisposable Correctly
- public partial class NotificationDeferrer : IDisposable
-#pragma warning restore CA1063 // Implement IDisposable Correctly
- {
- private readonly HackedCollectionView _acvs;
- private readonly object _currentItem;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Source ACVS
- public NotificationDeferrer(HackedCollectionView acvs)
- {
- _acvs = acvs;
- _currentItem = _acvs.CurrentItem;
- _acvs._deferCounter++;
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
- /// 2
-#pragma warning disable CA1063 // Implement IDisposable Correctly
- public void Dispose()
-#pragma warning restore CA1063 // Implement IDisposable Correctly
- {
- _acvs.MoveCurrentTo(_currentItem);
- _acvs._deferCounter--;
- _acvs.Refresh();
- }
- }
-}
diff --git a/src/Extensions/HackedCollectionView.Events.cs b/src/Extensions/HackedCollectionView.Events.cs
deleted file mode 100644
index b3331b5..0000000
--- a/src/Extensions/HackedCollectionView.Events.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.UI.Xaml.Data;
-using Windows.Foundation.Collections;
-
-namespace Sungaila.SUBSTitute.Extensions;
-
-///
-/// A collection view implementation that supports filtering, grouping, sorting and incremental loading
-///
-public partial class HackedCollectionView
-{
- ///
- /// Currently selected item changing event
- ///
- /// event args
- private void OnCurrentChanging(CurrentChangingEventArgs e)
- {
- if (_deferCounter > 0)
- {
- return;
- }
-
- CurrentChanging?.Invoke(this, e);
- }
-
- ///
- /// Currently selected item changed event
- ///
- /// event args
- private void OnCurrentChanged(object e)
- {
- if (_deferCounter > 0)
- {
- return;
- }
-
- CurrentChanged?.Invoke(this, e);
-
- // ReSharper disable once ExplicitCallerInfoArgument
- OnPropertyChanged(nameof(CurrentItem));
- }
-
- ///
- /// Vector changed event
- ///
- /// event args
- private void OnVectorChanged(IVectorChangedEventArgs e)
- {
- if (_deferCounter > 0)
- {
- return;
- }
-
- VectorChanged?.Invoke(this, e);
-
- // ReSharper disable once ExplicitCallerInfoArgument
- OnPropertyChanged(nameof(Count));
- }
-}
diff --git a/src/Extensions/HackedCollectionView.cs b/src/Extensions/HackedCollectionView.cs
deleted file mode 100644
index 0657e72..0000000
--- a/src/Extensions/HackedCollectionView.cs
+++ /dev/null
@@ -1,812 +0,0 @@
-using CommunityToolkit.WinUI.Collections;
-using CommunityToolkit.WinUI.Helpers;
-using Microsoft.UI.Xaml.Data;
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Collections.Specialized;
-using System.ComponentModel;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
-
-namespace Sungaila.SUBSTitute.Extensions;
-
-public partial class HackedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer