2025-10-15 21:25:05 +01:00
using System.Collections.ObjectModel ;
using System.Reflection ;
2025-10-16 01:15:13 +01:00
using System.Text ;
2025-10-15 21:25:05 +01:00
using System.Windows.Input ;
2025-10-16 01:15:13 +01:00
using Aaru.CommonTypes ;
using Aaru.CommonTypes.Enums ;
using Aaru.CommonTypes.Interfaces ;
using Aaru.Core ;
2025-10-15 22:05:55 +01:00
using Aaru.Helpers ;
using Aaru.Tui.Models ;
2025-10-15 21:25:05 +01:00
using Avalonia ;
using Avalonia.Controls.ApplicationLifetimes ;
2025-10-15 22:05:55 +01:00
using Avalonia.Media ;
2025-10-15 21:25:05 +01:00
using CommunityToolkit.Mvvm.ComponentModel ;
using CommunityToolkit.Mvvm.Input ;
2025-10-16 01:15:13 +01:00
using Humanizer ;
using Humanizer.Bytes ;
2025-10-15 22:05:55 +01:00
using Color = Avalonia . Media . Color ;
2025-10-15 21:25:05 +01:00
namespace Aaru.Tui.ViewModels.Windows ;
2025-10-15 22:05:55 +01:00
public sealed partial class MainWindowViewModel : ViewModelBase
2025-10-15 21:25:05 +01:00
{
[ObservableProperty]
2025-10-16 00:13:02 +01:00
string _copyright ;
2025-10-15 22:05:55 +01:00
[ObservableProperty]
2025-10-16 00:13:02 +01:00
string _currentPath ;
2025-10-15 22:44:09 +01:00
[ObservableProperty]
2025-10-15 22:05:55 +01:00
ObservableCollection < FileModel > _files = [ ] ;
2025-10-15 21:25:05 +01:00
[ObservableProperty]
2025-10-16 00:13:02 +01:00
string _informationalVersion ;
FileModel ? _selectedFile ;
2025-10-15 21:25:05 +01:00
public MainWindowViewModel ( )
{
2025-10-15 22:54:35 +01:00
ExitCommand = new RelayCommand ( Exit ) ;
OpenSelectedFileCommand = new RelayCommand ( OpenSelectedFile , CanOpenSelectedFile ) ;
2025-10-15 21:25:05 +01:00
InformationalVersion =
Assembly . GetExecutingAssembly ( )
. GetCustomAttribute < AssemblyInformationalVersionAttribute > ( )
? . InformationalVersion ? ?
"?.?.?" ;
2025-10-15 22:05:55 +01:00
Copyright = Assembly . GetExecutingAssembly ( ) . GetCustomAttribute < AssemblyCopyrightAttribute > ( ) ? . Copyright ? ? "" ;
2025-10-15 21:25:05 +01:00
}
2025-10-16 00:13:02 +01:00
public FileModel ? SelectedFile
{
get = > _selectedFile ;
set
{
SetProperty ( ref _selectedFile , value ) ;
OnPropertyChanged ( nameof ( IsFileInfoAvailable ) ) ;
OnPropertyChanged ( nameof ( SelectedFileIsNotDirectory ) ) ;
OnPropertyChanged ( nameof ( SelectedFileLength ) ) ;
OnPropertyChanged ( nameof ( SelectedFileCreationTime ) ) ;
OnPropertyChanged ( nameof ( SelectedFileLastWriteTime ) ) ;
OnPropertyChanged ( nameof ( SelectedFileAttributes ) ) ;
OnPropertyChanged ( nameof ( SelectedFileUnixMode ) ) ;
2025-10-16 01:15:13 +01:00
OnPropertyChanged ( nameof ( SelectedFileHasInformation ) ) ;
OnPropertyChanged ( nameof ( SelectedFileInformation ) ) ;
2025-10-16 00:13:02 +01:00
}
}
2025-10-15 22:54:35 +01:00
2025-10-16 00:13:02 +01:00
public ICommand OpenSelectedFileCommand { get ; }
public ICommand ExitCommand { get ; }
public bool IsFileInfoAvailable = > SelectedFile ? . FileInfo ! = null ;
public bool SelectedFileIsNotDirectory = > SelectedFile ? . IsDirectory = = false ;
public long? SelectedFileLength = > SelectedFile ? . IsDirectory = = false ? SelectedFile ? . FileInfo ? . Length : 0 ;
public DateTime ? SelectedFileCreationTime = > SelectedFile ? . FileInfo ? . CreationTime ;
public DateTime ? SelectedFileLastWriteTime = > SelectedFile ? . FileInfo ? . LastWriteTime ;
public string? SelectedFileAttributes = > SelectedFile ? . FileInfo ? . Attributes . ToString ( ) ;
public string? SelectedFileUnixMode = > SelectedFile ? . FileInfo ? . UnixFileMode . ToString ( ) ;
2025-10-16 01:15:13 +01:00
public bool SelectedFileHasInformation = > SelectedFile ? . Information ! = null ;
public string? SelectedFileInformation = > SelectedFile ? . Information ;
2025-10-15 21:25:05 +01:00
void Exit ( )
{
var lifetime = Application . Current ! . ApplicationLifetime as IControlledApplicationLifetime ;
lifetime ! . Shutdown ( ) ;
}
public void LoadComplete ( )
2025-10-15 22:54:35 +01:00
{
LoadFiles ( ) ;
}
public void LoadFiles ( )
2025-10-15 21:25:05 +01:00
{
2025-10-15 22:44:09 +01:00
CurrentPath = Directory . GetCurrentDirectory ( ) ;
2025-10-15 22:54:35 +01:00
Files . Clear ( ) ;
2025-10-15 22:44:09 +01:00
2025-10-15 22:05:55 +01:00
var parentDirectory = new FileModel
{
Filename = ".." ,
2025-10-15 22:54:35 +01:00
Path = Path . GetRelativePath ( CurrentPath , ".." ) ,
2025-10-15 22:05:55 +01:00
ForegroundBrush =
new SolidColorBrush ( Color . Parse ( DirColorsParser . Instance . DirectoryColor ? ?
2025-10-15 22:54:35 +01:00
DirColorsParser . Instance . NormalColor ) ) ,
IsDirectory = true
2025-10-15 22:05:55 +01:00
} ;
Files . Add ( parentDirectory ) ;
2025-10-15 22:54:35 +01:00
foreach ( FileModel model in Directory . GetDirectories ( CurrentPath , "*" , SearchOption . TopDirectoryOnly )
. Select ( directory = > new FileModel
{
Path = directory ,
Filename = Path . GetFileName ( directory ) ,
ForegroundBrush =
new SolidColorBrush ( Color . Parse ( DirColorsParser . Instance
. DirectoryColor ? ?
DirColorsParser . Instance . NormalColor ) ) ,
IsDirectory = true
} ) )
2025-10-15 22:05:55 +01:00
Files . Add ( model ) ;
2025-10-15 21:25:05 +01:00
2025-10-15 22:54:35 +01:00
foreach ( string file in Directory . GetFiles ( CurrentPath , "*" , SearchOption . TopDirectoryOnly ) )
2025-10-15 22:05:55 +01:00
{
var model = new FileModel
{
Path = file ,
Filename = Path . GetFileName ( file )
} ;
string extension = Path . GetExtension ( file ) ;
model . ForegroundBrush =
new SolidColorBrush ( Color . Parse ( DirColorsParser . Instance . ExtensionColors . TryGetValue ( extension ,
out string? hex )
? hex
: DirColorsParser . Instance . NormalColor ) ) ;
Files . Add ( model ) ;
}
2025-10-16 00:13:02 +01:00
_ = Task . Run ( Worker ) ;
}
void Worker ( )
{
2025-10-16 01:15:13 +01:00
foreach ( FileModel file in Files )
{
try
{
file . FileInfo = new FileInfo ( file . Path ) ;
IFilter inputFilter = PluginRegister . Singleton . GetFilter ( file . Path ) ;
if ( inputFilter is null ) continue ;
IBaseImage imageFormat = ImageFormat . Detect ( inputFilter ) ;
if ( imageFormat is null ) continue ;
StringBuilder sb = new ( ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . Version ) )
sb . AppendLine ( $"Format: {imageFormat.Format} version {imageFormat.Info.Version}" ) ;
else
sb . AppendLine ( $"Format: {imageFormat.Format}" ) ;
switch ( string . IsNullOrWhiteSpace ( imageFormat . Info . Application ) )
{
case false when ! string . IsNullOrWhiteSpace ( imageFormat . Info . ApplicationVersion ) :
sb . AppendLine ( $"Was created with {imageFormat.Info.Application} version {imageFormat.Info.ApplicationVersion}" ) ;
break ;
case false :
sb . AppendLine ( $"Was created with {imageFormat.Info.Application}" ) ;
break ;
}
sb . AppendLine ( $"Image without headers is {imageFormat.Info.ImageSize} bytes long" ) ;
sb . AppendLine ( $"Contains a media of {imageFormat.Info.Sectors} sectors with a maximum sector size of {imageFormat.Info.SectorSize} bytes (if all sectors are of the same size this would be [aqua]{ByteSize.FromBytes(imageFormat.Info.Sectors * imageFormat.Info.SectorSize).Humanize()})" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . Creator ) )
sb . AppendLine ( $"Created by: {imageFormat.Info.Creator}" ) ;
if ( imageFormat . Info . CreationTime ! = DateTime . MinValue )
sb . AppendLine ( $"Created on {imageFormat.Info.CreationTime}" ) ;
if ( imageFormat . Info . LastModificationTime ! = DateTime . MinValue )
sb . AppendLine ( $"Last modified on {imageFormat.Info.LastModificationTime}" ) ;
sb . AppendLine ( $"Contains a media of type {imageFormat.Info.MediaType} and XML type {imageFormat.Info.MetadataMediaType}" ) ;
sb . AppendLine ( imageFormat . Info . HasPartitions ? "Has partitions" : "Doesn\'t have partitions" ) ;
sb . AppendLine ( imageFormat . Info . HasSessions ? "Has sessions" : "Doesn\'t have sessions" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . Comments ) )
sb . AppendLine ( $"Comments: {imageFormat.Info.Comments}" ) ;
if ( imageFormat . Info . MediaSequence ! = 0 & & imageFormat . Info . LastMediaSequence ! = 0 )
sb . AppendLine ( $"Media is number {imageFormat.Info.MediaSequence} on a set of {imageFormat.Info.LastMediaSequence} medias" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . MediaTitle ) )
sb . AppendLine ( $"Media title: {imageFormat.Info.MediaTitle}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . MediaManufacturer ) )
sb . AppendLine ( $"Media manufacturer: {imageFormat.Info.MediaManufacturer}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . MediaModel ) )
sb . AppendLine ( $"Media model: {imageFormat.Info.MediaModel}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . MediaSerialNumber ) )
sb . AppendLine ( $"Media serial number: {imageFormat.Info.MediaSerialNumber}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . MediaBarcode ) )
sb . AppendLine ( $"Media barcode: {imageFormat.Info.MediaBarcode}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . MediaPartNumber ) )
sb . AppendLine ( $"Media part number: {imageFormat.Info.MediaPartNumber}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . DriveManufacturer ) )
sb . AppendLine ( $"Drive manufacturer: {imageFormat.Info.DriveManufacturer}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . DriveModel ) )
sb . AppendLine ( $"Drive model: {imageFormat.Info.DriveModel}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . DriveSerialNumber ) )
sb . AppendLine ( $"Drive serial number: {imageFormat.Info.DriveSerialNumber}" ) ;
if ( ! string . IsNullOrWhiteSpace ( imageFormat . Info . DriveFirmwareRevision ) )
sb . AppendLine ( $"Drive firmware info: {imageFormat.Info.DriveFirmwareRevision}" ) ;
if ( imageFormat . Info . Cylinders > 0 & &
imageFormat . Info is { Heads : > 0 , SectorsPerTrack : > 0 } & &
imageFormat . Info . MetadataMediaType ! = MetadataMediaType . OpticalDisc & &
imageFormat is not ITapeImage { IsTape : true } )
sb . AppendLine ( $"Media geometry: {imageFormat.Info.Cylinders} cylinders, {imageFormat.Info.Heads} heads, {imageFormat.Info.SectorsPerTrack} sectors per track" ) ;
if ( imageFormat . Info . ReadableMediaTags is { Count : > 0 } )
{
sb . AppendLine ( $"Contains {imageFormat.Info.ReadableMediaTags.Count} readable media tags:" ) ;
foreach ( MediaTagType tag in imageFormat . Info . ReadableMediaTags . Order ( ) ) sb . Append ( $"{tag} " ) ;
sb . AppendLine ( ) ;
}
if ( imageFormat . Info . ReadableSectorTags is { Count : > 0 } )
{
sb . AppendLine ( $"Contains {imageFormat.Info.ReadableSectorTags.Count} readable sector tags:" ) ;
foreach ( SectorTagType tag in imageFormat . Info . ReadableSectorTags . Order ( ) ) sb . Append ( $"{tag} " ) ;
sb . AppendLine ( ) ;
}
file . Information = sb . ToString ( ) ;
}
catch ( Exception ex )
{
SentrySdk . CaptureException ( ex ) ;
}
}
2025-10-15 21:25:05 +01:00
}
2025-10-15 22:54:35 +01:00
void OpenSelectedFile ( )
{
2025-10-16 00:13:02 +01:00
if ( SelectedFile ? . IsDirectory ! = true ) return ;
2025-10-15 22:54:35 +01:00
CurrentPath = SelectedFile . Path ;
Environment . CurrentDirectory = CurrentPath ;
LoadFiles ( ) ;
}
bool CanOpenSelectedFile ( ) = > SelectedFile ! = null ;
2025-10-15 21:25:05 +01:00
}