Files
Aaru/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs

829 lines
28 KiB
C#
Raw Normal View History

2020-04-17 21:45:50 +01:00
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : MediaDumpViewModel.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : GUI view models.
//
// --[ Description ] ----------------------------------------------------------
//
// View model and code for the media dump window.
//
// --[ 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/>.
//
// ----------------------------------------------------------------------------
2024-12-19 10:45:18 +00:00
// Copyright © 2011-2025 Natalia Portillo
2020-04-17 21:45:50 +01:00
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
2025-08-20 21:19:43 +01:00
using System.Windows.Input;
using System.Xml.Serialization;
using Aaru.CommonTypes;
using Aaru.CommonTypes.AaruMetadata;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Metadata;
using Aaru.Core;
using Aaru.Core.Devices.Dumping;
using Aaru.Core.Logging;
using Aaru.Core.Media.Info;
using Aaru.Devices;
using Aaru.Gui.Models;
using Aaru.Localization;
using Aaru.Logging;
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
2025-08-20 21:19:43 +01:00
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
2020-07-22 13:20:25 +01:00
using JetBrains.Annotations;
2023-09-26 01:29:07 +01:00
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
2025-08-20 18:51:05 +01:00
using Sentry;
using DeviceInfo = Aaru.Core.Devices.Info.DeviceInfo;
using Dump = Aaru.Core.Devices.Dumping.Dump;
using File = System.IO.File;
using MediaType = Aaru.CommonTypes.MediaType;
namespace Aaru.Gui.ViewModels.Windows;
2025-08-20 21:19:43 +01:00
public sealed partial class MediaDumpViewModel : ViewModelBase
{
2025-08-20 21:19:43 +01:00
readonly string _devicePath;
readonly Window _view;
[ObservableProperty]
bool _closeVisible;
[ObservableProperty]
string _destination;
[ObservableProperty]
bool _destinationEnabled;
[ObservableProperty]
Device _dev;
[ObservableProperty]
Dump _dumper;
[ObservableProperty]
string _encodingEnabled;
[ObservableProperty]
bool _encodingVisible;
bool _existingMetadata;
[ObservableProperty]
bool _force;
[ObservableProperty]
string _formatReadOnly;
[ObservableProperty]
string _log;
[ObservableProperty]
bool _optionsVisible;
[ObservableProperty]
string _outputPrefix;
[ObservableProperty]
bool _persistent;
[ObservableProperty]
bool _progress1Visible;
[ObservableProperty]
bool _progress2Indeterminate;
[ObservableProperty]
double _progress2MaxValue;
[ObservableProperty]
string _progress2Text;
[ObservableProperty]
double _progress2Value;
[ObservableProperty]
bool _progress2Visible;
[ObservableProperty]
bool _progressIndeterminate;
[ObservableProperty]
double _progressMaxValue;
[ObservableProperty]
string _progressText;
[ObservableProperty]
double _progressValue;
[ObservableProperty]
bool _progressVisible;
Resume _resume;
[ObservableProperty]
double _retries;
[ObservableProperty]
EncodingModel _selectedEncoding;
2022-03-06 13:29:38 +00:00
ImagePluginModel _selectedPlugin;
2025-08-20 21:19:43 +01:00
[ObservableProperty]
Metadata _sidecar;
[ObservableProperty]
double _skipped;
[ObservableProperty]
bool _startVisible;
[ObservableProperty]
bool _stopEnabled;
[ObservableProperty]
bool _stopOnError;
[ObservableProperty]
bool _stopVisible;
[ObservableProperty]
bool _track1Pregap;
[ObservableProperty]
bool _track1PregapVisible;
[ObservableProperty]
bool _trim;
bool _useResume;
[ObservableProperty]
bool _useSidecar;
2022-03-06 13:29:38 +00:00
2023-10-03 23:27:57 +01:00
public MediaDumpViewModel(string devicePath, DeviceInfo deviceInfo, Window view,
2022-03-06 13:29:38 +00:00
[CanBeNull] ScsiInfo scsiInfo = null)
{
_view = view;
DestinationEnabled = true;
StartVisible = true;
CloseVisible = true;
OptionsVisible = true;
2025-08-20 21:19:43 +01:00
StartCommand = new RelayCommand(Start);
CloseCommand = new RelayCommand(Close);
StopCommand = new RelayCommand(Stop);
DestinationCommand = new AsyncRelayCommand(DestinationAsync);
2024-05-01 04:39:38 +01:00
PluginsList = [];
Encodings = [];
2022-03-06 13:29:38 +00:00
// Defaults
StopOnError = false;
Force = false;
Persistent = true;
Resume = true;
Track1Pregap = false;
2025-08-20 21:19:43 +01:00
UseSidecar = true;
2022-03-06 13:29:38 +00:00
Trim = true;
ExistingMetadata = false;
Retries = 5;
Skipped = 512;
MediaType mediaType;
if(scsiInfo != null)
mediaType = scsiInfo.MediaType;
else
2023-10-03 23:27:57 +01:00
{
2022-03-06 13:29:38 +00:00
switch(deviceInfo.Type)
{
case DeviceType.SecureDigital:
mediaType = MediaType.SecureDigital;
2022-03-06 13:29:38 +00:00
break;
case DeviceType.MMC:
mediaType = MediaType.MMC;
2022-03-06 13:29:38 +00:00
break;
default:
if(deviceInfo.IsPcmcia)
mediaType = MediaType.PCCardTypeII;
else if(deviceInfo.IsCompactFlash)
mediaType = MediaType.CompactFlash;
else
mediaType = MediaType.GENERIC_HDD;
2022-03-06 13:29:38 +00:00
break;
}
2023-10-03 23:27:57 +01:00
}
PluginRegister plugins = PluginRegister.Singleton;
foreach(IWritableImage plugin in plugins.WritableImages.Values)
{
2024-05-01 04:05:22 +01:00
if(plugin is null) continue;
if(plugin.SupportedMediaTypes.Contains(mediaType))
2023-10-03 23:27:57 +01:00
{
PluginsList.Add(new ImagePluginModel
{
Plugin = plugin
});
2023-10-03 23:27:57 +01:00
}
}
2025-08-20 21:19:43 +01:00
foreach(EncodingModel model in Encoding.GetEncodings()
.Select(info => new EncodingModel
{
Name = info.Name,
DisplayName = info.GetEncoding().EncodingName
})
.Concat(Claunia.Encoding.Encoding.GetEncodings()
.Select(info => new EncodingModel
{
Name = info.Name,
DisplayName = info.DisplayName
}))
.AsParallel()
.OrderBy(m => m.DisplayName))
Encodings.Add(model);
2022-03-06 13:29:38 +00:00
Track1PregapVisible = mediaType switch
{
MediaType.CD
or MediaType.CDDA
or MediaType.CDG
or MediaType.CDEG
or MediaType.CDI
or MediaType.CDROM
or MediaType.CDROMXA
or MediaType.CDPLUS
or MediaType.CDMO
or MediaType.CDR
or MediaType.CDRW
or MediaType.CDMRW
or MediaType.VCD
or MediaType.SVCD
or MediaType.PCD
or MediaType.DDCD
or MediaType.DDCDR
or MediaType.DDCDRW
or MediaType.DTSCD
or MediaType.CDMIDI
or MediaType.CDV
or MediaType.CDIREADY
or MediaType.FMTOWNS
or MediaType.PS1CD
or MediaType.PS2CD
or MediaType.MEGACD
or MediaType.SATURNCD
or MediaType.GDROM
or MediaType.GDR
or MediaType.MilCD
or MediaType.SuperCDROM2
or MediaType.JaguarCD
or MediaType.ThreeDO
or MediaType.PCFX
or MediaType.NeoGeoCD
or MediaType.CDTV
or MediaType.CD32
or MediaType.Playdia
or MediaType.Pippin
or MediaType.VideoNow
or MediaType.VideoNowColor
or MediaType.VideoNowXp
or MediaType.CVD => true,
_ => false
};
2022-03-06 13:29:38 +00:00
_devicePath = devicePath;
}
2025-08-20 21:19:43 +01:00
public ICommand StartCommand { get; }
public ICommand CloseCommand { get; }
public ICommand StopCommand { get; }
public ICommand DestinationCommand { get; }
2022-03-06 13:29:38 +00:00
public ObservableCollection<ImagePluginModel> PluginsList { get; }
public ObservableCollection<EncodingModel> Encodings { get; }
2022-03-06 13:29:38 +00:00
public string Title { get; }
2022-03-06 13:29:38 +00:00
public ImagePluginModel SelectedPlugin
{
get => _selectedPlugin;
set
{
2025-08-20 21:19:43 +01:00
SetProperty(ref _selectedPlugin, value);
2022-03-06 13:29:38 +00:00
Destination = "";
2022-03-06 13:29:38 +00:00
if(value is null)
{
DestinationEnabled = false;
2022-03-06 13:29:38 +00:00
return;
}
2022-03-06 13:29:38 +00:00
DestinationEnabled = true;
2022-03-06 13:29:38 +00:00
if(!value.Plugin.SupportedOptions.Any())
{
2022-03-06 13:29:38 +00:00
// Hide options
}
2022-03-06 13:29:38 +00:00
/* TODO: Plugin options
grpOptions.Visible = true;
2022-03-06 13:29:38 +00:00
var stkOptions = new StackLayout
{
Orientation = Orientation.Vertical
};
foreach((string name, Type type, string description, object @default) option in plugin.SupportedOptions)
switch(option.type.ToString())
{
2022-03-06 13:29:38 +00:00
case "System.Boolean":
var optBoolean = new CheckBox();
optBoolean.ID = "opt" + option.name;
optBoolean.Text = option.description;
optBoolean.Checked = (bool)option.@default;
stkOptions.Items.Add(optBoolean);
2022-03-06 13:29:38 +00:00
break;
case "System.SByte":
case "System.Int16":
case "System.Int32":
case "System.Int64":
var stkNumber = new StackLayout();
stkNumber.Orientation = Orientation.Horizontal;
var optNumber = new NumericStepper();
optNumber.ID = "opt" + option.name;
optNumber.Value = Convert.ToDouble(option.@default);
stkNumber.Items.Add(optNumber);
var lblNumber = new Label();
lblNumber.Text = option.description;
stkNumber.Items.Add(lblNumber);
stkOptions.Items.Add(stkNumber);
2022-03-06 13:29:38 +00:00
break;
case "System.Byte":
case "System.UInt16":
case "System.UInt32":
case "System.UInt64":
var stkUnsigned = new StackLayout();
stkUnsigned.Orientation = Orientation.Horizontal;
var optUnsigned = new NumericStepper();
optUnsigned.ID = "opt" + option.name;
optUnsigned.MinValue = 0;
optUnsigned.Value = Convert.ToDouble(option.@default);
stkUnsigned.Items.Add(optUnsigned);
var lblUnsigned = new Label();
lblUnsigned.Text = option.description;
stkUnsigned.Items.Add(lblUnsigned);
stkOptions.Items.Add(stkUnsigned);
2022-03-06 13:29:38 +00:00
break;
case "System.Single":
case "System.Double":
var stkFloat = new StackLayout();
stkFloat.Orientation = Orientation.Horizontal;
var optFloat = new NumericStepper();
optFloat.ID = "opt" + option.name;
optFloat.DecimalPlaces = 2;
optFloat.Value = Convert.ToDouble(option.@default);
stkFloat.Items.Add(optFloat);
var lblFloat = new Label();
lblFloat.Text = option.description;
stkFloat.Items.Add(lblFloat);
stkOptions.Items.Add(stkFloat);
2022-03-06 13:29:38 +00:00
break;
case "System.Guid":
// TODO
break;
case "System.String":
var stkString = new StackLayout();
stkString.Orientation = Orientation.Horizontal;
var lblString = new Label();
lblString.Text = option.description;
stkString.Items.Add(lblString);
var optString = new TextBox();
optString.ID = "opt" + option.name;
optString.Text = (string)option.@default;
stkString.Items.Add(optString);
stkOptions.Items.Add(stkString);
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
grpOptions.Content = stkOptions;
*/
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
public bool Resume
{
get => _useResume;
set
{
2025-08-20 21:19:43 +01:00
SetProperty(ref _useResume, value);
2022-03-06 13:29:38 +00:00
2024-05-01 04:05:22 +01:00
if(!value) return;
2022-03-06 13:29:38 +00:00
2025-08-20 21:19:43 +01:00
if(_outputPrefix != null) CheckResumeFileAsync().GetAwaiter().GetResult();
}
2022-03-06 13:29:38 +00:00
}
public bool ExistingMetadata
{
get => _existingMetadata;
set
{
2025-08-20 21:19:43 +01:00
SetProperty(ref _existingMetadata, value);
if(!value)
2022-03-06 13:29:38 +00:00
{
_sidecar = null;
2022-03-06 13:29:38 +00:00
return;
}
IReadOnlyList<IStorageFile> result = _view.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = UI.Dialog_Choose_existing_metadata_sidecar,
AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>
{
FilePickerFileTypes.AaruMetadata
}
})
.Result;
if(result.Count != 1)
{
2022-03-06 13:29:38 +00:00
ExistingMetadata = false;
return;
}
2022-03-06 13:29:38 +00:00
try
{
var fs = new FileStream(result[0].Path.AbsolutePath, FileMode.Open);
_sidecar =
2024-05-01 04:05:22 +01:00
(JsonSerializer.Deserialize(fs, typeof(MetadataJson), MetadataJsonContext.Default) as MetadataJson)
?.AaruMetadata;
fs.Close();
2022-03-06 13:29:38 +00:00
}
2025-08-20 18:51:05 +01:00
catch(Exception ex)
2022-03-06 13:29:38 +00:00
{
2025-08-20 18:51:05 +01:00
SentrySdk.CaptureException(ex);
2022-03-06 13:29:38 +00:00
// ReSharper disable AssignmentIsFullyDiscarded
_ = MessageBoxManager.
// ReSharper restore AssignmentIsFullyDiscarded
2024-05-01 04:05:22 +01:00
GetMessageBoxStandard(UI.Title_Error, UI.Incorrect_metadata_sidecar_file, ButtonEnum.Ok, Icon.Error)
.ShowWindowDialogAsync(_view)
.Result;
2022-03-06 13:29:38 +00:00
ExistingMetadata = false;
}
}
2022-03-06 13:29:38 +00:00
}
2025-08-20 21:19:43 +01:00
async Task DestinationAsync()
2022-03-06 13:29:38 +00:00
{
2024-05-01 04:05:22 +01:00
if(SelectedPlugin is null) return;
IStorageFile result = await _view.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
{
Title = UI.Dialog_Choose_destination_file,
FileTypeChoices = new List<FilePickerFileType>
{
new(SelectedPlugin.Plugin.Name)
{
Patterns = SelectedPlugin.Plugin.KnownExtensions.ToList()
}
}
2022-03-06 13:29:38 +00:00
});
2022-03-06 13:29:38 +00:00
if(result is null)
{
2022-03-06 13:29:38 +00:00
Destination = "";
_outputPrefix = null;
2022-03-06 13:29:38 +00:00
return;
}
Destination = result.Path.AbsolutePath;
_outputPrefix = Path.Combine(Path.GetDirectoryName(Destination) ?? "",
Path.GetFileNameWithoutExtension(Destination));
if(string.IsNullOrEmpty(Path.GetExtension(Destination)))
Destination += SelectedPlugin.Plugin.KnownExtensions.First();
2022-03-06 13:29:38 +00:00
Resume = true;
}
2025-08-20 21:19:43 +01:00
async Task CheckResumeFileAsync()
2022-03-06 13:29:38 +00:00
{
_resume = null;
2022-03-06 13:29:38 +00:00
try
{
if(File.Exists(_outputPrefix + ".resume.json"))
{
var fs = new FileStream(_outputPrefix + ".resume.json", FileMode.Open);
_resume =
(await JsonSerializer.DeserializeAsync(fs, typeof(ResumeJson), ResumeJsonContext.Default) as
ResumeJson)?.Resume;
fs.Close();
}
// DEPRECATED: To be removed in Aaru 7
else if(File.Exists(_outputPrefix + ".resume.xml"))
{
// Should be covered by virtue of being the same exact class as the JSON above
2024-05-01 04:05:22 +01:00
#pragma warning disable IL2026
var xs = new XmlSerializer(typeof(Resume));
2024-05-01 04:05:22 +01:00
#pragma warning restore IL2026
var sr = new StreamReader(_outputPrefix + ".resume.xml");
// Should be covered by virtue of being the same exact class as the JSON above
2024-05-01 04:05:22 +01:00
#pragma warning disable IL2026
_resume = (Resume)xs.Deserialize(sr);
2024-05-01 04:05:22 +01:00
#pragma warning restore IL2026
sr.Close();
}
}
2025-08-20 18:51:05 +01:00
catch(Exception ex)
{
2025-08-20 18:51:05 +01:00
SentrySdk.CaptureException(ex);
2024-05-01 04:05:22 +01:00
await MessageBoxManager
.GetMessageBoxStandard(UI.Title_Error,
UI.Incorrect_resume_file_cannot_use_it,
ButtonEnum.Ok,
Icon.Error)
.ShowWindowDialogAsync(_view);
2022-03-06 13:29:38 +00:00
Resume = false;
2022-03-06 13:29:38 +00:00
return;
}
if(_resume == null || _resume.NextBlock <= _resume.LastBlock || _resume.BadBlocks.Count != 0 && !_resume.Tape)
2022-03-06 13:29:38 +00:00
return;
2024-05-01 04:05:22 +01:00
await MessageBoxManager
.GetMessageBoxStandard(UI.Title_Warning,
UI.Media_already_dumped_correctly_please_choose_another_destination,
ButtonEnum.Ok,
Icon.Warning)
.ShowWindowDialogAsync(_view);
2022-03-06 13:29:38 +00:00
Resume = false;
}
2025-08-20 21:19:43 +01:00
void Close() => _view.Close();
2025-08-20 21:19:43 +01:00
internal void Stop()
2022-03-06 13:29:38 +00:00
{
StopEnabled = false;
_dumper?.Abort();
}
2025-08-20 21:19:43 +01:00
void Start()
2022-03-06 13:29:38 +00:00
{
Log = "";
CloseVisible = false;
StartVisible = false;
StopVisible = true;
StopEnabled = true;
ProgressVisible = true;
DestinationEnabled = false;
OptionsVisible = false;
UpdateStatus(UI.Opening_device);
_dev = Device.Create(_devicePath, out ErrorNumber devErrno);
switch(_dev)
{
case null:
StoppingErrorMessage(string.Format(UI.Error_0_opening_device, devErrno));
return;
case Devices.Remote.Device remoteDev:
2024-05-01 04:05:22 +01:00
Statistics.AddRemote(remoteDev.RemoteApplication,
remoteDev.RemoteVersion,
remoteDev.RemoteOperatingSystem,
remoteDev.RemoteOperatingSystemVersion,
remoteDev.RemoteArchitecture);
break;
2022-03-06 13:29:38 +00:00
}
if(_dev.Error)
2022-03-06 13:29:38 +00:00
{
StoppingErrorMessage(string.Format(UI.Error_0_opening_device, _dev.LastError));
2022-03-06 13:29:38 +00:00
return;
}
2022-03-06 13:29:38 +00:00
Statistics.AddDevice(_dev);
Statistics.AddCommand("dump-media");
2022-03-06 13:29:38 +00:00
if(SelectedPlugin is null)
{
StoppingErrorMessage(UI.Cannot_open_output_plugin);
2022-03-06 13:29:38 +00:00
return;
}
2022-03-06 13:29:38 +00:00
Encoding encoding = null;
2022-11-14 01:20:28 +00:00
if(SelectedEncoding is not null)
2023-10-03 23:27:57 +01:00
{
try
{
2022-03-06 13:29:38 +00:00
encoding = Claunia.Encoding.Encoding.GetEncoding(SelectedEncoding.Name);
}
2022-03-06 13:29:38 +00:00
catch(ArgumentException)
{
StoppingErrorMessage(UI.Specified_encoding_is_not_supported);
return;
}
2023-10-03 23:27:57 +01:00
}
Dictionary<string, string> parsedOptions = new();
2022-03-06 13:29:38 +00:00
/* TODO: Options
if(grpOptions.Content is StackLayout stkFormatOptions)
foreach(Control option in stkFormatOptions.Children)
{
2022-03-06 13:29:38 +00:00
string value;
2022-03-06 13:29:38 +00:00
switch(option)
{
2022-03-06 13:29:38 +00:00
case CheckBox optBoolean:
value = optBoolean.Checked?.ToString();
2022-03-06 13:29:38 +00:00
break;
case NumericStepper optNumber:
value = optNumber.Value.ToString(CultureInfo.CurrentCulture);
2022-03-06 13:29:38 +00:00
break;
case TextBox optString:
value = optString.Text;
2022-03-06 13:29:38 +00:00
break;
default: continue;
}
2022-03-06 13:29:38 +00:00
string key = option.ID.Substring(3);
2022-03-06 13:29:38 +00:00
parsedOptions.Add(key, value);
}
*/
2025-08-19 15:55:44 +01:00
DeviceLog.StartLog(_dev, false);
AaruLogging.WriteLine(UI.Output_image_format_0, SelectedPlugin.Name);
2022-03-06 13:29:38 +00:00
var errorLog = new ErrorLog(_outputPrefix + ".error.log");
2024-05-01 04:05:22 +01:00
_dumper = new Dump(Resume,
_dev,
_devicePath,
SelectedPlugin.Plugin,
(ushort)Retries,
Force,
false,
Persistent,
StopOnError,
_resume,
encoding,
_outputPrefix,
Destination,
parsedOptions,
_sidecar,
(uint)Skipped,
!ExistingMetadata,
!Trim,
2024-05-01 04:05:22 +01:00
Track1Pregap,
true,
false,
DumpSubchannel.Any,
0,
false,
false,
false,
false,
false,
true,
errorLog,
false,
64,
true,
true,
false,
10,
true,
1080);
2022-03-06 13:29:38 +00:00
new Thread(DoWork).Start();
}
2020-07-13 18:54:41 +01:00
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
async void DoWork()
2022-03-06 13:29:38 +00:00
{
_dumper.UpdateStatus += UpdateStatus;
_dumper.ErrorMessage += ErrorMessage;
_dumper.StoppingErrorMessage += StoppingErrorMessage;
_dumper.PulseProgress += PulseProgress;
_dumper.InitProgress += InitProgress;
_dumper.UpdateProgress += UpdateProgress;
_dumper.EndProgress += EndProgress;
_dumper.InitProgress2 += InitProgress2;
_dumper.UpdateProgress2 += UpdateProgress2;
_dumper.EndProgress2 += EndProgress2;
_dumper.Start();
_dev.Close();
2025-08-20 21:19:43 +01:00
await WorkFinishedAsync();
2022-03-06 13:29:38 +00:00
}
2025-08-20 21:19:43 +01:00
async Task WorkFinishedAsync() => await Dispatcher.UIThread.InvokeAsync(() =>
2022-03-06 13:29:38 +00:00
{
CloseVisible = true;
StopVisible = false;
Progress1Visible = false;
Progress2Visible = false;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void EndProgress2() => await Dispatcher.UIThread.InvokeAsync(() => { Progress2Visible = false; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-07 07:36:44 +00:00
async void UpdateProgress2(string text, long current, long maximum) => await Dispatcher.UIThread.InvokeAsync(() =>
{
Progress2Text = text;
Progress2Indeterminate = false;
2022-03-07 07:36:44 +00:00
Progress2MaxValue = maximum;
Progress2Value = current;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void InitProgress2() => await Dispatcher.UIThread.InvokeAsync(() => { Progress2Visible = true; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void EndProgress() => await Dispatcher.UIThread.InvokeAsync(() => { Progress1Visible = false; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-07 07:36:44 +00:00
async void UpdateProgress(string text, long current, long maximum) => await Dispatcher.UIThread.InvokeAsync(() =>
{
ProgressText = text;
ProgressIndeterminate = false;
2022-03-07 07:36:44 +00:00
ProgressMaxValue = maximum;
ProgressValue = current;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void InitProgress() => await Dispatcher.UIThread.InvokeAsync(() => { Progress1Visible = true; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void PulseProgress(string text) => await Dispatcher.UIThread.InvokeAsync(() =>
{
ProgressText = text;
ProgressIndeterminate = true;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void StoppingErrorMessage(string text) => await Dispatcher.UIThread.InvokeAsync(async () =>
{
ErrorMessage(text);
2024-05-01 04:05:22 +01:00
await MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, $"{text}", ButtonEnum.Ok, Icon.Error)
.ShowWindowDialogAsync(_view);
2025-08-20 21:19:43 +01:00
await WorkFinishedAsync();
2022-03-06 13:29:38 +00:00
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void ErrorMessage(string text) => await Dispatcher.UIThread.InvokeAsync(() =>
{
Log += text + Environment.NewLine;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void UpdateStatus(string text) => await Dispatcher.UIThread.InvokeAsync(() =>
{
Log += text + Environment.NewLine;
});
}