Browse Source

Fix resume loading behavior

pull/109/head
Ionite 1 year ago
parent
commit
85b8a25baa
No known key found for this signature in database
  1. 1
      StabilityMatrix.Avalonia/ViewModels/DownloadProgressItemViewModel.cs
  2. 6
      StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs
  3. 14
      StabilityMatrix.Avalonia/ViewModels/ProgressManagerViewModel.cs
  4. 37
      StabilityMatrix.Core/Models/TrackedDownload.cs
  5. 2
      StabilityMatrix.Core/Services/ITrackedDownloadService.cs
  6. 6
      StabilityMatrix.Core/Services/TrackedDownloadService.cs

1
StabilityMatrix.Avalonia/ViewModels/DownloadProgressItemViewModel.cs

@ -13,6 +13,7 @@ public class DownloadProgressItemViewModel : PausableProgressItemViewModelBase
{ {
this.download = download; this.download = download;
Id = download.Id;
Name = download.FileName; Name = download.FileName;
State = download.ProgressState; State = download.ProgressState;

6
StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs

@ -24,6 +24,7 @@ public partial class MainWindowViewModel : ViewModelBase
{ {
private readonly ISettingsManager settingsManager; private readonly ISettingsManager settingsManager;
private readonly ServiceManager<ViewModelBase> dialogFactory; private readonly ServiceManager<ViewModelBase> dialogFactory;
private readonly ITrackedDownloadService trackedDownloadService;
private readonly IDiscordRichPresenceService discordRichPresenceService; private readonly IDiscordRichPresenceService discordRichPresenceService;
public string Greeting => "Welcome to Avalonia!"; public string Greeting => "Welcome to Avalonia!";
@ -45,11 +46,13 @@ public partial class MainWindowViewModel : ViewModelBase
public MainWindowViewModel( public MainWindowViewModel(
ISettingsManager settingsManager, ISettingsManager settingsManager,
IDiscordRichPresenceService discordRichPresenceService, IDiscordRichPresenceService discordRichPresenceService,
ITrackedDownloadService trackedDownloadService,
ServiceManager<ViewModelBase> dialogFactory) ServiceManager<ViewModelBase> dialogFactory)
{ {
this.settingsManager = settingsManager; this.settingsManager = settingsManager;
this.dialogFactory = dialogFactory; this.dialogFactory = dialogFactory;
this.discordRichPresenceService = discordRichPresenceService; this.discordRichPresenceService = discordRichPresenceService;
this.trackedDownloadService = trackedDownloadService;
ProgressManagerViewModel = dialogFactory.Get<ProgressManagerViewModel>(); ProgressManagerViewModel = dialogFactory.Get<ProgressManagerViewModel>();
UpdateViewModel = dialogFactory.Get<UpdateViewModel>(); UpdateViewModel = dialogFactory.Get<UpdateViewModel>();
@ -81,6 +84,9 @@ public partial class MainWindowViewModel : ViewModelBase
// Initialize Discord Rich Presence (this needs LibraryDir so is set here) // Initialize Discord Rich Presence (this needs LibraryDir so is set here)
discordRichPresenceService.UpdateState(); discordRichPresenceService.UpdateState();
// Load in-progress downloads
ProgressManagerViewModel.AddDownloads(trackedDownloadService.Downloads);
// Index checkpoints if we dont have // Index checkpoints if we dont have
Task.Run(() => settingsManager.IndexCheckpoints()).SafeFireAndForget(); Task.Run(() => settingsManager.IndexCheckpoints()).SafeFireAndForget();

14
StabilityMatrix.Avalonia/ViewModels/ProgressManagerViewModel.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Avalonia.Collections; using Avalonia.Collections;
@ -38,6 +39,19 @@ public partial class ProgressManagerViewModel : PageViewModelBase
ProgressItems.Add(vm); ProgressItems.Add(vm);
} }
public void AddDownloads(IEnumerable<TrackedDownload> downloads)
{
foreach (var download in downloads)
{
if (ProgressItems.Any(vm => vm.Id == download.Id))
{
continue;
}
var vm = new DownloadProgressItemViewModel(download);
ProgressItems.Add(vm);
}
}
public void StartEventListener() public void StartEventListener()
{ {
EventManager.Instance.ProgressChanged += OnProgressChanged; EventManager.Instance.ProgressChanged += OnProgressChanged;

37
StabilityMatrix.Core/Models/TrackedDownload.cs

@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using AsyncAwaitBestPractices; using AsyncAwaitBestPractices;
using NLog;
using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Models.Progress;
@ -16,6 +17,8 @@ public class TrackedDownloadProgressEventArgs : EventArgs
public class TrackedDownload public class TrackedDownload
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
[JsonIgnore] [JsonIgnore]
private IDownloadService? downloadService; private IDownloadService? downloadService;
@ -128,6 +131,7 @@ public class TrackedDownload
{ {
throw new InvalidOperationException($"Download state must be inactive to start, not {ProgressState}"); throw new InvalidOperationException($"Download state must be inactive to start, not {ProgressState}");
} }
Logger.Debug("Starting download {Download}", FileName);
EnsureDownloadService(); EnsureDownloadService();
@ -138,34 +142,59 @@ public class TrackedDownload
.ContinueWith(OnDownloadTaskCompleted); .ContinueWith(OnDownloadTaskCompleted);
ProgressState = ProgressState.Working; ProgressState = ProgressState.Working;
OnProgressStateChanged(ProgressState);
} }
public void Resume() public void Resume()
{ {
if (ProgressState != ProgressState.Inactive) return; if (ProgressState != ProgressState.Inactive)
{
Logger.Warn("Attempted to resume download {Download} but it is not paused ({State})", FileName, ProgressState);
}
Logger.Debug("Resuming download {Download}", FileName);
// Read the temp file to get the current size
var tempSize = 0L;
var tempFile = DownloadDirectory.JoinFile(TempFileName);
if (tempFile.Exists)
{
tempSize = tempFile.Info.Length;
}
EnsureDownloadService(); EnsureDownloadService();
downloadCancellationTokenSource = new CancellationTokenSource(); downloadCancellationTokenSource = new CancellationTokenSource();
downloadPauseTokenSource = new CancellationTokenSource(); downloadPauseTokenSource = new CancellationTokenSource();
downloadTask = StartDownloadTask(0, AggregateCancellationTokenSource.Token) downloadTask = StartDownloadTask(tempSize, AggregateCancellationTokenSource.Token)
.ContinueWith(OnDownloadTaskCompleted); .ContinueWith(OnDownloadTaskCompleted);
ProgressState = ProgressState.Working; ProgressState = ProgressState.Working;
OnProgressStateChanged(ProgressState);
} }
public void Pause() public void Pause()
{ {
if (ProgressState != ProgressState.Working) return; if (ProgressState != ProgressState.Working)
{
Logger.Warn("Attempted to pause download {Download} but it is not in progress ({State})", FileName, ProgressState);
return;
}
Logger.Debug("Pausing download {Download}", FileName);
downloadPauseTokenSource?.Cancel(); downloadPauseTokenSource?.Cancel();
} }
public void Cancel() public void Cancel()
{ {
if (ProgressState is not (ProgressState.Working or ProgressState.Inactive)) return; if (ProgressState is not (ProgressState.Working or ProgressState.Inactive))
{
Logger.Warn("Attempted to cancel download {Download} but it is not in progress ({State})", FileName, ProgressState);
return;
}
Logger.Debug("Cancelling download {Download}", FileName);
downloadCancellationTokenSource?.Cancel(); downloadCancellationTokenSource?.Cancel();
} }

2
StabilityMatrix.Core/Services/ITrackedDownloadService.cs

@ -5,6 +5,8 @@ namespace StabilityMatrix.Core.Services;
public interface ITrackedDownloadService public interface ITrackedDownloadService
{ {
IEnumerable<TrackedDownload> Downloads { get; }
event EventHandler<TrackedDownload>? DownloadAdded; event EventHandler<TrackedDownload>? DownloadAdded;
TrackedDownload NewDownload(Uri downloadUrl, FilePath downloadPath); TrackedDownload NewDownload(Uri downloadUrl, FilePath downloadPath);

6
StabilityMatrix.Core/Services/TrackedDownloadService.cs

@ -17,6 +17,8 @@ public class TrackedDownloadService : ITrackedDownloadService, IDisposable
private readonly ConcurrentDictionary<Guid, (TrackedDownload, FileStream)> downloads = new(); private readonly ConcurrentDictionary<Guid, (TrackedDownload, FileStream)> downloads = new();
public IEnumerable<TrackedDownload> Downloads => downloads.Values.Select(x => x.Item1);
/// <inheritdoc /> /// <inheritdoc />
public event EventHandler<TrackedDownload>? DownloadAdded; public event EventHandler<TrackedDownload>? DownloadAdded;
@ -136,6 +138,10 @@ public class TrackedDownloadService : ITrackedDownloadService, IDisposable
download.SetDownloadService(downloadService); download.SetDownloadService(downloadService);
downloads.TryAdd(download.Id, (download, fileStream)); downloads.TryAdd(download.Id, (download, fileStream));
// Connect to state changed event to update json file
download.ProgressStateChanged += TrackedDownload_OnProgressStateChanged;
OnDownloadAdded(download); OnDownloadAdded(download);
logger.LogDebug("Loaded in-progress download {Download}", download.FileName); logger.LogDebug("Loaded in-progress download {Download}", download.FileName);

Loading…
Cancel
Save