[GUI] Add block map to media scan.

This commit is contained in:
2025-11-20 01:27:38 +00:00
parent 17dc7423c2
commit 92bbdaaab6
2 changed files with 88 additions and 46 deletions

View File

@@ -30,8 +30,10 @@
// Copyright © 2011-2025 Natalia Portillo // Copyright © 2011-2025 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
@@ -40,7 +42,6 @@ using Aaru.Core.Devices.Scanning;
using Aaru.Devices; using Aaru.Devices;
using Aaru.Localization; using Aaru.Localization;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
@@ -56,17 +57,20 @@ namespace Aaru.Gui.ViewModels.Windows;
public sealed partial class MediaScanViewModel : ViewModelBase public sealed partial class MediaScanViewModel : ViewModelBase
{ {
readonly Device _device; readonly Device _device;
readonly Window _view; readonly string _devicePath;
readonly List<(ulong startingSector, double duration)> _pendingSectorData = new();
readonly object _pendingSectorDataLock = new();
readonly Window _view;
[ObservableProperty] [ObservableProperty]
string _a; string _a;
[ObservableProperty] [ObservableProperty]
string _avgSpeed; string _avgSpeed;
[ObservableProperty] [ObservableProperty]
Color _axesColor;
[ObservableProperty]
string _b; string _b;
[ObservableProperty] [ObservableProperty]
ObservableCollection<(ulong startingSector, double duration)> _blockMapSectorData;
[ObservableProperty]
ulong _blocks; ulong _blocks;
ulong _blocksToRead; ulong _blocksToRead;
[ObservableProperty] [ObservableProperty]
@@ -75,13 +79,10 @@ public sealed partial class MediaScanViewModel : ViewModelBase
bool _closeVisible; bool _closeVisible;
[ObservableProperty] [ObservableProperty]
string _d; string _d;
readonly string _devicePath;
[ObservableProperty] [ObservableProperty]
string _e; string _e;
[ObservableProperty] [ObservableProperty]
string _f; string _f;
[ObservableProperty]
Color _lineColor;
ScanResults _localResults; ScanResults _localResults;
[ObservableProperty] [ObservableProperty]
string _maxSpeed; string _maxSpeed;
@@ -98,16 +99,6 @@ public sealed partial class MediaScanViewModel : ViewModelBase
[ObservableProperty] [ObservableProperty]
bool _progress1Visible; bool _progress1Visible;
[ObservableProperty] [ObservableProperty]
string _progress2Indeterminate;
[ObservableProperty]
string _progress2MaxValue;
[ObservableProperty]
string _progress2Text;
[ObservableProperty]
string _progress2Value;
[ObservableProperty]
string _progress2Visible;
[ObservableProperty]
bool _progressIndeterminate; bool _progressIndeterminate;
[ObservableProperty] [ObservableProperty]
double _progressMaxValue; double _progressMaxValue;
@@ -119,6 +110,8 @@ public sealed partial class MediaScanViewModel : ViewModelBase
bool _progressVisible; bool _progressVisible;
[ObservableProperty] [ObservableProperty]
bool _resultsVisible; bool _resultsVisible;
[ObservableProperty]
uint _scanBlockSize;
MediaScan _scanner; MediaScan _scanner;
[ObservableProperty] [ObservableProperty]
bool _startVisible; bool _startVisible;
@@ -146,23 +139,8 @@ public sealed partial class MediaScanViewModel : ViewModelBase
StopCommand = new RelayCommand(Stop); StopCommand = new RelayCommand(Stop);
StartVisible = true; StartVisible = true;
CloseVisible = true; CloseVisible = true;
BlockMapList = [];
// ChartPoints = new ObservableCollection<DataPoint>();
StepsX = double.NaN;
StepsY = double.NaN;
AxesColor = Colors.Black;
LineColor = Colors.Yellow;
} }
public string SpeedLabel => UI.ButtonLabel_Stop;
public string KbsLabel => UI.Kb_s;
public string BlockLabel => UI.Title_Block;
public ObservableCollection<(ulong block, double duration)> BlockMapList { get; }
// public ObservableCollection<DataPoint> ChartPoints { get; }
public string Title { get; } public string Title { get; }
public ICommand StartCommand { get; } public ICommand StartCommand { get; }
@@ -181,7 +159,6 @@ public sealed partial class MediaScanViewModel : ViewModelBase
ProgressVisible = true; ProgressVisible = true;
ResultsVisible = true; ResultsVisible = true;
// ChartPoints.Clear();
new Thread(DoWork).Start(); new Thread(DoWork).Start();
} }
@@ -204,8 +181,17 @@ public sealed partial class MediaScanViewModel : ViewModelBase
ScanResults results = _scanner.Scan(); ScanResults results = _scanner.Scan();
// Flush any remaining pending sector data
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {
lock(_pendingSectorDataLock)
{
foreach((ulong startingSector, double duration) item in _pendingSectorData)
BlockMapSectorData.Add(item);
_pendingSectorData.Clear();
}
TotalTime = string.Format(Localization.Core.Took_a_total_of_0_1_processing_commands, TotalTime = string.Format(Localization.Core.Took_a_total_of_0_1_processing_commands,
results.TotalTime.Seconds().Humanize(minUnit: TimeUnit.Second), results.TotalTime.Seconds().Humanize(minUnit: TimeUnit.Second),
results.ProcessingTime.Seconds().Humanize(minUnit: TimeUnit.Second)); results.ProcessingTime.Seconds().Humanize(minUnit: TimeUnit.Second));
@@ -268,6 +254,9 @@ public sealed partial class MediaScanViewModel : ViewModelBase
async void InitBlockMap(ulong blocks, ulong blockSize, ulong blocksToRead, ushort currentProfile) => async void InitBlockMap(ulong blocks, ulong blockSize, ulong blocksToRead, ushort currentProfile) =>
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {
ScanBlockSize = (uint)blocksToRead;
BlockMapSectorData = [];
Blocks = blocks / blocksToRead; Blocks = blocks / blocksToRead;
_blocksToRead = blocksToRead; _blocksToRead = blocksToRead;
@@ -419,14 +408,12 @@ public sealed partial class MediaScanViewModel : ViewModelBase
{ {
_localResults.Errored += _blocksToRead; _localResults.Errored += _blocksToRead;
UnreadableSectors = string.Format(Localization.Core._0_sectors_could_not_be_read, _localResults.Errored); UnreadableSectors = string.Format(Localization.Core._0_sectors_could_not_be_read, _localResults.Errored);
BlockMapList.Add((sector / _blocksToRead, double.NaN));
}); });
[SuppressMessage("ReSharper", "AsyncVoidMethod")] [SuppressMessage("ReSharper", "AsyncVoidMethod")]
async void OnScanTime(ulong sector, double duration) => await Dispatcher.UIThread.InvokeAsync(() => async void OnScanTime(ulong sector, double duration)
{ {
BlockMapList.Add((sector / _blocksToRead, duration)); // Update local results counters (thread-safe, no UI dispatch needed)
switch(duration) switch(duration)
{ {
case < 3: case < 3:
@@ -455,11 +442,55 @@ public sealed partial class MediaScanViewModel : ViewModelBase
break; break;
} }
A = string.Format(Localization.Core._0_sectors_took_less_than_3_ms, _localResults.A); // Batch sector data updates
B = string.Format(Localization.Core._0_sectors_took_less_than_10_ms_but_more_than_3_ms, _localResults.B); List<(ulong sector, double duration)> itemsToAdd = null;
C = string.Format(Localization.Core._0_sectors_took_less_than_50_ms_but_more_than_10_ms, _localResults.C);
D = string.Format(Localization.Core._0_sectors_took_less_than_150_ms_but_more_than_50_ms, _localResults.D); lock(_pendingSectorDataLock)
E = string.Format(Localization.Core._0_sectors_took_less_than_500_ms_but_more_than_150_ms, _localResults.E); {
F = string.Format(Localization.Core._0_sectors_took_more_than_500_ms, _localResults.F); _pendingSectorData.Add((sector, duration));
});
// Only dispatch to UI thread every 50 items to reduce overhead
if(_pendingSectorData.Count >= 50)
{
itemsToAdd = _pendingSectorData.ToList();
_pendingSectorData.Clear();
}
}
// Dispatch outside the lock
if(itemsToAdd != null)
{
await Dispatcher.UIThread.InvokeAsync(() =>
{
foreach((ulong sector, double duration) item in itemsToAdd)
BlockMapSectorData.Add(item);
// Update text labels
A = string.Format(Localization.Core
._0_sectors_took_less_than_3_ms,
_localResults.A);
B = string.Format(Localization.Core
._0_sectors_took_less_than_10_ms_but_more_than_3_ms,
_localResults.B);
C = string.Format(Localization.Core
._0_sectors_took_less_than_50_ms_but_more_than_10_ms,
_localResults.C);
D = string.Format(Localization.Core
._0_sectors_took_less_than_150_ms_but_more_than_50_ms,
_localResults.D);
E = string.Format(Localization.Core
._0_sectors_took_less_than_500_ms_but_more_than_150_ms,
_localResults.E);
F = string.Format(Localization.Core
._0_sectors_took_more_than_500_ms,
_localResults.F);
},
DispatcherPriority.Background);
}
}
} }

View File

@@ -83,7 +83,18 @@
<TabItem.Header> <TabItem.Header>
<TextBlock Text="{x:Static localization:UI.Title_Block_map}" /> <TextBlock Text="{x:Static localization:UI.Title_Block_map}" />
</TabItem.Header> </TabItem.Header>
<!-- <controls:BlockMap Width="750" Height="400" Blocks="{Binding Blocks}" ItemsSource="{Binding BlockMapList}" /> --> <Border Margin="8"
BorderThickness="1"
BorderBrush="LightGray"
CornerRadius="8">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<controls:BlockMap SectorData="{Binding BlockMapSectorData, Mode=OneWay}"
VerticalAlignment="Top"
ScanBlockSize="{Binding ScanBlockSize, Mode=OneWay}"
Margin="4" />
</ScrollViewer>
</Border>
</TabItem> </TabItem>
<TabItem> <TabItem>
<TabItem.Header> <TabItem.Header>