108 lines
3.6 KiB
C#
108 lines
3.6 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace VideoDownloader.App.Browser.Features;
|
|
|
|
/// <summary>CoreWebView2DownloadOperation 의 최소 추상화(단위 테스트 fake 교체 가능).</summary>
|
|
public interface IDownloadOperation
|
|
{
|
|
string Uri { get; }
|
|
string FileName { get; }
|
|
long BytesReceived { get; }
|
|
long TotalBytesToReceive { get; }
|
|
/// <summary>InProgress / Interrupted / Completed / Cancelled</summary>
|
|
string State { get; }
|
|
void Pause();
|
|
void Resume();
|
|
void Cancel();
|
|
/// <summary>BytesReceived/State 변경 통지(구현은 호스트 스레드에서 발화).</summary>
|
|
event Action? Changed;
|
|
}
|
|
|
|
/// <summary>다운로드 매니저 UI 항목(T1-5) — 진행률/속도/상태를 INPC 로 노출.</summary>
|
|
public sealed class PageDownloadItem : INotifyPropertyChanged
|
|
{
|
|
public IDownloadOperation Op { get; }
|
|
public string FileName { get; }
|
|
public string Uri { get; }
|
|
public long TotalBytes { get; }
|
|
private long _received;
|
|
private long _bps;
|
|
private string _state;
|
|
|
|
public PageDownloadItem(IDownloadOperation op, string fileName)
|
|
{
|
|
Op = op;
|
|
FileName = fileName;
|
|
Uri = op.Uri;
|
|
TotalBytes = op.TotalBytesToReceive;
|
|
_received = op.BytesReceived;
|
|
_state = op.State;
|
|
op.Changed += () =>
|
|
{
|
|
_received = op.BytesReceived;
|
|
_state = op.State;
|
|
OnPropertyChangedAll();
|
|
};
|
|
}
|
|
|
|
public double Percent => TotalBytes > 0 ? Math.Clamp(_received * 100.0 / TotalBytes, 0, 100) : 0;
|
|
public long BytesPerSecond => _bps;
|
|
public string State => _state;
|
|
public bool IsFinished => _state is "Completed" or "Interrupted" or "Cancelled";
|
|
public bool CanControl => _state == "InProgress";
|
|
|
|
public string SpeedText => _bps switch
|
|
{
|
|
<= 0 => "—",
|
|
< 1024 => $"{(double)_bps:F1} B/s",
|
|
< 1024 * 1024 => $"{_bps / 1024.0:F1} KB/s",
|
|
_ => $"{_bps / 1024.0 / 1024.0:F1} MB/s",
|
|
};
|
|
|
|
private long? _lastSpeedReceived;
|
|
|
|
/// <summary>속도 갱신: (현재까지 수신 바이트, 직전 호출로부터 경과).</summary>
|
|
public void UpdateSpeed(long receivedNow, TimeSpan elapsed)
|
|
{
|
|
_received = receivedNow;
|
|
if (elapsed.TotalSeconds > 0)
|
|
{
|
|
var delta = Math.Max(0, receivedNow - (_lastSpeedReceived ?? 0));
|
|
_bps = (long)(delta / elapsed.TotalSeconds);
|
|
}
|
|
_lastSpeedReceived = receivedNow;
|
|
OnPropertyChangedAll();
|
|
}
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
private void OnPropertyChangedAll()
|
|
{
|
|
foreach (var n in new[] { nameof(Percent), nameof(BytesPerSecond), nameof(SpeedText), nameof(State), nameof(IsFinished), nameof(CanControl) })
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
|
}
|
|
}
|
|
|
|
/// <summary>페이지 다운로드 목록(T1-5) — 최신순, 일시정지/재개/취소, 완료 정리.</summary>
|
|
public sealed class PageDownloadTracker
|
|
{
|
|
public ObservableCollection<PageDownloadItem> Items { get; } = new();
|
|
|
|
public PageDownloadItem Add(IDownloadOperation op, string fileName)
|
|
{
|
|
var item = new PageDownloadItem(op, fileName);
|
|
Items.Insert(0, item);
|
|
return item;
|
|
}
|
|
|
|
public void Pause(PageDownloadItem item) => item.Op.Pause();
|
|
public void Resume(PageDownloadItem item) => item.Op.Resume();
|
|
public void Cancel(PageDownloadItem item) => item.Op.Cancel();
|
|
|
|
public void ClearCompleted()
|
|
{
|
|
foreach (var done in Items.Where(i => i.IsFinished).ToList())
|
|
Items.Remove(done);
|
|
}
|
|
}
|