Skip to content

Commit

Permalink
Merge pull request #1297 from erri120/feat/888-charts
Browse files Browse the repository at this point in the history
Download speed chart
  • Loading branch information
erri120 committed May 6, 2024
2 parents 8db6f5e + 48b5dcf commit 30eaae2
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 4 deletions.
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<PackageVersion Include="FlatSharp.Compiler" Version="7.6.0" />
<PackageVersion Include="FlatSharp.Runtime" Version="7.6.0" />
<PackageVersion Include="LinqGen" Version="0.3.1" />
<PackageVersion Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc2" />
<PackageVersion Include="NexusMods.MnemonicDB" Version="0.9.17" />
<PackageVersion Include="NexusMods.MnemonicDB.Abstractions" Version="0.9.17" />
<PackageVersion Include="NexusMods.Paths" Version="0.9.3" />
Expand Down
5 changes: 5 additions & 0 deletions src/NexusMods.App.UI/Helpers/StringFormatters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public static string ToSizeString(long currentBytes, long totalBytes)
return $"{currentBytesStr} / {totalBytesStr}";
}

public static string ToThroughputString(long throughput, TimeSpan interval)
{
return new ByteRate(ByteSize.FromBytes(throughput), interval).Humanize();
}

/// <summary>
/// Formats the seconds remaining in format '0 mins', '0 secs' etc.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/NexusMods.App.UI/NexusMods.App.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<PackageReference Include="Avalonia.ReactiveUI" />
<PackageReference Include="Avalonia.Svg.Skia" />
<PackageReference Include="Avalonia.Themes.Fluent" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
<PackageReference Include="Markdown.Avalonia.Tight" />
<PackageReference Include="DynamicData" />
<PackageReference Include="Humanizer" />
Expand Down
6 changes: 6 additions & 0 deletions src/NexusMods.App.UI/Pages/Downloads/IInProgressViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.ObjectModel;
using System.Windows.Input;
using DynamicData;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using NexusMods.App.UI.Controls.DataGrid;
using NexusMods.App.UI.Controls.DownloadGrid;
using NexusMods.App.UI.Pages.Downloads.ViewModels;
Expand All @@ -17,6 +19,10 @@ public interface IInProgressViewModel : IPageViewModelInterface

ReadOnlyObservableCollection<IDataGridColumnFactory<DownloadColumn>> Columns { get; }

public ReadOnlyObservableCollection<ISeries> Series { get; }

public Axis[] YAxes { get; }
public Axis[] XAxes { get; }

/// <summary>
/// True if download is running, else false.
Expand Down
12 changes: 8 additions & 4 deletions src/NexusMods.App.UI/Pages/Downloads/InProgressView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
xmlns:resources="clr-namespace:NexusMods.App.UI.Resources"
xmlns:downloads="clr-namespace:NexusMods.App.UI.Pages.Downloads"
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.Avalonia;assembly=LiveChartsCore.SkiaSharpView.Avalonia"
xmlns:skiaSharpView="clr-namespace:LiveChartsCore.SkiaSharpView;assembly=LiveChartsCore.SkiaSharpView"
mc:Ignorable="d" d:DesignWidth="920" d:DesignHeight="664"
x:Class="NexusMods.App.UI.Pages.Downloads.InProgressView">
<Design.DataContext>
Expand Down Expand Up @@ -60,7 +62,7 @@
</Border>

<!-- Page Content -->
<Grid RowDefinitions="Auto, 24, *, Auto" Margin="24, 16" Grid.Row="1">
<Grid RowDefinitions="Auto, *, 24, *, Auto" Margin="24, 16" Grid.Row="1">

<!-- Title & Status -->
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch" Grid.Row="0">
Expand Down Expand Up @@ -98,19 +100,21 @@

</DockPanel>

<lvc:CartesianChart Grid.Row="1" x:Name="Chart"/>

<!-- Progress -->
<ProgressBar Classes="DownloadBar"
ProgressTextFormat="{x:Static resources:Language.ProgressBar_ProgressTextFormat__Total_1_0}"
x:Name="DownloadProgressBar" Minimum="0" Maximum="1" Grid.Row="1" />
x:Name="DownloadProgressBar" Minimum="0" Maximum="1" Grid.Row="2" />

<!-- Currently Downloaded Mods -->
<DataGrid Grid.Row="2"
<DataGrid Grid.Row="3"
HorizontalAlignment="Stretch"
CanUserSortColumns="True"
Margin="-16,16"
x:Name="ModsDataGrid" />

