Files
Aaru/Aaru.Tui/ViewModels/Windows/ImageWindowViewModel.cs

270 lines
9.0 KiB
C#
Raw Normal View History

2025-10-16 16:39:31 +01:00
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Text User Interface.
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2025 Natalia Portillo
// ****************************************************************************/
2025-10-16 11:43:03 +01:00
using System.Collections.ObjectModel;
using System.Text;
2025-10-16 11:03:35 +01:00
using System.Windows.Input;
2025-10-16 11:43:03 +01:00
using Aaru.CommonTypes;
2025-10-16 11:03:35 +01:00
using Aaru.CommonTypes.Interfaces;
2025-10-16 11:43:03 +01:00
using Aaru.Tui.Models;
2025-11-18 04:47:22 +00:00
using Aaru.Tui.ViewModels.Dialogs;
using Aaru.Tui.Views.Dialogs;
2025-11-18 04:36:49 +00:00
using Aaru.Tui.Views.Windows;
2025-10-16 11:03:35 +01:00
using Avalonia;
2025-11-18 04:47:22 +00:00
using Avalonia.Controls;
2025-10-16 11:03:35 +01:00
using Avalonia.Controls.ApplicationLifetimes;
2025-10-16 11:43:03 +01:00
using CommunityToolkit.Mvvm.ComponentModel;
2025-10-16 11:03:35 +01:00
using CommunityToolkit.Mvvm.Input;
using Humanizer;
2025-11-18 04:47:22 +00:00
using Prism.DryIoc;
using Partition = Aaru.CommonTypes.Partition;
2025-10-16 11:03:35 +01:00
namespace Aaru.Tui.ViewModels.Windows;
public sealed partial class ImageWindowViewModel : ViewModelBase
{
2025-11-18 04:36:49 +00:00
readonly IRegionManager _regionManager;
2025-10-16 11:43:03 +01:00
[ObservableProperty]
2025-10-16 12:06:45 +01:00
public string _filePath;
[ObservableProperty]
string _filesystemInformation;
2025-11-18 04:36:49 +00:00
IMediaImage _imageFormat;
[ObservableProperty]
bool _isFilesystemInformationVisible;
[ObservableProperty]
bool _isPartitionInformationVisible;
[ObservableProperty]
2025-10-16 11:43:03 +01:00
bool _isStatusVisible;
[ObservableProperty]
ObservableCollection<FileSystemModelNode> _nodes;
[ObservableProperty]
string _partitionDescription;
[ObservableProperty]
string _partitionLength;
[ObservableProperty]
string _partitionName;
[ObservableProperty]
string _partitionOffset;
[ObservableProperty]
string _partitionScheme;
[ObservableProperty]
string _partitionSequence;
[ObservableProperty]
string _partitionSize;
[ObservableProperty]
string _partitionStart;
[ObservableProperty]
string _partitionType;
[ObservableProperty]
2025-10-16 11:43:03 +01:00
string? _status;
2025-10-16 11:03:35 +01:00
2025-11-18 04:36:49 +00:00
public ImageWindowViewModel(IRegionManager regionManager)
2025-10-16 11:03:35 +01:00
{
2025-11-18 04:36:49 +00:00
_regionManager = regionManager;
ExitCommand = new RelayCommand(Exit);
BackCommand = new RelayCommand(Back);
HelpCommand = new AsyncRelayCommand(HelpAsync);
2025-10-16 11:03:35 +01:00
}
public FileSystemModelNode? SelectedNode
{
get;
set
{
SetProperty(ref field, value);
if(field is null) return;
if(field.Partition is not null && field.Filesystem is null)
{
IsPartitionInformationVisible = true;
PartitionSequence = field.Partition.Value.Sequence.ToString();
PartitionName = field.Partition.Value.Name;
PartitionType = field.Partition.Value.Type;
PartitionStart = field.Partition.Value.Start.ToString();
PartitionOffset = ByteSize.FromBytes(field.Partition.Value.Offset).Humanize();
2025-10-18 13:36:08 +01:00
PartitionLength = string.Format(Localization.Resources._0_sectors, field.Partition.Value.Length);
2025-10-18 13:36:08 +01:00
PartitionSize = ByteSize.FromBytes(field.Partition.Value.Size).Humanize();
PartitionScheme = field.Partition.Value.Scheme;
PartitionDescription = field.Partition.Value.Description;
OnPropertyChanged(nameof(PartitionSequence));
OnPropertyChanged(nameof(PartitionName));
OnPropertyChanged(nameof(PartitionType));
OnPropertyChanged(nameof(PartitionStart));
OnPropertyChanged(nameof(PartitionOffset));
OnPropertyChanged(nameof(PartitionLength));
OnPropertyChanged(nameof(PartitionSize));
OnPropertyChanged(nameof(PartitionScheme));
OnPropertyChanged(nameof(PartitionDescription));
}
else
IsPartitionInformationVisible = false;
if(field.Filesystem is not null)
{
IsFilesystemInformationVisible = true;
FilesystemInformation = field.FilesystemInformation ?? "";
OnPropertyChanged(nameof(FilesystemInformation));
}
else
IsFilesystemInformationVisible = false;
OnPropertyChanged(nameof(IsPartitionInformationVisible));
OnPropertyChanged(nameof(IsFilesystemInformationVisible));
}
}
public ICommand BackCommand { get; }
public ICommand HelpCommand { get; }
public ICommand ExitCommand { get; }
2025-10-16 11:03:35 +01:00
void Back()
{
2025-11-18 04:36:49 +00:00
IRegion? region = _regionManager.Regions["ContentRegion"];
IRegionNavigationService? navigationService = region.NavigationService;
if(navigationService?.Journal.CanGoBack == true)
navigationService.Journal.GoBack();
else
{
// No history - navigate directly to FileView
_regionManager.RequestNavigate("ContentRegion", nameof(FileView));
}
2025-10-16 11:03:35 +01:00
}
void Exit()
{
var lifetime = Application.Current!.ApplicationLifetime as IControlledApplicationLifetime;
lifetime!.Shutdown();
}
2025-10-16 11:43:03 +01:00
2025-11-18 04:36:49 +00:00
/// <inheritdoc />
public override void OnNavigatedTo(NavigationContext navigationContext)
2025-10-16 11:43:03 +01:00
{
2025-11-18 04:36:49 +00:00
_imageFormat = navigationContext.Parameters.GetValue<IMediaImage>("imageFormat");
FilePath = navigationContext.Parameters.GetValue<string>("filePath");
2025-10-16 11:43:03 +01:00
_ = Task.Run(Worker);
}
2025-11-18 04:47:22 +00:00
Task HelpAsync()
{
AvaloniaObject? view = (Application.Current as PrismApplication)?.MainWindow;
if(view is null) return Task.CompletedTask;
var dialog = new ImageHelpDialog
{
DataContext = new ImageHelpDialogViewModel(null!)
};
// Set the dialog reference after creation
((ImageHelpDialogViewModel)dialog.DataContext!)._dialog = dialog;
2025-11-18 04:47:22 +00:00
return dialog.ShowDialog(view as Window);
}
2025-10-16 11:43:03 +01:00
void Worker()
{
IsStatusVisible = true;
2025-10-18 13:36:08 +01:00
Status = Localization.Resources.Loading_partitions;
2025-10-16 11:43:03 +01:00
2025-10-16 12:06:45 +01:00
Nodes = [];
2025-10-16 11:43:03 +01:00
List<Partition>? partitionsList = Core.Partitions.GetAll(_imageFormat);
if(partitionsList.Count == 0)
{
partitionsList.Add(new Partition
{
2025-10-18 13:36:08 +01:00
Name = Aaru.Localization.Core.Whole_device,
2025-10-16 11:43:03 +01:00
Length = _imageFormat.Info.Sectors,
Size = _imageFormat.Info.Sectors * _imageFormat.Info.SectorSize
});
}
var sequence = 0;
2025-10-18 13:36:08 +01:00
Status = Localization.Resources.Loading_filesystems;
2025-10-16 11:57:23 +01:00
PluginRegister plugins = PluginRegister.Singleton;
2025-10-16 11:43:03 +01:00
foreach(Partition partition in partitionsList)
{
2025-10-18 13:36:08 +01:00
var node = new FileSystemModelNode(partition.Name ??
string.Format(Localization.Resources.Partition_0, sequence))
2025-10-16 11:43:03 +01:00
{
Partition = partition
};
2025-10-16 11:57:23 +01:00
Core.Filesystems.Identify(_imageFormat, out List<string>? idPlugins, partition);
if(idPlugins.Count > 0)
{
var subNodes = new ObservableCollection<FileSystemModelNode>();
foreach(string pluginName in idPlugins)
{
if(!plugins.Filesystems.TryGetValue(pluginName, out IFilesystem? fs)) continue;
if(fs is null) continue;
2025-10-16 12:06:45 +01:00
var fsNode = new FileSystemModelNode(fs.Name)
{
Partition = partition,
2025-10-16 12:06:45 +01:00
Filesystem = fs
};
try
{
fs.GetInformation(_imageFormat, partition, Encoding.ASCII, out string? information, out _);
fsNode.FilesystemInformation = information;
}
catch(Exception ex)
{
SentrySdk.CaptureException(ex);
}
2025-10-16 11:57:23 +01:00
subNodes.Add(fsNode);
}
node.SubNodes = subNodes;
}
2025-10-16 11:43:03 +01:00
Nodes.Add(node);
sequence++;
}
2025-10-18 13:36:08 +01:00
Status = Localization.Resources.Done;
2025-10-16 11:43:03 +01:00
IsStatusVisible = false;
}
2025-10-16 11:03:35 +01:00
}