Refactor and enhance Download Manager application

- Added new services: IContentDialogService, ISnackbarService
- Replaced DashboardPage and DashboardViewModel with DownloadingPage, DownloadingPageViewModel, WaitingPage, and WaitingPageViewModel
- Introduced AddNewTaskPage and AddNewTaskViewModel
- Replaced DownloadServiceManger with DownloadManagerService
- Updated WPF-UI package to 3.0.4 and added HtmlAgilityPack 1.11.61
- Refactored DownloadWorker to use async methods and added retry logic
- Converted DownloadItemData to partial class with ObservableProperty attributes
- Changed initial navigation page to DownloadingPage
- Updated MainWindow navigation items and title
- Added new utility classes: DoubleUtilities, MD5Utilities, StringExtension
- Added new XAML pages and ViewModels for task management and display
- Removed obsolete DashboardPage and related files
This commit is contained in:
Misaki
2024-07-01 02:14:19 +09:00
parent 150cd3cb26
commit 3a59979efd
33 changed files with 1180 additions and 212 deletions

View File

@@ -0,0 +1,181 @@
using Downloader;
using DownloadManager.Models;
using DownloadManager.Models.UrlGetter;
using DownloadManager.Views.Pages;
using Microsoft.Win32;
using System.IO;
using System.Net;
using Wpf.Ui;
using Wpf.Ui.Controls;
namespace DownloadManager.ViewModels.Pages
{
public partial class TaskData : ObservableObject
{
[ObservableProperty]
private string? taskURL;
[ObservableProperty]
private UrlGetterType urlGetter = UrlGetterType.Direct;
[ObservableProperty]
private string? saveLocation;
[ObservableProperty]
private int splitCount = 1;
[ObservableProperty]
private bool useParallelDownload = false;
[ObservableProperty]
private int retryCount = 3;
[ObservableProperty]
private string? userAgent;
[ObservableProperty]
private string? cookies;
[ObservableProperty]
private string? proxy;
}
public partial class AddNewTaskViewModel(ISnackbarService snackbarService) : ObservableObject, INavigationAware
{
[ObservableProperty]
private TaskData? taskDataConfig;
private string _lastSaveLocation = string.Empty;
public void OnNavigatedTo()
{
TaskDataConfig = new();
TaskDataConfig.SaveLocation = _lastSaveLocation;
}
public void OnNavigatedFrom()
{
}
[RelayCommand]
public void PickSaveLocation()
{
if (TaskDataConfig == null)
return;
OpenFolderDialog openFolderDialog = new()
{
Multiselect = true,
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
};
if (openFolderDialog.ShowDialog() != true)
{
return;
}
if (openFolderDialog.FolderNames.Length == 0)
{
return;
}
var folderName = string.Join("\n", openFolderDialog.FolderNames);
TaskDataConfig.SaveLocation = folderName;
}
[RelayCommand]
public async Task ApplyTask()
{
if (TaskDataConfig == null)
return;
if (string.IsNullOrEmpty(TaskDataConfig.TaskURL))
{
snackbarService.Show(
"Task URL is empty",
"Please add at least one task url to download",
ControlAppearance.Danger,
new SymbolIcon(SymbolRegular.ErrorCircle24),
TimeSpan.FromSeconds(5));
return;
}
if (string.IsNullOrEmpty(TaskDataConfig.SaveLocation) || !Directory.Exists(TaskDataConfig.SaveLocation))
{
snackbarService.Show(
"Save location is not exists",
"Please add a valid location",
ControlAppearance.Danger,
new SymbolIcon(SymbolRegular.ErrorCircle24),
TimeSpan.FromSeconds(5));
return;
}
// Split TaskDataConfig.TaskURL to one task per line
var taskUrls = TaskDataConfig.TaskURL.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
await Task.Run(() =>
{
foreach (var taskUrl in taskUrls)
{
if (string.IsNullOrEmpty(TaskDataConfig.TaskURL))
{
snackbarService.Show(
"Invalid task URL",
"Please add a valid task URL",
ControlAppearance.Danger,
new SymbolIcon(SymbolRegular.ErrorCircle24),
TimeSpan.FromSeconds(5));
return;
}
var cookies = new CookieContainer();
if (!string.IsNullOrEmpty(TaskDataConfig.Cookies))
{
var cookieStrings = TaskDataConfig.Cookies.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var cookieString in cookieStrings)
{
var cookieParts = cookieString.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
if (cookieParts.Length != 2)
{
continue;
}
cookies.Add(new Cookie(cookieParts[0].Trim(), cookieParts[1].Trim(), "/", new Uri(TaskDataConfig.Cookies).Host));
}
}
var config = new DownloadConfiguration
{
ChunkCount = TaskDataConfig.SplitCount,
ParallelDownload = TaskDataConfig.UseParallelDownload,
MaxTryAgainOnFailover = TaskDataConfig.RetryCount,
BufferBlockSize = 10240,
RequestConfiguration =
{
UserAgent = TaskDataConfig.UserAgent,
CookieContainer = cookies,
Proxy = new WebProxy(TaskDataConfig.Proxy)
}
};
var data = new DownloadItemData(TaskDataConfig.SaveLocation, taskUrl, TaskDataConfig.UrlGetter, config);
App.GetService<DownloaderCore.DownloadManagerService>().AddDownloadItem(data);
}
});
App.GetService<INavigationService>().Navigate(typeof(DownloadingPage));
try
{
await App.GetService<DownloaderCore.DownloadManagerService>().FindNextDownloadAndStart();
}
catch (Exception ex)
{
snackbarService.Show(
"Error downloading files",
ex.Message,
ControlAppearance.Danger,
new SymbolIcon(SymbolRegular.ErrorCircle24),
TimeSpan.FromSeconds(5));
}
_lastSaveLocation = TaskDataConfig.SaveLocation;
}
}
}

