From bfee579719679cf191c8f496e1e1f4d68a80f134 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Thu, 6 Nov 2025 13:47:51 -0700 Subject: [PATCH] Fix DirectoryOrCustomSelectControl --- .../DirectoryOrCustomSelectControl.axaml | 78 +++++-- .../DirectoryOrCustomSelectControl.axaml.cs | 198 +++++++++++------- .../Settings/ImportantSettingsVM.cs | 7 +- .../Configuration.KnownDirectories.cs | 4 +- 4 files changed, 182 insertions(+), 105 deletions(-) diff --git a/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml b/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml index 761f205d..72cae907 100644 --- a/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml +++ b/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml @@ -6,29 +6,63 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="LibationAvalonia.Controls.DirectoryOrCustomSelectControl"> - - + - + - + - - - + + diff --git a/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs b/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs index fe51170e..13981d56 100644 --- a/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs +++ b/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs @@ -1,142 +1,184 @@ using Avalonia; +using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Platform.Storage; using Dinah.Core; using LibationFileManager; using ReactiveUI; using System.Collections.Generic; +using System.IO; using System.Linq; +#nullable enable namespace LibationAvalonia.Controls { public partial class DirectoryOrCustomSelectControl : UserControl { - public static readonly StyledProperty> KnownDirectoriesProperty = - AvaloniaProperty.Register>(nameof(KnownDirectories), DirectorySelectControl.DefaultKnownDirectories); + public static readonly StyledProperty?> KnownDirectoriesProperty = + AvaloniaProperty.Register?>(nameof(KnownDirectories), DefaultKnownDirectories); - public static readonly StyledProperty SubDirectoryProperty = - AvaloniaProperty.Register(nameof(SubDirectory)); + public static readonly StyledProperty SubDirectoryProperty = + AvaloniaProperty.Register(nameof(SubDirectory)); - public static readonly StyledProperty DirectoryProperty = - AvaloniaProperty.Register(nameof(Directory)); + public static readonly StyledProperty DirectoryProperty = + AvaloniaProperty.Register(nameof(Directory)); - public List KnownDirectories + public IList? KnownDirectories { get => GetValue(KnownDirectoriesProperty); set => SetValue(KnownDirectoriesProperty, value); } - public string Directory + public string? Directory { get => GetValue(DirectoryProperty); set => SetValue(DirectoryProperty, value); } - public string SubDirectory + public string? SubDirectory { get => GetValue(SubDirectoryProperty); set => SetValue(SubDirectoryProperty, value); } - private readonly DirectoryState directoryState = new(); + public static IList DefaultKnownDirectories => [ + Configuration.KnownDirectories.WinTemp, + Configuration.KnownDirectories.UserProfile, + Configuration.KnownDirectories.ApplicationData, + Configuration.KnownDirectories.AppDir, + Configuration.KnownDirectories.MyMusic, + Configuration.KnownDirectories.MyDocs, + Configuration.KnownDirectories.LibationFiles]; + private readonly AvaloniaList _knownDirNames; public DirectoryOrCustomSelectControl() { InitializeComponent(); - - grid.DataContext = directoryState; - - directoryState.PropertyChanged += DirectoryState_PropertyChanged; - PropertyChanged += DirectoryOrCustomSelectControl_PropertyChanged; + _knownDirNames = new(GetKnownDirectories(DefaultKnownDirectories)); + cmbKnownDirs.ItemsSource = _knownDirNames; + cmbKnownDirs.SelectionChanged += CmbKnownDirs_SelectionChanged; + btnBrowse.Click += Browse_Click; } - private void DirectoryState_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + private void CmbKnownDirs_SelectionChanged(object? sender, SelectionChangedEventArgs e) { - if (e.PropertyName is nameof(DirectoryState.SelectedDirectory) or nameof(DirectoryState.KnownChecked) && - directoryState.KnownChecked && - directoryState.SelectedDirectory is Configuration.KnownDirectories kdir && - kdir is not Configuration.KnownDirectories.None) + if (cmbKnownDirs.SelectedItem is KnownDirectoryItem item && item.Directory is not null) { - Directory = kdir is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute : Configuration.GetKnownDirectoryPath(kdir); - } - else if (e.PropertyName is nameof(DirectoryState.CustomDir) or nameof(DirectoryState.CustomChecked) && - directoryState.CustomChecked && - directoryState.CustomDir is not null) - { - Directory = directoryState.CustomDir; + Directory = item.Directory; } } - private class DirectoryState : ViewModels.ViewModelBase - { - private string _customDir; - private string _subDirectory; - private bool _knownChecked; - private bool _customChecked; - private Configuration.KnownDirectories? _selectedDirectory; - public string CustomDir { get => _customDir; set => this.RaiseAndSetIfChanged(ref _customDir, value); } - public string SubDirectory { get => _subDirectory; set => this.RaiseAndSetIfChanged(ref _subDirectory, value); } - public bool KnownChecked { get => _knownChecked; set => this.RaiseAndSetIfChanged(ref _knownChecked, value); } - public bool CustomChecked { get => _customChecked; set => this.RaiseAndSetIfChanged(ref _customChecked, value); } + private IEnumerable GetKnownDirectories(IEnumerable knownDirs) + => knownDirs.Select(k => new KnownDirectoryItem(k, SubDirectory)).Where(k => k.Directory is not null); - public Configuration.KnownDirectories? SelectedDirectory { get => _selectedDirectory; set => this.RaiseAndSetIfChanged(ref _selectedDirectory, value); } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + if (change.Property == SubDirectoryProperty) + { + foreach (var item in _knownDirNames) + { + item.SubDirectory = SubDirectory; + } + VerifyAndApplyDirectory(Directory); + } + else if (change.Property == KnownDirectoriesProperty) + { + var knownDirs = KnownDirectories?.Count > 0 ? KnownDirectories : DefaultKnownDirectories; + if (!_knownDirNames.Select(k => k.KnownDirectory).SequenceEqual(knownDirs)) + { + _knownDirNames.Clear(); + _knownDirNames.AddRange(GetKnownDirectories(knownDirs)); + } + VerifyAndApplyDirectory(Directory); + } + else if (change.Property == DirectoryProperty) + { + VerifyAndApplyDirectory(Directory); + } + + base.OnPropertyChanged(change); } - private async void CustomDirBrowseBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + private void VerifyAndApplyDirectory(string? directory) { - var options = new Avalonia.Platform.Storage.FolderPickerOpenOptions + if (string.IsNullOrWhiteSpace(Directory)) + return; + + bool dirIsKnown = false; + foreach (var item in _knownDirNames) + { + if (item.IsSamePathAs(directory)) + { + rbKnown.IsChecked = true; + Directory = item.Directory; + cmbKnownDirs.SelectedItem = item; + dirIsKnown = true; + break; + } + } + if (!dirIsKnown) + { + tboxCustomDirPath.Text = directory; + rbCustom.IsChecked = true; + } + } + + public async void Browse_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + if (VisualRoot is not Window window) + return; + + var options = new FolderPickerOpenOptions { AllowMultiple = false }; - var selectedFolders = await (VisualRoot as Window).StorageProvider.OpenFolderPickerAsync(options); - - directoryState.CustomDir = selectedFolders.SingleOrDefault()?.TryGetLocalPath() ?? directoryState.CustomDir; + var selectedFolders = await window.StorageProvider.OpenFolderPickerAsync(options); + Directory = selectedFolders.SingleOrDefault()?.TryGetLocalPath() ?? Directory; } - private void DirectoryOrCustomSelectControl_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) + private class KnownDirectoryItem : ReactiveObject { - if (e.Property == DirectoryProperty) + public Configuration.KnownDirectories KnownDirectory { get; set; } + private string? _directory; + public string? Directory { get => _directory; private set => this.RaiseAndSetIfChanged(ref _directory, value); } + public string? Name { get; } + private string? _subDir; + public string? SubDirectory { - var directory = Directory?.Trim() ?? ""; - - var noSubDir = RemoveSubDirectoryFromPath(directory); - var known = Configuration.GetKnownDirectory(noSubDir); - - if (known == Configuration.KnownDirectories.None && noSubDir == Configuration.AppDir_Absolute) - known = Configuration.KnownDirectories.AppDir; - - if (known is Configuration.KnownDirectories.None) + get => _subDir; + set { - directoryState.CustomDir = directory; - directoryState.CustomChecked = true; - } - else - { - directoryState.SelectedDirectory = known; - directoryState.KnownChecked = true; + _subDir = value; + if (Configuration.GetKnownDirectoryPath(KnownDirectory) is string dir) + { + Directory = Path.Combine(dir, _subDir ?? ""); + } } } - else if (e.Property == KnownDirectoriesProperty && - KnownDirectories.Count > 0 && - directoryState.SelectedDirectory is null or Configuration.KnownDirectories.None) - directoryState.SelectedDirectory = KnownDirectories[0]; - } - private string RemoveSubDirectoryFromPath(string path) - { - if (string.IsNullOrWhiteSpace(SubDirectory)) - return path; + public KnownDirectoryItem(Configuration.KnownDirectories known, string? subDir) + { + Name = known.GetDescription(); + KnownDirectory = known; + SubDirectory = subDir; + } - path = path?.Trim() ?? ""; - if (string.IsNullOrWhiteSpace(path)) - return path; + public bool IsSamePathAs(string? otherPath) + { + if (string.IsNullOrWhiteSpace(otherPath) || string.IsNullOrWhiteSpace(Directory)) + return false; - var bottomDir = System.IO.Path.GetFileName(path); - if (SubDirectory.EqualsInsensitive(bottomDir)) - return System.IO.Path.GetDirectoryName(path); + try + { + var p1 = Path.GetFullPath(Directory); + var p2 = Path.GetFullPath(otherPath); + return p1.Equals(p2, System.StringComparison.OrdinalIgnoreCase); + } + catch { return false; } + } - return path; + public override string? ToString() => Name?.ToString(); } } } diff --git a/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs b/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs index 7e88c783..22bf08ee 100644 --- a/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs +++ b/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs @@ -67,10 +67,11 @@ namespace LibationAvalonia.ViewModels.Settings public List KnownDirectories { get; } = new() { - Configuration.KnownDirectories.UserProfile, - Configuration.KnownDirectories.AppDir, - Configuration.KnownDirectories.MyDocs, + Configuration.KnownDirectories.LibationFiles, Configuration.KnownDirectories.MyMusic, + Configuration.KnownDirectories.MyDocs, + Configuration.KnownDirectories.AppDir, + Configuration.KnownDirectories.UserProfile }; public string BooksText { get; } = Configuration.GetDescription(nameof(Configuration.Books)); diff --git a/Source/LibationFileManager/Configuration.KnownDirectories.cs b/Source/LibationFileManager/Configuration.KnownDirectories.cs index 8159e0ff..e0871f86 100644 --- a/Source/LibationFileManager/Configuration.KnownDirectories.cs +++ b/Source/LibationFileManager/Configuration.KnownDirectories.cs @@ -10,8 +10,8 @@ namespace LibationFileManager { public partial class Configuration { - public static string ProcessDirectory { get; } = Path.GetDirectoryName(Exe.FileLocationOnDisk)!; - public static string AppDir_Relative => $@".{Path.PathSeparator}{LIBATION_FILES_KEY}"; + public static string ProcessDirectory { get; } = Path.GetDirectoryName(Environment.ProcessPath)!; + public static string AppDir_Relative => $@".{Path.DirectorySeparatorChar}{LIBATION_FILES_KEY}"; public static string AppDir_Absolute => Path.GetFullPath(Path.Combine(ProcessDirectory, LIBATION_FILES_KEY)); public static string MyDocs => Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Libation")); public static string MyMusic => Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyMusic), "Libation"));