<TextBlock Grid.Row="2"
<TextBlock Grid.Row="4"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="0,66,0,0"
Expand Down
7 changes: 7 additions & 0 deletions src/NexusMods.App.UI/Pages/Downloads/InProgressView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ public InProgressView()

this.WhenActivated(d =>
{
this.OneWayBind(ViewModel, vm => vm.Series, view => view.Chart.Series)
.DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.YAxes, view => view.Chart.YAxes)
.DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.XAxes, view => view.Chart.XAxes)
.DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.ShowCancelDialogCommand, view => view.CancelButton)
.DisposeWith(d);
Expand Down
69 changes: 69 additions & 0 deletions src/NexusMods.App.UI/Pages/Downloads/InProgressViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,25 @@
using DynamicData;
using DynamicData.Binding;
using JetBrains.Annotations;
using LiveChartsCore;
using LiveChartsCore.Defaults;
using LiveChartsCore.SkiaSharpView;
using NexusMods.App.UI.Controls.DataGrid;
using NexusMods.App.UI.Controls.DownloadGrid;
using NexusMods.App.UI.Controls.DownloadGrid.Columns.DownloadGameName;
using NexusMods.App.UI.Controls.DownloadGrid.Columns.DownloadName;
using NexusMods.App.UI.Controls.DownloadGrid.Columns.DownloadSize;
using NexusMods.App.UI.Controls.DownloadGrid.Columns.DownloadStatus;
using NexusMods.App.UI.Controls.DownloadGrid.Columns.DownloadVersion;
using NexusMods.App.UI.Helpers;
using NexusMods.App.UI.Overlays;
using NexusMods.App.UI.Pages.Downloads.ViewModels;
using NexusMods.App.UI.Resources;
using NexusMods.App.UI.Windows;
using NexusMods.App.UI.WorkspaceSystem;
using NexusMods.Icons;
using NexusMods.Networking.Downloaders.Interfaces;
using NexusMods.Paths;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;

Expand Down Expand Up @@ -76,12 +81,48 @@ private ReadOnlyObservableCollection<IDataGridColumnFactory<DownloadColumn>>
[Reactive]
public ICommand ShowSettings { get; private set; } = ReactiveCommand.Create(() => { }, Observable.Return(false));

private readonly ObservableCollectionExtended<DateTimePoint> _throughputValues = [];
public ReadOnlyObservableCollection<ISeries> Series { get; } = ReadOnlyObservableCollection<ISeries>.Empty;

private readonly ObservableCollectionExtended<double> _customSeparators = [0];

public Axis[] YAxes { get; } = [];

public Axis[] XAxes { get; } =
[
new DateTimeAxis(TimeSpan.FromSeconds(1), static date => date.ToString("HH:mm:ss"))
{
AnimationsSpeed = TimeSpan.FromMilliseconds(0),
LabelsPaint = null,
},
];

[UsedImplicitly]
public InProgressViewModel(
IWindowManager windowManager,
IDownloadService downloadService,
IOverlayController overlayController) : base(windowManager)
{
Series = new ReadOnlyObservableCollection<ISeries>([
new LineSeries<DateTimePoint>
{
Values = _throughputValues,
Fill = null,
GeometryFill = null,
GeometryStroke = null,
},
]);

YAxes =
[
new Axis
{
MinLimit = 0,
CustomSeparators = _customSeparators,
Labeler = static value => StringFormatters.ToThroughputString((long)value, TimeSpan.FromSeconds(1)),
},
];

TabTitle = Language.InProgressDownloadsPage_Title;
TabIcon = IconValues.Downloading;

Expand Down Expand Up @@ -291,5 +332,33 @@ private void UpdateWindowInfoInternal()
var throughput = Tasks.Sum(x => x.Throughput);
var remainingBytes = totalSizeBytes - totalDownloadedBytes;
SecondsRemaining = throughput < 1.0 ? 0 : (int)(remainingBytes / Math.Max(throughput, 1));

if (_throughputValues.Count > 120)
{
_throughputValues.RemoveRange(0, count: 60);
}

throughput = totalSizeBytes > 0 ? throughput : 0;
if (throughput > _customSeparators.Last())
{
_customSeparators.Add(FirstMultiple(throughput));
}

_throughputValues.Add(new DateTimePoint(DateTime.Now, throughput));
}

private static double FirstMultiple(long value)
{
const int step = 5;
var start = (long)Size.MB.Value * step;

var res = start;

while (res <= value)
{
res += start;
}

return res;
}
}

0 comments on commit 30eaae2

Please sign in to comment.