Refactor path handling in UI components
- Removed redundant folder and file opening methods from AiTabView and FaceAiTabView. - Introduced PathPickerField control to streamline path selection and opening functionality across multiple views. - Updated FaceAiTabView and GeneralTabView to utilize PathPickerField for source and destination path selection. - Created PathShellService to encapsulate logic for opening paths in the file explorer. - Simplified XAML structure by replacing manual grid definitions with PathPickerField components. - Removed unused namespaces and cleaned up code for better readability and maintainability.
This commit is contained in:
parent
f3ac1ea920
commit
398cfa310e
10 changed files with 484 additions and 562 deletions
|
|
@ -4,15 +4,11 @@ using Avalonia.Input;
|
|||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
using ImageCatalog_2.Models;
|
||||
using ImageCatalog_2.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -22,11 +18,9 @@ namespace ImageCatalog_2.AvaloniaViews;
|
|||
public partial class FaceAiTabView : Avalonia.Controls.UserControl
|
||||
{
|
||||
private INotifyPropertyChanged? _faceAiPropertySource;
|
||||
private readonly PickerPreferenceService _pickerPreferenceService;
|
||||
|
||||
public FaceAiTabView()
|
||||
{
|
||||
_pickerPreferenceService = Program.ServiceProvider.GetRequiredService<PickerPreferenceService>();
|
||||
InitializeComponent();
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
}
|
||||
|
|
@ -74,142 +68,6 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
|
|||
});
|
||||
}
|
||||
|
||||
private async void SelectFaceExecutable_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var currentPath = DataContext is DataModel currentModel ? currentModel.FaceExecutablePath : null;
|
||||
var folders = await OpenFolderPickerAsync("Seleziona la cartella Face Recognition Windows", PickerPreferenceKeys.FaceExecutableFolder, currentPath);
|
||||
if (folders.Count > 0 && DataContext is DataModel model)
|
||||
{
|
||||
model.FaceExecutablePath = folders[0].Path.LocalPath;
|
||||
_pickerPreferenceService.RememberPath(PickerPreferenceKeys.FaceExecutableFolder, model.FaceExecutablePath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectFaceOutputFolder_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var currentPath = DataContext is DataModel currentModel ? currentModel.FaceOutputFolderPath : null;
|
||||
var folders = await OpenFolderPickerAsync("Seleziona la cartella output per encodings e log", PickerPreferenceKeys.FaceOutputFolder, currentPath);
|
||||
if (folders.Count > 0 && DataContext is DataModel model)
|
||||
{
|
||||
model.FaceOutputFolderPath = folders[0].Path.LocalPath;
|
||||
_pickerPreferenceService.RememberPath(PickerPreferenceKeys.FaceOutputFolder, model.FaceOutputFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectFaceMatcherExecutable_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var files = await OpenFilePickerAsync(
|
||||
"Seleziona face_matcher.exe",
|
||||
[new FilePickerFileType("Eseguibile") { Patterns = ["*.exe"] }],
|
||||
PickerPreferenceKeys.FaceMatcherExecutable,
|
||||
DataContext is DataModel currentModel ? currentModel.FaceMatcherExecutablePath : null);
|
||||
|
||||
if (files.Count > 0 && DataContext is DataModel model)
|
||||
{
|
||||
model.FaceMatcherExecutablePath = files[0].Path.LocalPath;
|
||||
_pickerPreferenceService.RememberPath(PickerPreferenceKeys.FaceMatcherExecutable, model.FaceMatcherExecutablePath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectFaceMatcherImage_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var files = await OpenFilePickerAsync(
|
||||
"Seleziona immagine per il match",
|
||||
[new FilePickerFileType("Immagini") { Patterns = ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] }],
|
||||
PickerPreferenceKeys.FaceMatcherImage,
|
||||
DataContext is DataModel currentModel ? currentModel.FaceMatcherSelectedImagePath : null);
|
||||
|
||||
if (files.Count > 0 && DataContext is DataModel model)
|
||||
{
|
||||
model.FaceMatcherSelectedImagePath = files[0].Path.LocalPath;
|
||||
_pickerPreferenceService.RememberPath(PickerPreferenceKeys.FaceMatcherImage, model.FaceMatcherSelectedImagePath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectFaceMatcherEncodings_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var files = await OpenFilePickerAsync(
|
||||
"Seleziona file encodings .pkl",
|
||||
[new FilePickerFileType("Encodings") { Patterns = ["*.pkl"] }],
|
||||
PickerPreferenceKeys.FaceMatcherEncodings,
|
||||
DataContext is DataModel currentModel ? currentModel.FaceMatcherEncodingsPath : null);
|
||||
|
||||
if (files.Count > 0 && DataContext is DataModel model)
|
||||
{
|
||||
model.FaceMatcherEncodingsPath = files[0].Path.LocalPath;
|
||||
_pickerPreferenceService.RememberPath(PickerPreferenceKeys.FaceMatcherEncodings, model.FaceMatcherEncodingsPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectFaceMatcherOutput_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var file = await SaveFilePickerAsync(
|
||||
"Seleziona output CSV del matcher",
|
||||
"csv",
|
||||
[new FilePickerFileType("CSV") { Patterns = ["*.csv"] }],
|
||||
PickerPreferenceKeys.FaceMatcherOutput,
|
||||
DataContext is DataModel currentModel ? currentModel.FaceMatcherOutputPath : null);
|
||||
|
||||
if (file is not null && DataContext is DataModel model)
|
||||
{
|
||||
model.FaceMatcherOutputPath = file.Path.LocalPath;
|
||||
_pickerPreferenceService.RememberPath(PickerPreferenceKeys.FaceMatcherOutput, model.FaceMatcherOutputPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectFaceMatcherLog_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var file = await SaveFilePickerAsync(
|
||||
"Seleziona log TXT del matcher",
|
||||
"txt",
|
||||
[new FilePickerFileType("Log") { Patterns = ["*.txt", "*.log"] }],
|
||||
PickerPreferenceKeys.FaceMatcherLog,
|
||||
DataContext is DataModel currentModel ? currentModel.FaceMatcherLogPath : null);
|
||||
|
||||
if (file is not null && DataContext is DataModel model)
|
||||
{
|
||||
model.FaceMatcherLogPath = file.Path.LocalPath;
|
||||
_pickerPreferenceService.RememberPath(PickerPreferenceKeys.FaceMatcherLog, model.FaceMatcherLogPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenFaceExecutableFolder_Click(object? sender, RoutedEventArgs e) => OpenFromTextBox("FaceExecutablePathTextBox");
|
||||
|
||||
private void OpenFaceOutputFolder_Click(object? sender, RoutedEventArgs e) => OpenFromTextBox("FaceOutputFolderTextBox");
|
||||
|
||||
private void OpenFaceMatcherExecutable_Click(object? sender, RoutedEventArgs e) => OpenFromTextBox("FaceMatcherExecutablePathTextBox");
|
||||
|
||||
private void OpenFaceMatcherImage_Click(object? sender, RoutedEventArgs e) => OpenFromTextBox("FaceMatcherImagePathTextBox");
|
||||
|
||||
private void OpenFaceMatcherEncodings_Click(object? sender, RoutedEventArgs e) => OpenFromTextBox("FaceMatcherEncodingsPathTextBox");
|
||||
|
||||
private void OpenFaceMatcherOutput_Click(object? sender, RoutedEventArgs e) => OpenFromTextBox("FaceMatcherOutputPathTextBox");
|
||||
|
||||
private void OpenFaceMatcherLog_Click(object? sender, RoutedEventArgs e) => OpenFromTextBox("FaceMatcherLogPathTextBox");
|
||||
|
||||
private void OpenFaceDestinationFolder_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
string? path = null;
|
||||
if (DataContext is DataModel model)
|
||||
{
|
||||
path = (model.DestinationPath ?? string.Empty).Trim();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
OpenInExplorer(path);
|
||||
return;
|
||||
}
|
||||
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? path : directory);
|
||||
}
|
||||
|
||||
private async void OpenFaceMatcherPreview_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Button { Tag: FaceMatcherResultItem item })
|
||||
|
|
@ -444,14 +302,14 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
|
|||
Grid.SetRow(footer, 2);
|
||||
|
||||
var openFileButton = new Button { Content = "Apri file" };
|
||||
openFileButton.Click += (_, _) => OpenInExplorer(item.ResolvedImagePath);
|
||||
openFileButton.Click += (_, _) => PathShellService.OpenInExplorer(item.ResolvedImagePath);
|
||||
footer.Children.Add(openFileButton);
|
||||
|
||||
var openFolderButton = new Button { Content = "Apri cartella" };
|
||||
openFolderButton.Click += (_, _) =>
|
||||
{
|
||||
var directory = Path.GetDirectoryName(item.ResolvedImagePath);
|
||||
OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? item.ResolvedImagePath : directory);
|
||||
PathShellService.OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? item.ResolvedImagePath : directory);
|
||||
};
|
||||
footer.Children.Add(openFolderButton);
|
||||
|
||||
|
|
@ -464,104 +322,4 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
|
|||
return dialog;
|
||||
}
|
||||
|
||||
private void OpenFromTextBox(string textBoxName)
|
||||
{
|
||||
var textBox = this.FindControl<Avalonia.Controls.TextBox>(textBoxName);
|
||||
var path = textBox?.Text?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Directory.Exists(path) || File.Exists(path))
|
||||
{
|
||||
OpenInExplorer(path);
|
||||
return;
|
||||
}
|
||||
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? path : directory);
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(string title, string preferenceKey, string? currentPath)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
var storageProvider = topLevel?.StorageProvider;
|
||||
if (storageProvider is null)
|
||||
{
|
||||
return Array.Empty<IStorageFolder>();
|
||||
}
|
||||
|
||||
var suggestedStartLocation = await _pickerPreferenceService.TryGetStartFolderAsync(storageProvider, preferenceKey, currentPath);
|
||||
|
||||
return await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = title,
|
||||
SuggestedStartLocation = suggestedStartLocation
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyList<IStorageFile>> OpenFilePickerAsync(string title, IReadOnlyList<FilePickerFileType> fileTypes, string preferenceKey, string? currentPath)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
var storageProvider = topLevel?.StorageProvider;
|
||||
if (storageProvider is null)
|
||||
{
|
||||
return Array.Empty<IStorageFile>();
|
||||
}
|
||||
|
||||
var suggestedStartLocation = await _pickerPreferenceService.TryGetStartFolderAsync(storageProvider, preferenceKey, currentPath);
|
||||
|
||||
return await storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
Title = title,
|
||||
FileTypeFilter = fileTypes,
|
||||
SuggestedStartLocation = suggestedStartLocation
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<IStorageFile?> SaveFilePickerAsync(string title, string defaultExtension, IReadOnlyList<FilePickerFileType> fileTypes, string preferenceKey, string? currentPath)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
var storageProvider = topLevel?.StorageProvider;
|
||||
if (storageProvider is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var suggestedStartLocation = await _pickerPreferenceService.TryGetStartFolderAsync(storageProvider, preferenceKey, currentPath);
|
||||
|
||||
return await storageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
Title = title,
|
||||
DefaultExtension = defaultExtension,
|
||||
FileTypeChoices = fileTypes,
|
||||
SuggestedStartLocation = suggestedStartLocation
|
||||
});
|
||||
}
|
||||
|
||||
private static void OpenInExplorer(string? path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var normalizedPath = path.Trim().Trim('"');
|
||||
try
|
||||
{
|
||||
if (File.Exists(normalizedPath))
|
||||
{
|
||||
Process.Start("explorer.exe", $"/select,\"{normalizedPath}\"");
|
||||
}
|
||||
else if (Directory.Exists(normalizedPath))
|
||||
{
|
||||
Process.Start(new ProcessStartInfo { FileName = normalizedPath, UseShellExecute = true });
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore failures when opening Explorer.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue