285 lines
9.1 KiB
C#
285 lines
9.1 KiB
C#
|
|
using Avalonia;
|
||
|
|
using Avalonia.Controls;
|
||
|
|
using Avalonia.Data;
|
||
|
|
using Avalonia.Platform.Storage;
|
||
|
|
using ImageCatalog_2.Services;
|
||
|
|
using Microsoft.Extensions.DependencyInjection;
|
||
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
namespace ImageCatalog_2.Controls;
|
||
|
|
|
||
|
|
public partial class PathPickerField : UserControl
|
||
|
|
{
|
||
|
|
private readonly PickerPreferenceService _pickerPreferenceService;
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> LabelProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(Label), string.Empty);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> TextProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(Text), string.Empty, defaultBindingMode: BindingMode.TwoWay);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> WatermarkProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(Watermark), string.Empty);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> PreferenceKeyProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(PreferenceKey), string.Empty);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> PickerTitleProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(PickerTitle), string.Empty);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> FileTypeNameProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(FileTypeName), string.Empty);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> FilePatternsProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(FilePatterns), string.Empty);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<string> DefaultExtensionProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, string>(nameof(DefaultExtension), string.Empty);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<PathPickerSelectionMode> PickerModeProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, PathPickerSelectionMode>(nameof(PickerMode), PathPickerSelectionMode.Folder);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<bool> IsTextReadOnlyProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, bool>(nameof(IsTextReadOnly), false);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<bool> ShowPickerButtonProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, bool>(nameof(ShowPickerButton), true);
|
||
|
|
|
||
|
|
public static readonly StyledProperty<bool> AppendDirectorySeparatorProperty =
|
||
|
|
AvaloniaProperty.Register<PathPickerField, bool>(nameof(AppendDirectorySeparator), false);
|
||
|
|
|
||
|
|
public PathPickerField()
|
||
|
|
{
|
||
|
|
_pickerPreferenceService = Program.ServiceProvider.GetRequiredService<PickerPreferenceService>();
|
||
|
|
InitializeComponent();
|
||
|
|
}
|
||
|
|
|
||
|
|
public string Label
|
||
|
|
{
|
||
|
|
get => GetValue(LabelProperty);
|
||
|
|
set => SetValue(LabelProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public string Text
|
||
|
|
{
|
||
|
|
get => GetValue(TextProperty);
|
||
|
|
set => SetValue(TextProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public string Watermark
|
||
|
|
{
|
||
|
|
get => GetValue(WatermarkProperty);
|
||
|
|
set => SetValue(WatermarkProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public string PreferenceKey
|
||
|
|
{
|
||
|
|
get => GetValue(PreferenceKeyProperty);
|
||
|
|
set => SetValue(PreferenceKeyProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public string PickerTitle
|
||
|
|
{
|
||
|
|
get => GetValue(PickerTitleProperty);
|
||
|
|
set => SetValue(PickerTitleProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public string FileTypeName
|
||
|
|
{
|
||
|
|
get => GetValue(FileTypeNameProperty);
|
||
|
|
set => SetValue(FileTypeNameProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public string FilePatterns
|
||
|
|
{
|
||
|
|
get => GetValue(FilePatternsProperty);
|
||
|
|
set => SetValue(FilePatternsProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public string DefaultExtension
|
||
|
|
{
|
||
|
|
get => GetValue(DefaultExtensionProperty);
|
||
|
|
set => SetValue(DefaultExtensionProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public PathPickerSelectionMode PickerMode
|
||
|
|
{
|
||
|
|
get => GetValue(PickerModeProperty);
|
||
|
|
set => SetValue(PickerModeProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool IsTextReadOnly
|
||
|
|
{
|
||
|
|
get => GetValue(IsTextReadOnlyProperty);
|
||
|
|
set => SetValue(IsTextReadOnlyProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool ShowPickerButton
|
||
|
|
{
|
||
|
|
get => GetValue(ShowPickerButtonProperty);
|
||
|
|
set => SetValue(ShowPickerButtonProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool AppendDirectorySeparator
|
||
|
|
{
|
||
|
|
get => GetValue(AppendDirectorySeparatorProperty);
|
||
|
|
set => SetValue(AppendDirectorySeparatorProperty, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
private async void PickPath_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||
|
|
{
|
||
|
|
var topLevel = TopLevel.GetTopLevel(this);
|
||
|
|
var storageProvider = topLevel?.StorageProvider;
|
||
|
|
if (storageProvider is null)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var selectedPath = await PickPathAsync(storageProvider);
|
||
|
|
if (string.IsNullOrWhiteSpace(selectedPath))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
Text = selectedPath;
|
||
|
|
|
||
|
|
if (!string.IsNullOrWhiteSpace(PreferenceKey))
|
||
|
|
{
|
||
|
|
_pickerPreferenceService.RememberPath(PreferenceKey, selectedPath);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OpenPath_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||
|
|
{
|
||
|
|
PathShellService.OpenInExplorer(Text);
|
||
|
|
}
|
||
|
|
|
||
|
|
private async Task<string?> PickPathAsync(IStorageProvider storageProvider)
|
||
|
|
{
|
||
|
|
var suggestedStartLocation = await TryGetSuggestedStartLocationAsync(storageProvider);
|
||
|
|
var pickerTitle = ResolvePickerTitle();
|
||
|
|
|
||
|
|
switch (PickerMode)
|
||
|
|
{
|
||
|
|
case PathPickerSelectionMode.Folder:
|
||
|
|
{
|
||
|
|
var folders = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||
|
|
{
|
||
|
|
Title = pickerTitle,
|
||
|
|
SuggestedStartLocation = suggestedStartLocation
|
||
|
|
});
|
||
|
|
|
||
|
|
return folders.Count == 0
|
||
|
|
? null
|
||
|
|
: NormalizeSelectedPath(folders[0].Path.LocalPath);
|
||
|
|
}
|
||
|
|
case PathPickerSelectionMode.OpenFile:
|
||
|
|
{
|
||
|
|
var files = await storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||
|
|
{
|
||
|
|
Title = pickerTitle,
|
||
|
|
SuggestedStartLocation = suggestedStartLocation,
|
||
|
|
FileTypeFilter = BuildFileTypes()
|
||
|
|
});
|
||
|
|
|
||
|
|
return files.Count == 0
|
||
|
|
? null
|
||
|
|
: files[0].Path.LocalPath;
|
||
|
|
}
|
||
|
|
case PathPickerSelectionMode.SaveFile:
|
||
|
|
{
|
||
|
|
var file = await storageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||
|
|
{
|
||
|
|
Title = pickerTitle,
|
||
|
|
SuggestedStartLocation = suggestedStartLocation,
|
||
|
|
DefaultExtension = NormalizeDefaultExtension(DefaultExtension),
|
||
|
|
FileTypeChoices = BuildFileTypes()
|
||
|
|
});
|
||
|
|
|
||
|
|
return file?.Path.LocalPath;
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private async Task<IStorageFolder?> TryGetSuggestedStartLocationAsync(IStorageProvider storageProvider)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrWhiteSpace(PreferenceKey))
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
return await _pickerPreferenceService.TryGetStartFolderAsync(storageProvider, PreferenceKey, Text);
|
||
|
|
}
|
||
|
|
|
||
|
|
private IReadOnlyList<FilePickerFileType> BuildFileTypes()
|
||
|
|
{
|
||
|
|
var patterns = (FilePatterns ?? string.Empty)
|
||
|
|
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||
|
|
|
||
|
|
if (patterns.Length == 0)
|
||
|
|
{
|
||
|
|
return Array.Empty<FilePickerFileType>();
|
||
|
|
}
|
||
|
|
|
||
|
|
var fileTypeName = string.IsNullOrWhiteSpace(FileTypeName)
|
||
|
|
? "File"
|
||
|
|
: FileTypeName.Trim();
|
||
|
|
|
||
|
|
return
|
||
|
|
[
|
||
|
|
new FilePickerFileType(fileTypeName)
|
||
|
|
{
|
||
|
|
Patterns = patterns.ToList()
|
||
|
|
}
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
private string ResolvePickerTitle()
|
||
|
|
{
|
||
|
|
if (!string.IsNullOrWhiteSpace(PickerTitle))
|
||
|
|
{
|
||
|
|
return PickerTitle;
|
||
|
|
}
|
||
|
|
|
||
|
|
var cleanedLabel = string.IsNullOrWhiteSpace(Label)
|
||
|
|
? "percorso"
|
||
|
|
: Label.Trim().TrimEnd(':');
|
||
|
|
|
||
|
|
return PickerMode == PathPickerSelectionMode.SaveFile
|
||
|
|
? $"Salva {cleanedLabel.ToLowerInvariant()}"
|
||
|
|
: $"Seleziona {cleanedLabel.ToLowerInvariant()}";
|
||
|
|
}
|
||
|
|
|
||
|
|
private string NormalizeSelectedPath(string selectedPath)
|
||
|
|
{
|
||
|
|
if (PickerMode != PathPickerSelectionMode.Folder || !AppendDirectorySeparator)
|
||
|
|
{
|
||
|
|
return selectedPath;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (string.IsNullOrWhiteSpace(selectedPath))
|
||
|
|
{
|
||
|
|
return string.Empty;
|
||
|
|
}
|
||
|
|
|
||
|
|
return selectedPath.EndsWith(Path.DirectorySeparatorChar)
|
||
|
|
|| selectedPath.EndsWith(Path.AltDirectorySeparatorChar)
|
||
|
|
? selectedPath
|
||
|
|
: selectedPath + Path.DirectorySeparatorChar;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string NormalizeDefaultExtension(string extension)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrWhiteSpace(extension))
|
||
|
|
{
|
||
|
|
return string.Empty;
|
||
|
|
}
|
||
|
|
|
||
|
|
return extension.Trim().TrimStart('.');
|
||
|
|
}
|
||
|
|
}
|