From 2367901ed51afb8a90ecdb5c79a14cf70db15afe Mon Sep 17 00:00:00 2001 From: David Sungaila Date: Fri, 27 Sep 2024 00:15:30 +0200 Subject: [PATCH] Migrate to Windows App SDK 1.6 (#3) --- .gitignore | 2 +- SUBSTitute.sln | 22 +--- src/App.manifest | 4 +- src/Commands/MappingCommands.cs | 46 ++++++-- src/Converters/BoolToOpacityConverter.cs | 2 +- src/Converters/EnumToStringConverter.cs | 2 +- src/Converters/NullToVisibilityConverter.cs | 2 +- src/Converters/ThumbnailConverter.cs | 2 +- src/Extensions/HackedCollectionView.Defer.cs | 57 +++++++++ src/Extensions/HackedCollectionView.Events.cs | 62 ++++++++++ src/Extensions/HackedCollectionView.cs | 108 ++---------------- src/Extensions/TypeExtension.cs | 2 +- src/Extensions/VectorChangedEventArgs.cs | 59 +++++----- src/NativeMethods.txt | 3 +- src/Package.appxmanifest | 6 +- .../PublishProfiles/win-arm64.pubxml | 19 +++ src/Properties/PublishProfiles/win-x64.pubxml | 19 +++ src/PropertiesSigning.targets | 11 -- src/SUBSTitute.csproj | 69 +++++------ src/TrimmerRoots.xml | 20 ++++ src/ViewModels/AddDriveViewModel.cs | 2 +- src/ViewModels/DriveViewModel.cs | 22 +++- src/ViewModels/LetterViewModel.cs | 2 +- src/ViewModels/MainViewModel.cs | 2 +- src/ViewModels/MappingViewModel.cs | 2 +- src/ViewModels/RemoveDriveViewModel.cs | 2 +- src/ViewModels/SettingsViewModel.cs | 2 +- src/ViewModels/ViewModel.cs | 2 +- src/Views/GridView.xaml | 8 +- src/Views/ListView.xaml | 6 +- src/Views/MainWindow.xaml | 3 + src/Views/MainWindow.xaml.cs | 67 ++++++++++- src/Views/TileView.xaml | 8 +- 33 files changed, 407 insertions(+), 238 deletions(-) create mode 100644 src/Extensions/HackedCollectionView.Defer.cs create mode 100644 src/Extensions/HackedCollectionView.Events.cs create mode 100644 src/Properties/PublishProfiles/win-arm64.pubxml create mode 100644 src/Properties/PublishProfiles/win-x64.pubxml delete mode 100644 src/PropertiesSigning.targets create mode 100644 src/TrimmerRoots.xml diff --git a/.gitignore b/.gitignore index 8dd4607..6a54c30 100644 --- a/.gitignore +++ b/.gitignore @@ -184,7 +184,7 @@ publish/ *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted -*.pubxml +#*.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to diff --git a/SUBSTitute.sln b/SUBSTitute.sln index 12c7d73..8592d47 100644 --- a/SUBSTitute.sln +++ b/SUBSTitute.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 +# 17 VisualStudioVersion = 17.9.34723.18 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SUBSTitute", "src\SUBSTitute.csproj", "{3DA68281-59F8-46A1-B263-31EC608AFCE3}" @@ -14,13 +14,8 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 - Release|x86 = Release|x86 - ReleaseSigned|ARM64 = ReleaseSigned|ARM64 - ReleaseSigned|x64 = ReleaseSigned|x64 - ReleaseSigned|x86 = ReleaseSigned|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -29,27 +24,12 @@ Global {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Debug|x64.ActiveCfg = Debug|x64 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Debug|x64.Build.0 = Debug|x64 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Debug|x64.Deploy.0 = Debug|x64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Debug|x86.ActiveCfg = Debug|x86 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Debug|x86.Build.0 = Debug|x86 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Debug|x86.Deploy.0 = Debug|x86 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|ARM64.ActiveCfg = Release|ARM64 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|ARM64.Build.0 = Release|ARM64 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|ARM64.Deploy.0 = Release|ARM64 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|x64.ActiveCfg = Release|x64 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|x64.Build.0 = Release|x64 {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|x64.Deploy.0 = Release|x64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|x86.ActiveCfg = Release|x86 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|x86.Build.0 = Release|x86 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.Release|x86.Deploy.0 = Release|x86 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|ARM64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|ARM64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|ARM64.Deploy.0 = ReleaseSigned|ARM64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|x64.Deploy.0 = ReleaseSigned|x64 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|x86 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|x86.Build.0 = ReleaseSigned|x86 - {3DA68281-59F8-46A1-B263-31EC608AFCE3}.ReleaseSigned|x86.Deploy.0 = ReleaseSigned|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/App.manifest b/src/App.manifest index e35285d..3e66d15 100644 --- a/src/App.manifest +++ b/src/App.manifest @@ -2,12 +2,12 @@ + version="2.1.0.0" /> - + diff --git a/src/Commands/MappingCommands.cs b/src/Commands/MappingCommands.cs index 0f6128c..5113d3c 100644 --- a/src/Commands/MappingCommands.cs +++ b/src/Commands/MappingCommands.cs @@ -1,4 +1,5 @@ using CommunityToolkit.Mvvm.Input; +using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Sungaila.SUBSTitute.ViewModels; @@ -7,6 +8,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Windows.Storage; using Windows.Win32; namespace Sungaila.SUBSTitute.Commands @@ -48,24 +50,44 @@ private static bool IsVirtualDrive(string driveName) internal static DriveViewModel GetDriveViewModel(MappingViewModel mappingViewModel, DriveInfo driveInfo) { - string volumeLabel = string.Empty; - string driveFormat = string.Empty; - - if (driveInfo.IsReady) - { - volumeLabel = driveInfo.VolumeLabel; - driveFormat = driveInfo.DriveFormat; - } - - return new DriveViewModel + var result = new DriveViewModel { ParentViewModel = mappingViewModel, Letter = driveInfo.Name.First(), - Label = volumeLabel, - DriveFormat = driveFormat, + Label = driveInfo.Name, DriveType = driveInfo.DriveType, IsVirtual = IsVirtualDrive(driveInfo.Name) }; + + Task.Run(() => + { + // get the disk label + try + { + string driveDisplayName = StorageFolder.GetFolderFromPathAsync(driveInfo.Name).GetAwaiter().GetResult().DisplayName; + + App.MainWindow?.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () => + { + result.Label = driveDisplayName; + }); + } + catch { } + + // get the disk format + try + { + if (!driveInfo.IsReady) + return; + + App.MainWindow?.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () => + { + result.DriveFormat = driveInfo.DriveFormat; + }); + } + catch { } + }); + + return result; } public static readonly IAsyncRelayCommand AddVirtualDrive = new AsyncRelayCommand(async parameter => diff --git a/src/Converters/BoolToOpacityConverter.cs b/src/Converters/BoolToOpacityConverter.cs index 3f12f4e..21b3955 100644 --- a/src/Converters/BoolToOpacityConverter.cs +++ b/src/Converters/BoolToOpacityConverter.cs @@ -4,7 +4,7 @@ namespace Sungaila.SUBSTitute.Converters { - public class BoolToOpacityConverter : IValueConverter + public partial class BoolToOpacityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { diff --git a/src/Converters/EnumToStringConverter.cs b/src/Converters/EnumToStringConverter.cs index f600247..6ddb6f1 100644 --- a/src/Converters/EnumToStringConverter.cs +++ b/src/Converters/EnumToStringConverter.cs @@ -4,7 +4,7 @@ namespace Sungaila.SUBSTitute.Converters { - public class EnumToStringConverter : IValueConverter + public partial class EnumToStringConverter : IValueConverter { public object? Convert(object value, Type targetType, object parameter, string language) { diff --git a/src/Converters/NullToVisibilityConverter.cs b/src/Converters/NullToVisibilityConverter.cs index e4704d3..e96c1b4 100644 --- a/src/Converters/NullToVisibilityConverter.cs +++ b/src/Converters/NullToVisibilityConverter.cs @@ -4,7 +4,7 @@ namespace Sungaila.SUBSTitute.Converters { - public class NullToVisibilityConverter : IValueConverter + public partial class NullToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { diff --git a/src/Converters/ThumbnailConverter.cs b/src/Converters/ThumbnailConverter.cs index 070731d..915280f 100644 --- a/src/Converters/ThumbnailConverter.cs +++ b/src/Converters/ThumbnailConverter.cs @@ -7,7 +7,7 @@ namespace Sungaila.SUBSTitute.Converters { - public class ThumbnailConverter : IValueConverter + public partial class ThumbnailConverter : IValueConverter { public object? Convert(object value, Type targetType, object parameter, string language) { diff --git a/src/Extensions/HackedCollectionView.Defer.cs b/src/Extensions/HackedCollectionView.Defer.cs new file mode 100644 index 0000000..e95605e --- /dev/null +++ b/src/Extensions/HackedCollectionView.Defer.cs @@ -0,0 +1,57 @@ +// 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 new file mode 100644 index 0000000..b3331b5 --- /dev/null +++ b/src/Extensions/HackedCollectionView.Events.cs @@ -0,0 +1,62 @@ +// 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 index af2573c..0657e72 100644 --- a/src/Extensions/HackedCollectionView.cs +++ b/src/Extensions/HackedCollectionView.cs @@ -1,5 +1,4 @@ -#nullable disable -using CommunityToolkit.WinUI.Collections; +using CommunityToolkit.WinUI.Collections; using CommunityToolkit.WinUI.Helpers; using Microsoft.UI.Xaml.Data; using System; @@ -16,7 +15,7 @@ namespace Sungaila.SUBSTitute.Extensions; -public class HackedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer +public partial class HackedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer { private readonly List _view; @@ -437,7 +436,7 @@ int IComparer.Compare(object x, object y) /// /// Occurs when a property value changes. /// - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; /// /// Property changed event invoker @@ -801,96 +800,13 @@ private bool MoveCurrentToIndex(int i) OnCurrentChanged(null!); return true; } +} - /// - /// 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 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(); - } - } - - /// - /// 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)); - } -} \ No newline at end of file +#pragma warning restore CS8767 +#pragma warning restore CS8769 +#pragma warning restore CS8622 +#pragma warning restore CS8601 +#pragma warning restore CS8600 +#pragma warning restore CS8604 +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning restore CS8603 // Possible null reference return. diff --git a/src/Extensions/TypeExtension.cs b/src/Extensions/TypeExtension.cs index 5ff4ee5..09f5a26 100644 --- a/src/Extensions/TypeExtension.cs +++ b/src/Extensions/TypeExtension.cs @@ -5,7 +5,7 @@ namespace Sungaila.SUBSTitute.Extensions { [MarkupExtensionReturnType(ReturnType = typeof(string))] - public class TypeExtension : MarkupExtension + public partial class TypeExtension : MarkupExtension { public Type? Type { get; set; } diff --git a/src/Extensions/VectorChangedEventArgs.cs b/src/Extensions/VectorChangedEventArgs.cs index b8ff5dc..8e9392e 100644 --- a/src/Extensions/VectorChangedEventArgs.cs +++ b/src/Extensions/VectorChangedEventArgs.cs @@ -4,39 +4,38 @@ using Windows.Foundation.Collections; -namespace Sungaila.SUBSTitute.Extensions +namespace Sungaila.SUBSTitute.Extensions; + +/// +/// Vector changed EventArgs +/// +internal partial class VectorChangedEventArgs : IVectorChangedEventArgs { /// - /// Vector changed EventArgs + /// Initializes a new instance of the class. /// - internal class VectorChangedEventArgs : IVectorChangedEventArgs + /// collection change type + /// index of item changed + /// item changed + public VectorChangedEventArgs(CollectionChange cc, int index = -1, object item = null!) { - /// - /// Initializes a new instance of the class. - /// - /// collection change type - /// index of item changed - /// item changed - public VectorChangedEventArgs(CollectionChange cc, int index = -1, object? item = null) - { - CollectionChange = cc; - Index = (uint)index; - } + CollectionChange = cc; + Index = (uint)index; + } - /// - /// Gets the type of change that occurred in the vector. - /// - /// - /// The type of change in the vector. - /// - public CollectionChange CollectionChange { get; } + /// + /// Gets the type of change that occurred in the vector. + /// + /// + /// The type of change in the vector. + /// + public CollectionChange CollectionChange { get; } - /// - /// Gets the position where the change occurred in the vector. - /// - /// - /// The zero-based position where the change occurred in the vector, if applicable. - /// - public uint Index { get; } - } -} \ No newline at end of file + /// + /// Gets the position where the change occurred in the vector. + /// + /// + /// The zero-based position where the change occurred in the vector, if applicable. + /// + public uint Index { get; } +} diff --git a/src/NativeMethods.txt b/src/NativeMethods.txt index 100d02c..be080e5 100644 --- a/src/NativeMethods.txt +++ b/src/NativeMethods.txt @@ -2,4 +2,5 @@ QueryDosDevice IFileOpenDialog FileOpenDialog -CoCreateInstance \ No newline at end of file +CoCreateInstance +GetWindowPlacement \ No newline at end of file diff --git a/src/Package.appxmanifest b/src/Package.appxmanifest index 253bcd0..ee7c0f5 100644 --- a/src/Package.appxmanifest +++ b/src/Package.appxmanifest @@ -10,7 +10,7 @@ + Version="2.1.0.0" /> @@ -21,8 +21,8 @@ - - + + diff --git a/src/Properties/PublishProfiles/win-arm64.pubxml b/src/Properties/PublishProfiles/win-arm64.pubxml new file mode 100644 index 0000000..3526538 --- /dev/null +++ b/src/Properties/PublishProfiles/win-arm64.pubxml @@ -0,0 +1,19 @@ + + + + + FileSystem + ARM64 + win-arm64 + bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ + true + False + False + True + False + True + False + + \ No newline at end of file diff --git a/src/Properties/PublishProfiles/win-x64.pubxml b/src/Properties/PublishProfiles/win-x64.pubxml new file mode 100644 index 0000000..e6a0cd6 --- /dev/null +++ b/src/Properties/PublishProfiles/win-x64.pubxml @@ -0,0 +1,19 @@ + + + + + FileSystem + x64 + win-x64 + bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ + true + False + False + True + False + True + False + + \ No newline at end of file diff --git a/src/PropertiesSigning.targets b/src/PropertiesSigning.targets deleted file mode 100644 index 2cc9dbf..0000000 --- a/src/PropertiesSigning.targets +++ /dev/null @@ -1,11 +0,0 @@ - - - - - C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\ - - - Open Source Developer, David Sungaila - http://time.certum.pl - - \ No newline at end of file diff --git a/src/SUBSTitute.csproj b/src/SUBSTitute.csproj index 9a611a9..f64166a 100644 --- a/src/SUBSTitute.csproj +++ b/src/SUBSTitute.csproj @@ -3,26 +3,30 @@ WinExe - net8.0-windows10.0.22000.0 - 10.0.22000.0 + net8.0-windows10.0.22621.0 + 10.0.22621.0 + 10.0.26100.45 SUBSTitute Sungaila.SUBSTitute App.manifest - x86;x64;ARM64 - win10-x86;win10-x64;win10-arm64 - win10-$(Platform).pubxml + x64;ARM64 + win-x64;win-arm64 + true + win-$(Platform).pubxml true true - true SUBSTitute.ico 8CD1A8DE2BD78D45B0761089D621324F934DA0CA True - Debug;Release;ReleaseSigned + false + partial + true + true - 2.0.3 + 2.1.0 David Sungaila false @@ -52,7 +56,7 @@ Never 0 X:\Repos\sungaila\SUBSTitute\src\bin\Msix\ - x86|x64|arm64 + x64|arm64 True @@ -62,7 +66,7 @@ - + true true true @@ -86,35 +90,29 @@ + - - - - - + + + + + - - - + + + + - + - + - - - - $(DefaultXamlRuntime) @@ -123,9 +121,6 @@ MSBuild:Compile - - - $(DefaultXamlRuntime) Designer @@ -147,6 +142,15 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ViewModels/AddDriveViewModel.cs b/src/ViewModels/AddDriveViewModel.cs index 2c726a1..8de7719 100644 --- a/src/ViewModels/AddDriveViewModel.cs +++ b/src/ViewModels/AddDriveViewModel.cs @@ -5,7 +5,7 @@ namespace Sungaila.SUBSTitute.ViewModels { - public class AddDriveViewModel : ViewModel + public partial class AddDriveViewModel : ViewModel { public required MappingViewModel ParentViewModel { get; init; } diff --git a/src/ViewModels/DriveViewModel.cs b/src/ViewModels/DriveViewModel.cs index 158e966..6c09535 100644 --- a/src/ViewModels/DriveViewModel.cs +++ b/src/ViewModels/DriveViewModel.cs @@ -1,12 +1,19 @@ using Sungaila.SUBSTitute.Commands; using System; using System.IO; +using System.Text.RegularExpressions; using System.Windows.Input; namespace Sungaila.SUBSTitute.ViewModels { - public class DriveViewModel : ViewModel + public partial class DriveViewModel : ViewModel { + [GeneratedRegex(@" \([A-Z]:\)")] + private static partial Regex AppendedDriveLetterRegex(); + + [GeneratedRegex(@"[A-Z]:\\")] + private static partial Regex DriveLetterRegex(); + public required MappingViewModel ParentViewModel { get; init; } private char _letter; @@ -31,9 +38,18 @@ public string DriveName get { if (!string.IsNullOrEmpty(Label)) - return $"{Label} ({Letter}:)"; + { + if (AppendedDriveLetterRegex().IsMatch(Label)) + { + return Label[..^5]; + } + else if (!DriveLetterRegex().IsMatch(Label)) + { + return Label; + } + } - return $"{Letter}:"; + return string.Empty; } } diff --git a/src/ViewModels/LetterViewModel.cs b/src/ViewModels/LetterViewModel.cs index f1684a9..f6468c1 100644 --- a/src/ViewModels/LetterViewModel.cs +++ b/src/ViewModels/LetterViewModel.cs @@ -1,6 +1,6 @@ namespace Sungaila.SUBSTitute.ViewModels { - public class LetterViewModel : ViewModel + public partial class LetterViewModel : ViewModel { private char _name; diff --git a/src/ViewModels/MainViewModel.cs b/src/ViewModels/MainViewModel.cs index df7983f..49e612a 100644 --- a/src/ViewModels/MainViewModel.cs +++ b/src/ViewModels/MainViewModel.cs @@ -1,6 +1,6 @@ namespace Sungaila.SUBSTitute.ViewModels { - public class MainViewModel : ViewModel + public partial class MainViewModel : ViewModel { public MappingViewModel Mapping { get; } = new(); diff --git a/src/ViewModels/MappingViewModel.cs b/src/ViewModels/MappingViewModel.cs index 9464b7d..08ae920 100644 --- a/src/ViewModels/MappingViewModel.cs +++ b/src/ViewModels/MappingViewModel.cs @@ -6,7 +6,7 @@ namespace Sungaila.SUBSTitute.ViewModels { - public class MappingViewModel : ViewModel + public partial class MappingViewModel : ViewModel { private bool _showAllDrives = App.LocalSettings.Values["MappingShowAllDrives"] as bool? ?? true; diff --git a/src/ViewModels/RemoveDriveViewModel.cs b/src/ViewModels/RemoveDriveViewModel.cs index bf3c15d..b9ca672 100644 --- a/src/ViewModels/RemoveDriveViewModel.cs +++ b/src/ViewModels/RemoveDriveViewModel.cs @@ -2,7 +2,7 @@ namespace Sungaila.SUBSTitute.ViewModels { - public class RemoveDriveViewModel : ViewModel + public partial class RemoveDriveViewModel : ViewModel { public required MappingViewModel ParentViewModel { get; init; } diff --git a/src/ViewModels/SettingsViewModel.cs b/src/ViewModels/SettingsViewModel.cs index 3f0a9ce..4e052f3 100644 --- a/src/ViewModels/SettingsViewModel.cs +++ b/src/ViewModels/SettingsViewModel.cs @@ -6,7 +6,7 @@ namespace Sungaila.SUBSTitute.ViewModels { - public class SettingsViewModel : ViewModel + public partial class SettingsViewModel : ViewModel { private CultureInfo _selectedLanguage = new(ApplicationLanguages.PrimaryLanguageOverride); diff --git a/src/ViewModels/ViewModel.cs b/src/ViewModels/ViewModel.cs index efed8cb..1be014f 100644 --- a/src/ViewModels/ViewModel.cs +++ b/src/ViewModels/ViewModel.cs @@ -2,7 +2,7 @@ namespace Sungaila.SUBSTitute.ViewModels { - public class ViewModel : ObservableValidator + public partial class ViewModel : ObservableValidator { } } \ No newline at end of file diff --git a/src/Views/GridView.xaml b/src/Views/GridView.xaml index 6e5dbeb..592764f 100644 --- a/src/Views/GridView.xaml +++ b/src/Views/GridView.xaml @@ -41,16 +41,16 @@ + ToolTipService.ToolTip="{x:Bind Label, Mode=OneWay}" /> + ToolTipService.ToolTip="{x:Bind DriveTypeLocalized, Mode=OneWay}" /> diff --git a/src/Views/MainWindow.xaml.cs b/src/Views/MainWindow.xaml.cs index 5681660..1a7a22a 100644 --- a/src/Views/MainWindow.xaml.cs +++ b/src/Views/MainWindow.xaml.cs @@ -6,6 +6,10 @@ using Sungaila.SUBSTitute.ViewModels; using System; using System.Linq; +using Windows.Graphics; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.UI.WindowsAndMessaging; using WinUIEx; using Icon = System.Drawing.Icon; @@ -20,7 +24,8 @@ public MainWindow() var exePath = Environment.ProcessPath!; var icon = Icon.ExtractAssociatedIcon(exePath)!; - this.AppWindow.SetIcon(Win32Interop.GetIconIdFromIcon(icon.Handle)); + var iconId = Win32Interop.GetIconIdFromIcon(icon.Handle); + this.SetIcon(iconId); if (Content is FrameworkElement frameworkElement) { @@ -39,6 +44,32 @@ public MainWindow() { this.Title += $" ({App.ResourceLoader.GetString("Administrator")})"; } + + if (App.LocalSettings.Values["MainWindowWidth"] is double width && App.LocalSettings.Values["MainWindowHeight"] is double height) + { + try + { + this.SetWindowSize(width, height); + } + catch { } + } + + if (App.LocalSettings.Values["MainWindowX"] is int x && App.LocalSettings.Values["MainWindowY"] is int y) + { + try + { + this.Move(x, y); + } + catch { } + } + + if (App.LocalSettings.Values["MainWindowWindowState"] is int savedWindowState) + { + var windowState = (WindowState)savedWindowState; + + if (windowState == WindowState.Maximized) + this.WindowState = WindowState.Maximized; + } } private void NavigationView_Loaded(object sender, RoutedEventArgs e) @@ -83,5 +114,39 @@ public void ShowInfoBar(string message, InfoBarSeverity severity) InfoBar.Message = message; InfoBar.IsOpen = true; } + + private void WindowEx_WindowStateChanged(object sender, WindowState e) + { + if (e == WindowState.Minimized) + return; + + App.LocalSettings.Values["MainWindowWindowState"] = (int)e; + } + + private void WindowEx_SizeChanged(object sender, WindowSizeChangedEventArgs args) + { + if (!this.Visible || this.WindowState != WindowState.Normal) + return; + + App.LocalSettings.Values["MainWindowWidth"] = args.Size.Width; + App.LocalSettings.Values["MainWindowHeight"] = args.Size.Height; + } + + private void WindowEx_PositionChanged(object sender, PointInt32 e) + { + if (!this.Visible || this.WindowState != WindowState.Normal) + return; + + // WindowEx_PositionChanged is called before WindowEx_WindowStateChanged + // so we have to call Win32 APIs to check the current window state + WINDOWPLACEMENT windowplacement = new(); + PInvoke.GetWindowPlacement((HWND)this.GetWindowHandle(), ref windowplacement); + + if (windowplacement.showCmd == SHOW_WINDOW_CMD.SW_SHOWMAXIMIZED) + return; + + App.LocalSettings.Values["MainWindowX"] = e.X; + App.LocalSettings.Values["MainWindowY"] = e.Y; + } } } \ No newline at end of file diff --git a/src/Views/TileView.xaml b/src/Views/TileView.xaml index a301213..aeb8790 100644 --- a/src/Views/TileView.xaml +++ b/src/Views/TileView.xaml @@ -47,16 +47,16 @@ + ToolTipService.ToolTip="{x:Bind Label, Mode=OneWay}" /> + ToolTipService.ToolTip="{x:Bind DriveTypeLocalized, Mode=OneWay}" />