View File

@@ -1,11 +0,0 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.
namespace DownloadManager.ViewModels.Pages;
public partial class DashboardViewModel : ObservableObject
{
}

View File

@@ -0,0 +1,33 @@
using DownloadManager.DownloaderCore;
using DownloadManager.Models;
using System.Collections.ObjectModel;
using Wpf.Ui.Controls;
namespace DownloadManager.ViewModels.Pages;
public partial class DownloadingPageViewModel : ObservableObject, INavigationAware
{
[ObservableProperty]
private ObservableCollection<DownloadItemData>? downloadingTask;
public void OnNavigatedFrom()
{
}
public void OnNavigatedTo()
{
App.GetService<DownloadManagerService>().OnActiveWorkerChanged += DownloadService_OnDownloadServiceChanged;
LoadTasks();
}
private void DownloadService_OnDownloadServiceChanged()
{
LoadTasks();
}
private void LoadTasks()
{
DownloadingTask = new(App.GetService<DownloadManagerService>().GetDownloadingTask());
}
}

View File

@@ -0,0 +1,33 @@
using DownloadManager.DownloaderCore;
using DownloadManager.Models;
using System.Collections.ObjectModel;
using Wpf.Ui.Controls;
namespace DownloadManager.ViewModels.Pages;
public partial class WaitingPageViewModel : ObservableObject, INavigationAware
{
[ObservableProperty]
private ObservableCollection<DownloadItemData>? waitingTask;
public void OnNavigatedFrom()
{
}
public void OnNavigatedTo()
{
App.GetService<DownloadManagerService>().OnQueuedItemChanged += DownloadService_OnQueuedItemChanged;
LoadTasks();
}
private void DownloadService_OnQueuedItemChanged()
{
LoadTasks();
}
private void LoadTasks()
{
WaitingTask = new (App.GetService<DownloadManagerService>().GetWaitingTask());
}
}