From 7a4b411e034850e1b78a629de9eac0bbfa2ba104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9A=E5=BD=AA?= <1315508912@qq.com> Date: Sun, 24 Dec 2023 01:06:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E6=8F=90=E9=86=92=E7=9A=84=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Settings/RepeatDownloadStrategy.cs | 8 + DownKyi/App.axaml.cs | 16 +- .../Models/RepeatDownloadStrategyDisplay.cs | 9 + .../Services/Download/AddToDownloadService.cs | 248 ++++++++++-------- .../ViewAlreadyDownloadedDialogViewModel.cs | 66 +++++ .../ViewModels/Settings/ViewBasicViewModel.cs | 174 +++++++----- .../Dialogs/ViewAlreadyDownloadedDialog.axaml | 98 +++++++ .../ViewAlreadyDownloadedDialog.axaml.cs | 13 + DownKyi/Views/Settings/ViewBasic.axaml | 21 ++ 9 files changed, 467 insertions(+), 186 deletions(-) create mode 100644 DownKyi.Core/Settings/RepeatDownloadStrategy.cs create mode 100644 DownKyi/Models/RepeatDownloadStrategyDisplay.cs create mode 100644 DownKyi/ViewModels/Dialogs/ViewAlreadyDownloadedDialogViewModel.cs create mode 100644 DownKyi/Views/Dialogs/ViewAlreadyDownloadedDialog.axaml create mode 100644 DownKyi/Views/Dialogs/ViewAlreadyDownloadedDialog.axaml.cs diff --git a/DownKyi.Core/Settings/RepeatDownloadStrategy.cs b/DownKyi.Core/Settings/RepeatDownloadStrategy.cs new file mode 100644 index 0000000..0edf8ce --- /dev/null +++ b/DownKyi.Core/Settings/RepeatDownloadStrategy.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.Settings; + +public enum RepeatDownloadStrategy +{ + Ask, + ReDownload, + JumpOver +}; \ No newline at end of file diff --git a/DownKyi/App.axaml.cs b/DownKyi/App.axaml.cs index 8b131ba..67a0b42 100644 --- a/DownKyi/App.axaml.cs +++ b/DownKyi/App.axaml.cs @@ -37,6 +37,9 @@ public partial class App : PrismApplication { public static ObservableCollection DownloadingList { get; set; } public static ObservableCollection DownloadedList { get; set; } + public new static App Current => (App)Application.Current!; + public new MainWindow MainWindow => Container.Resolve(); + private IClassicDesktopStyleApplicationLifetime _appLife; // 下载服务 private IDownloadService? _downloadService; @@ -51,8 +54,15 @@ public partial class App : PrismApplication AvaloniaXamlLoader.Load(this); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - // desktop.Startup += OnStartup; desktop.Exit += OnExit!; + _appLife = desktop; + } + else + { + if (!Design.IsDesignMode) + { + throw new NotImplementedException("Not support this system."); + } } base.Initialize(); @@ -106,12 +116,14 @@ public partial class App : PrismApplication // UserSpace containerRegistry.RegisterForNavigation(ViewArchiveViewModel.Tag); // containerRegistry.RegisterForNavigation(ViewModels.UserSpace.ViewChannelViewModel.Tag); - containerRegistry.RegisterForNavigation(ViewModels.UserSpace.ViewSeasonsSeriesViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewModels.UserSpace + .ViewSeasonsSeriesViewModel.Tag); // dialogs containerRegistry.RegisterDialog(ViewAlertDialogViewModel.Tag); containerRegistry.RegisterDialog(ViewDownloadSetterViewModel.Tag); containerRegistry.RegisterDialog(ViewParsingSelectorViewModel.Tag); + containerRegistry.RegisterDialog(ViewAlreadyDownloadedDialogViewModel.Tag); } diff --git a/DownKyi/Models/RepeatDownloadStrategyDisplay.cs b/DownKyi/Models/RepeatDownloadStrategyDisplay.cs new file mode 100644 index 0000000..0d6c7bc --- /dev/null +++ b/DownKyi/Models/RepeatDownloadStrategyDisplay.cs @@ -0,0 +1,9 @@ +using DownKyi.Core.Settings; + +namespace DownKyi.Models; + +public class RepeatDownloadStrategyDisplay +{ + public string Name { get; set; } + public RepeatDownloadStrategy RepeatDownloadStrategy { get; set; } +} \ No newline at end of file diff --git a/DownKyi/Services/Download/AddToDownloadService.cs b/DownKyi/Services/Download/AddToDownloadService.cs index 6bac1f3..27c41d4 100644 --- a/DownKyi/Services/Download/AddToDownloadService.cs +++ b/DownKyi/Services/Download/AddToDownloadService.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Avalonia.Threading; using DownKyi.Core.BiliApi.BiliUtils; using DownKyi.Core.BiliApi.VideoStream; using DownKyi.Core.BiliApi.Zone; @@ -30,16 +31,16 @@ namespace DownKyi.Services.Download; public class AddToDownloadService { private readonly string Tag = "AddToDownloadService"; - private IInfoService videoInfoService; - private VideoInfoView videoInfoView; - private List videoSections; + private IInfoService _videoInfoService; + private VideoInfoView _videoInfoView; + private List? _videoSections; // 下载内容 - private bool downloadAudio = true; - private bool downloadVideo = true; - private bool downloadDanmaku = true; - private bool downloadSubtitle = true; - private bool downloadCover = true; + private bool _downloadAudio = true; + private bool _downloadVideo = true; + private bool _downloadDanmaku = true; + private bool _downloadSubtitle = true; + private bool _downloadCover = true; /// /// 添加下载 @@ -50,13 +51,13 @@ public class AddToDownloadService switch (streamType) { case PlayStreamType.VIDEO: - videoInfoService = new VideoInfoService(null); + _videoInfoService = new VideoInfoService(null); break; case PlayStreamType.BANGUMI: - videoInfoService = new BangumiInfoService(null); + _videoInfoService = new BangumiInfoService(null); break; case PlayStreamType.CHEESE: - videoInfoService = new CheeseInfoService(null); + _videoInfoService = new CheeseInfoService(null); break; default: break; @@ -73,13 +74,13 @@ public class AddToDownloadService switch (streamType) { case PlayStreamType.VIDEO: - videoInfoService = new VideoInfoService(id); + _videoInfoService = new VideoInfoService(id); break; case PlayStreamType.BANGUMI: - videoInfoService = new BangumiInfoService(id); + _videoInfoService = new BangumiInfoService(id); break; case PlayStreamType.CHEESE: - videoInfoService = new CheeseInfoService(id); + _videoInfoService = new CheeseInfoService(id); break; default: break; @@ -88,14 +89,14 @@ public class AddToDownloadService public void SetVideoInfoService(IInfoService videoInfoService) { - this.videoInfoService = videoInfoService; + _videoInfoService = videoInfoService; } public void GetVideo(VideoInfoView videoInfoView, List videoSections, List selectedVideo) { - this.videoInfoView = videoInfoView; - this.videoSections = videoSections; - foreach (VideoSection section in videoSections.Where(videoSection => videoSection.IsSelected)) + _videoInfoView = videoInfoView; + _videoSections = videoSections; + foreach (var section in videoSections.Where(videoSection => videoSection.IsSelected)) { foreach (var item in section.VideoPages) { @@ -109,32 +110,32 @@ public class AddToDownloadService public void GetVideo() { - videoInfoView = videoInfoService.GetVideoView(); - if (videoInfoView == null) + _videoInfoView = _videoInfoService.GetVideoView(); + if (_videoInfoView == null) { LogManager.Debug(Tag, "VideoInfoView is null."); return; } - videoSections = videoInfoService.GetVideoSections(true); - if (videoSections == null) + _videoSections = _videoInfoService.GetVideoSections(true); + if (_videoSections == null) { LogManager.Debug(Tag, "videoSections is not exist."); - videoSections = new List + _videoSections = new List { - new VideoSection + new() { Id = 0, Title = "default", IsSelected = true, - VideoPages = videoInfoService.GetVideoPages() + VideoPages = _videoInfoService.GetVideoPages() } }; } // 将所有视频设置为选中 - foreach (VideoSection section in videoSections) + foreach (var section in _videoSections) { foreach (var item in section.VideoPages) { @@ -149,14 +150,14 @@ public class AddToDownloadService /// public void ParseVideo(IInfoService videoInfoService) { - if (videoSections == null) + if (_videoSections == null) { return; } - foreach (VideoSection section in videoSections) + foreach (var section in _videoSections) { - foreach (VideoPage page in section.VideoPages) + foreach (var page in section.VideoPages) { // 执行解析任务 videoInfoService.GetVideoStream(page); @@ -168,56 +169,43 @@ public class AddToDownloadService /// 选择文件夹和下载项 /// /// - public async Task SetDirectory(IDialogService dialogService) + public async Task SetDirectory(IDialogService dialogService) { // 选择的下载文件夹 - string directory = string.Empty; + var directory = string.Empty; // 是否使用默认下载目录 if (SettingsManager.GetInstance().IsUseSaveVideoRootPath() == AllowStatus.YES) { // 下载内容 - VideoContentSettings videoContent = SettingsManager.GetInstance().GetVideoContent(); - downloadAudio = videoContent.DownloadAudio; - downloadVideo = videoContent.DownloadVideo; - downloadDanmaku = videoContent.DownloadDanmaku; - downloadSubtitle = videoContent.DownloadSubtitle; - downloadCover = videoContent.DownloadCover; + var videoContent = SettingsManager.GetInstance().GetVideoContent(); + _downloadAudio = videoContent.DownloadAudio; + _downloadVideo = videoContent.DownloadVideo; + _downloadDanmaku = videoContent.DownloadDanmaku; + _downloadSubtitle = videoContent.DownloadSubtitle; + _downloadCover = videoContent.DownloadCover; directory = SettingsManager.GetInstance().GetSaveVideoRootPath(); } else { - bool run = true; // 打开文件夹选择器 await dialogService.ShowDialogAsync(ViewDownloadSetterViewModel.Tag, null, result => { - if (result.Result == ButtonResult.OK) - { - // 选择的下载文件夹 - directory = result.Parameters.GetValue("directory"); + if (result.Result != ButtonResult.OK) return; + // 选择的下载文件夹 + directory = result.Parameters.GetValue("directory"); - // 下载内容 - downloadAudio = result.Parameters.GetValue("downloadAudio"); - downloadVideo = result.Parameters.GetValue("downloadVideo"); - downloadDanmaku = result.Parameters.GetValue("downloadDanmaku"); - downloadSubtitle = result.Parameters.GetValue("downloadSubtitle"); - downloadCover = result.Parameters.GetValue("downloadCover"); - } - - run = false; + // 下载内容 + _downloadAudio = result.Parameters.GetValue("downloadAudio"); + _downloadVideo = result.Parameters.GetValue("downloadVideo"); + _downloadDanmaku = result.Parameters.GetValue("downloadDanmaku"); + _downloadSubtitle = result.Parameters.GetValue("downloadSubtitle"); + _downloadCover = result.Parameters.GetValue("downloadCover"); }); - // await Task.Run(() => - // { - // while (true) - // { - // if (!run) break; - // Thread.Sleep(100); - // } - // }); } - if (directory == String.Empty) + if (directory == string.Empty) { return null; } @@ -234,7 +222,7 @@ public class AddToDownloadService // 下载设置dialog中如果点击取消或者关闭窗口, // 会返回空字符串, // 这时直接退出 - if (directory == null || directory == string.Empty) + if (string.IsNullOrEmpty(directory)) { return null; } @@ -252,33 +240,33 @@ public class AddToDownloadService /// 添加到下载列表 /// /// 传递事件的对象 + /// dialog /// 下载路径 /// 是否下载所有,包括未选中项 /// 添加的数量 - public int AddToDownload(IEventAggregator eventAggregator, string directory, bool isAll = false) + public async Task AddToDownload(IEventAggregator eventAggregator, IDialogService dialogService, string? directory, bool isAll = false) { - if (directory == null || directory == string.Empty) + if (string.IsNullOrEmpty(directory)) { return -1; } - if (videoSections == null) + if (_videoSections == null) { return -1; } // 视频计数 - int i = 0; - + var i = 0; // 添加到下载 - foreach (VideoSection section in videoSections) + foreach (var section in _videoSections) { if (section.VideoPages == null) { continue; } - foreach (VideoPage page in section.VideoPages) + foreach (var page in section.VideoPages) { // 只下载选中项,跳过未选中项 if (!isAll && !page.IsSelected) @@ -293,11 +281,11 @@ public class AddToDownloadService } // 判断VideoQuality - int retry = 0; + var retry = 0; while (page.VideoQuality == null && retry < 5) { // 执行解析任务 - videoInfoService.GetVideoStream(page); + _videoInfoService.GetVideoStream(page); retry++; } @@ -309,20 +297,18 @@ public class AddToDownloadService // 判断是否同一个视频,需要cid、画质、音质、视频编码都相同 // 如果存在正在下载列表,则跳过,并提示 - bool isDownloading = false; - foreach (DownloadingItem item in App.DownloadingList) + var isDownloading = false; + foreach (var item in App.DownloadingList) { if (item.DownloadBase == null) { continue; } - if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && - item.AudioCodec.Name == page.AudioQualityFormat && + if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && item.AudioCodec.Name == page.AudioQualityFormat && item.VideoCodecName == page.VideoQuality.SelectedVideoCodec) { - eventAggregator.GetEvent() - .Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloading")}"); + eventAggregator.GetEvent().Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloading")}"); isDownloading = true; break; } @@ -334,21 +320,59 @@ public class AddToDownloadService } // TODO 如果存在下载完成列表,弹出选择框是否再次下载 - bool isDownloaded = false; - foreach (DownloadedItem item in App.DownloadedList) + var isDownloaded = false; + foreach (var item in App.DownloadedList) { if (item.DownloadBase == null) { continue; } - if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && - item.AudioCodec.Name == page.AudioQualityFormat && + if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && item.AudioCodec.Name == page.AudioQualityFormat && item.VideoCodecName == page.VideoQuality.SelectedVideoCodec) { - eventAggregator.GetEvent() - .Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloaded")}"); - isDownloaded = true; + // eventAggregator.GetEvent().Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloaded")}"); + // isDownloaded = true; + var repeatDownloadStrategy = SettingsManager.GetInstance().GetRepeatDownloadStrategy(); + switch (repeatDownloadStrategy) + { + case RepeatDownloadStrategy.Ask: + { + var result = ButtonResult.Cancel; + await Dispatcher.UIThread.Invoke(async () => + { + var param = new DialogParameters + { + { "message", $"{item.Name}已下载,是否重新下载" }, + }; + + await dialogService.ShowDialogAsync(ViewAlreadyDownloadedDialogViewModel.Tag, param, + buttonResult => { result = buttonResult.Result; }); + }); + + if (result == ButtonResult.OK) + { + App.PropertyChangeAsync(() => { App.DownloadedList.Remove(item); }); + isDownloaded = false; + } + else + { + isDownloaded = true; + } + + break; + } + case RepeatDownloadStrategy.ReDownload: + isDownloaded = false; + break; + case RepeatDownloadStrategy.JumpOver: + isDownloaded = true; + break; + default: + isDownloaded = true; + break; + } + break; } } @@ -359,9 +383,9 @@ public class AddToDownloadService } // 视频分区 - int zoneId = -1; - List zoneList = VideoZone.Instance().GetZones(); - ZoneAttr zone = zoneList.Find(it => it.Id == videoInfoView.TypeId); + var zoneId = -1; + var zoneList = VideoZone.Instance().GetZones(); + var zone = zoneList.Find(it => it.Id == _videoInfoView.TypeId); if (zone != null) { if (zone.ParentId == 0) @@ -370,7 +394,7 @@ public class AddToDownloadService } else { - ZoneAttr zoneParent = zoneList.Find(it => it.Id == zone.ParentId); + var zoneParent = zoneList.Find(it => it.Id == zone.ParentId); if (zoneParent != null) { zoneId = zoneParent.Id; @@ -379,19 +403,19 @@ public class AddToDownloadService } // 如果只有一个视频章节,则不在命名中出现 - string sectionName = string.Empty; - if (videoSections.Count > 1) + var sectionName = string.Empty; + if (_videoSections.Count > 1) { sectionName = section.Title; } // 文件路径 - List fileNameParts = SettingsManager.GetInstance().GetFileNameParts(); - FileName fileName = FileName.Builder(fileNameParts) + var fileNameParts = SettingsManager.GetInstance().GetFileNameParts(); + var fileName = FileName.Builder(fileNameParts) .SetSection(Format.FormatFileName(sectionName)) - .SetMainTitle(Format.FormatFileName(videoInfoView.Title)) + .SetMainTitle(Format.FormatFileName(_videoInfoView.Title)) .SetPageTitle(Format.FormatFileName(page.Name)) - .SetVideoZone(videoInfoView.VideoZone.Split('>')[0]) + .SetVideoZone(_videoInfoView.VideoZone.Split('>')[0]) .SetAudioQuality(page.AudioQualityFormat) .SetVideoQuality(page.VideoQuality == null ? "" : page.VideoQuality.QualityFormat) .SetVideoCodec(page.VideoQuality == null ? "" : @@ -407,7 +431,7 @@ public class AddToDownloadService .SetUpName(Format.FormatFileName(page.Owner.Name)); // 序号设置 - OrderFormat orderFormat = SettingsManager.GetInstance().GetOrderFormat(); + var orderFormat = SettingsManager.GetInstance().GetOrderFormat(); switch (orderFormat) { case OrderFormat.NATURAL: @@ -419,11 +443,11 @@ public class AddToDownloadService } // 合成绝对路径 - string filePath = Path.Combine(directory, fileName.RelativePath()); + var filePath = Path.Combine(directory, fileName.RelativePath()); // 视频类别 PlayStreamType playStreamType; - switch (videoInfoView.TypeId) + switch (_videoInfoView.TypeId) { case -10: playStreamType = PlayStreamType.CHEESE; @@ -457,46 +481,42 @@ public class AddToDownloadService } // 添加到下载列表 - App.PropertyChangeAsync(new Action(() => + App.PropertyChangeAsync(() => { // 如果不存在,直接添加到下载列表 - DownloadBase downloadBase = new DownloadBase + var downloadBase = new DownloadBase { Bvid = page.Bvid, Avid = page.Avid, Cid = page.Cid, EpisodeId = page.EpisodeId, - CoverUrl = videoInfoView.CoverUrl, + CoverUrl = _videoInfoView.CoverUrl, PageCoverUrl = page.FirstFrame, ZoneId = zoneId, FilePath = filePath, Order = page.Order, - MainTitle = videoInfoView.Title, + MainTitle = _videoInfoView.Title, Name = page.Name, Duration = page.Duration, VideoCodecName = page.VideoQuality.SelectedVideoCodec, - Resolution = new Quality - { Name = page.VideoQuality.QualityFormat, Id = page.VideoQuality.Quality }, - AudioCodec = Constant.GetAudioQualities().FirstOrDefault(t => - { - return t.Name == page.AudioQualityFormat; - }), + Resolution = new Quality { Name = page.VideoQuality.QualityFormat, Id = page.VideoQuality.Quality }, + AudioCodec = Constant.GetAudioQualities().FirstOrDefault(t => { return t.Name == page.AudioQualityFormat; }) }; - Downloading downloading = new Downloading + var downloading = new Downloading { PlayStreamType = playStreamType, DownloadStatus = DownloadStatus.NOT_STARTED, }; // 需要下载的内容 - downloadBase.NeedDownloadContent["downloadAudio"] = downloadAudio; - downloadBase.NeedDownloadContent["downloadVideo"] = downloadVideo; - downloadBase.NeedDownloadContent["downloadDanmaku"] = downloadDanmaku; - downloadBase.NeedDownloadContent["downloadSubtitle"] = downloadSubtitle; - downloadBase.NeedDownloadContent["downloadCover"] = downloadCover; + downloadBase.NeedDownloadContent["downloadAudio"] = _downloadAudio; + downloadBase.NeedDownloadContent["downloadVideo"] = _downloadVideo; + downloadBase.NeedDownloadContent["downloadDanmaku"] = _downloadDanmaku; + downloadBase.NeedDownloadContent["downloadSubtitle"] = _downloadSubtitle; + downloadBase.NeedDownloadContent["downloadCover"] = _downloadCover; - DownloadingItem downloadingItem = new DownloadingItem + var downloadingItem = new DownloadingItem { DownloadBase = downloadBase, Downloading = downloading, @@ -505,7 +525,7 @@ public class AddToDownloadService App.DownloadingList.Add(downloadingItem); Thread.Sleep(10); - })); + }); i++; } } diff --git a/DownKyi/ViewModels/Dialogs/ViewAlreadyDownloadedDialogViewModel.cs b/DownKyi/ViewModels/Dialogs/ViewAlreadyDownloadedDialogViewModel.cs new file mode 100644 index 0000000..d0e728c --- /dev/null +++ b/DownKyi/ViewModels/Dialogs/ViewAlreadyDownloadedDialogViewModel.cs @@ -0,0 +1,66 @@ +using DownKyi.Images; +using Prism.Commands; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.Dialogs; + +public class ViewAlreadyDownloadedDialogViewModel : BaseDialogViewModel +{ + public const string Tag = "AlreadyDownloadedAlert"; + + #region 属性声明 + + private VectorImage? _image; + + public VectorImage? Image + { + get => _image; + set => SetProperty(ref _image, value); + } + + private string? _message; + + public string? Message + { + get => _message; + set => SetProperty(ref _message, value); + } + + #endregion + + public ViewAlreadyDownloadedDialogViewModel() + { + Title = "提示"; + Image = SystemIcon.Instance().Warning; + } + + #region 命令声明 + + private DelegateCommand? _yesCommand; + + public DelegateCommand YesCommand => _yesCommand ??= new DelegateCommand(ExecuteYesCommand); + + private void ExecuteYesCommand() + { + RaiseRequestClose(new DialogResult(ButtonResult.OK)); + } + + // 关闭窗口事件 + private DelegateCommand? _closeCommand; + public new DelegateCommand CloseCommand => _closeCommand ??= new DelegateCommand(ExecuteCloseCommand); + + /// + /// 关闭窗口事件 + /// + private void ExecuteCloseCommand() + { + RaiseRequestClose(new DialogResult(ButtonResult.Cancel)); + } + + #endregion + + public override void OnDialogOpened(IDialogParameters parameters) + { + Message = parameters.GetValue("message"); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Settings/ViewBasicViewModel.cs b/DownKyi/ViewModels/Settings/ViewBasicViewModel.cs index 1e6256e..39927c2 100644 --- a/DownKyi/ViewModels/Settings/ViewBasicViewModel.cs +++ b/DownKyi/ViewModels/Settings/ViewBasicViewModel.cs @@ -14,72 +14,88 @@ public class ViewBasicViewModel : ViewModelBase { public const string Tag = "PageSettingsBasic"; - private bool isOnNavigatedTo; + private bool _isOnNavigatedTo; #region 页面属性申明 - private bool none; + private bool _none; public bool None { - get { return none; } - set { SetProperty(ref none, value); } + get => _none; + set => SetProperty(ref _none, value); } - private bool closeApp; + private bool _closeApp; public bool CloseApp { - get { return closeApp; } - set { SetProperty(ref closeApp, value); } + get => _closeApp; + set => SetProperty(ref _closeApp, value); } - private bool closeSystem; + private bool _closeSystem; public bool CloseSystem { - get { return closeSystem; } - set { SetProperty(ref closeSystem, value); } + get => _closeSystem; + set => SetProperty(ref _closeSystem, value); } - private bool listenClipboard; + private bool _listenClipboard; public bool ListenClipboard { - get { return listenClipboard; } - set { SetProperty(ref listenClipboard, value); } + get => _listenClipboard; + set => SetProperty(ref _listenClipboard, value); } - private bool autoParseVideo; + private bool _autoParseVideo; public bool AutoParseVideo { - get { return autoParseVideo; } - set { SetProperty(ref autoParseVideo, value); } + get => _autoParseVideo; + set => SetProperty(ref _autoParseVideo, value); } - private List parseScopes; + private List _parseScopes; public List ParseScopes { - get { return parseScopes; } - set { SetProperty(ref parseScopes, value); } + get => _parseScopes; + set => SetProperty(ref _parseScopes, value); } - private ParseScopeDisplay selectedParseScope; + private ParseScopeDisplay _selectedParseScope; public ParseScopeDisplay SelectedParseScope { - get { return selectedParseScope; } - set { SetProperty(ref selectedParseScope, value); } + get => _selectedParseScope; + set => SetProperty(ref _selectedParseScope, value); } - private bool autoDownloadAll; + private bool _autoDownloadAll; public bool AutoDownloadAll { - get => autoDownloadAll; - set => SetProperty(ref autoDownloadAll, value); + get => _autoDownloadAll; + set => SetProperty(ref _autoDownloadAll, value); + } + + private List _repeatDownloadStrategy; + + public List RepeatDownloadStrategy + { + get => _repeatDownloadStrategy; + set => SetProperty(ref _repeatDownloadStrategy, value); + } + + private RepeatDownloadStrategyDisplay _selectedRepeatDownloadStrategy; + + public RepeatDownloadStrategyDisplay SelectedRepeatDownloadStrategy + { + get => _selectedRepeatDownloadStrategy; + set => SetProperty(ref _selectedRepeatDownloadStrategy, value); } #endregion @@ -89,14 +105,19 @@ public class ViewBasicViewModel : ViewModelBase #region 属性初始化 // 解析范围 - ParseScopes = new List() + ParseScopes = new List { - new ParseScopeDisplay { Name = DictionaryResource.GetString("ParseNone"), ParseScope = ParseScope.NONE }, - new ParseScopeDisplay - { Name = DictionaryResource.GetString("ParseSelectedItem"), ParseScope = ParseScope.SELECTED_ITEM }, - new ParseScopeDisplay - { Name = DictionaryResource.GetString("ParseCurrentSection"), ParseScope = ParseScope.CURRENT_SECTION }, - new ParseScopeDisplay { Name = DictionaryResource.GetString("ParseAll"), ParseScope = ParseScope.ALL } + new() { Name = DictionaryResource.GetString("ParseNone"), ParseScope = ParseScope.NONE }, + new() { Name = DictionaryResource.GetString("ParseSelectedItem"), ParseScope = ParseScope.SELECTED_ITEM }, + new() { Name = DictionaryResource.GetString("ParseCurrentSection"), ParseScope = ParseScope.CURRENT_SECTION }, + new() { Name = DictionaryResource.GetString("ParseAll"), ParseScope = ParseScope.ALL } + }; + + RepeatDownloadStrategy = new List + { + new() { Name = DictionaryResource.GetString("RepeatDownloadAsk"), RepeatDownloadStrategy = Core.Settings.RepeatDownloadStrategy.Ask }, + new() { Name = DictionaryResource.GetString("RepeatDownloadReDownload"), RepeatDownloadStrategy = Core.Settings.RepeatDownloadStrategy.ReDownload }, + new() { Name = DictionaryResource.GetString("RepeatDownloadReJumpOver"), RepeatDownloadStrategy = Core.Settings.RepeatDownloadStrategy.JumpOver } }; #endregion @@ -110,40 +131,41 @@ public class ViewBasicViewModel : ViewModelBase { base.OnNavigatedTo(navigationContext); - isOnNavigatedTo = true; + _isOnNavigatedTo = true; // 下载完成后的操作 - AfterDownloadOperation afterDownload = SettingsManager.GetInstance().GetAfterDownloadOperation(); + var afterDownload = SettingsManager.GetInstance().GetAfterDownloadOperation(); SetAfterDownloadOperation(afterDownload); // 是否监听剪贴板 - AllowStatus isListenClipboard = SettingsManager.GetInstance().IsListenClipboard(); + var isListenClipboard = SettingsManager.GetInstance().IsListenClipboard(); ListenClipboard = isListenClipboard == AllowStatus.YES; // 是否自动解析视频 - AllowStatus isAutoParseVideo = SettingsManager.GetInstance().IsAutoParseVideo(); + var isAutoParseVideo = SettingsManager.GetInstance().IsAutoParseVideo(); AutoParseVideo = isAutoParseVideo == AllowStatus.YES; // 解析范围 - ParseScope parseScope = SettingsManager.GetInstance().GetParseScope(); + var parseScope = SettingsManager.GetInstance().GetParseScope(); SelectedParseScope = ParseScopes.FirstOrDefault(t => { return t.ParseScope == parseScope; }); // 解析后是否自动下载解析视频 - AllowStatus isAutoDownloadAll = SettingsManager.GetInstance().IsAutoDownloadAll(); + var isAutoDownloadAll = SettingsManager.GetInstance().IsAutoDownloadAll(); AutoDownloadAll = isAutoDownloadAll == AllowStatus.YES; - isOnNavigatedTo = false; + // 重复下载策略 + var repeatDownloadStrategy = SettingsManager.GetInstance().GetRepeatDownloadStrategy(); + SelectedRepeatDownloadStrategy = RepeatDownloadStrategy.FirstOrDefault(t => { return t.RepeatDownloadStrategy == repeatDownloadStrategy; }); + + _isOnNavigatedTo = false; } #region 命令申明 // 下载完成后的操作事件 - private DelegateCommand afterDownloadOperationCommand; + private DelegateCommand? _afterDownloadOperationCommand; - public DelegateCommand AfterDownloadOperationCommand => afterDownloadOperationCommand ?? - (afterDownloadOperationCommand = - new DelegateCommand( - ExecuteAfterDownloadOperationCommand)); + public DelegateCommand AfterDownloadOperationCommand => _afterDownloadOperationCommand ??= new DelegateCommand(ExecuteAfterDownloadOperationCommand); /// /// 下载完成后的操作事件 @@ -167,51 +189,45 @@ public class ViewBasicViewModel : ViewModelBase break; } - bool isSucceed = SettingsManager.GetInstance().SetAfterDownloadOperation(afterDownload); + var isSucceed = SettingsManager.GetInstance().SetAfterDownloadOperation(afterDownload); PublishTip(isSucceed); } // 是否监听剪贴板事件 - private DelegateCommand listenClipboardCommand; + private DelegateCommand? _listenClipboardCommand; - public DelegateCommand ListenClipboardCommand => listenClipboardCommand ?? - (listenClipboardCommand = - new DelegateCommand(ExecuteListenClipboardCommand)); + public DelegateCommand ListenClipboardCommand => _listenClipboardCommand ??= new DelegateCommand(ExecuteListenClipboardCommand); /// /// 是否监听剪贴板事件 /// private void ExecuteListenClipboardCommand() { - AllowStatus isListenClipboard = ListenClipboard ? AllowStatus.YES : AllowStatus.NO; + var isListenClipboard = ListenClipboard ? AllowStatus.YES : AllowStatus.NO; - bool isSucceed = SettingsManager.GetInstance().IsListenClipboard(isListenClipboard); + var isSucceed = SettingsManager.GetInstance().IsListenClipboard(isListenClipboard); PublishTip(isSucceed); } - private DelegateCommand autoParseVideoCommand; + private DelegateCommand? _autoParseVideoCommand; - public DelegateCommand AutoParseVideoCommand => autoParseVideoCommand ?? - (autoParseVideoCommand = - new DelegateCommand(ExecuteAutoParseVideoCommand)); + public DelegateCommand AutoParseVideoCommand => _autoParseVideoCommand ??= new DelegateCommand(ExecuteAutoParseVideoCommand); /// /// 是否自动解析视频 /// private void ExecuteAutoParseVideoCommand() { - AllowStatus isAutoParseVideo = AutoParseVideo ? AllowStatus.YES : AllowStatus.NO; + var isAutoParseVideo = AutoParseVideo ? AllowStatus.YES : AllowStatus.NO; - bool isSucceed = SettingsManager.GetInstance().IsAutoParseVideo(isAutoParseVideo); + var isSucceed = SettingsManager.GetInstance().IsAutoParseVideo(isAutoParseVideo); PublishTip(isSucceed); } // 解析范围事件 - private DelegateCommand parseScopesCommand; + private DelegateCommand? _parseScopesCommand; - public DelegateCommand ParseScopesCommand => parseScopesCommand ?? - (parseScopesCommand = - new DelegateCommand(ExecuteParseScopesCommand)); + public DelegateCommand ParseScopesCommand => _parseScopesCommand ??= new DelegateCommand(ExecuteParseScopesCommand); /// /// 解析范围事件 @@ -219,30 +235,48 @@ public class ViewBasicViewModel : ViewModelBase /// private void ExecuteParseScopesCommand(object parameter) { - if (!(parameter is ParseScopeDisplay parseScope)) + if (parameter is not ParseScopeDisplay parseScope) { return; } - bool isSucceed = SettingsManager.GetInstance().SetParseScope(parseScope.ParseScope); + var isSucceed = SettingsManager.GetInstance().SetParseScope(parseScope.ParseScope); PublishTip(isSucceed); } // 解析后是否自动下载解析视频 - private DelegateCommand autoDownloadAllCommand; + private DelegateCommand? _autoDownloadAllCommand; - public DelegateCommand AutoDownloadAllCommand => autoDownloadAllCommand ?? - (autoDownloadAllCommand = - new DelegateCommand(ExecuteAutoDownloadAllCommand)); + public DelegateCommand AutoDownloadAllCommand => _autoDownloadAllCommand ??= new DelegateCommand(ExecuteAutoDownloadAllCommand); /// /// 解析后是否自动下载解析视频 /// private void ExecuteAutoDownloadAllCommand() { - AllowStatus isAutoDownloadAll = AutoDownloadAll ? AllowStatus.YES : AllowStatus.NO; + var isAutoDownloadAll = AutoDownloadAll ? AllowStatus.YES : AllowStatus.NO; - bool isSucceed = SettingsManager.GetInstance().IsAutoDownloadAll(isAutoDownloadAll); + var isSucceed = SettingsManager.GetInstance().IsAutoDownloadAll(isAutoDownloadAll); + PublishTip(isSucceed); + } + + // 解析范围事件 + private DelegateCommand? _repeatDownloadStrategyCommand; + + public DelegateCommand RepeatDownloadStrategyCommand => _repeatDownloadStrategyCommand ??= new DelegateCommand(ExecuteRepeatDownloadStrategyCommand); + + /// + /// 解析范围事件 + /// + /// + private void ExecuteRepeatDownloadStrategyCommand(object parameter) + { + if (parameter is not RepeatDownloadStrategyDisplay repeatDownloadStrategy) + { + return; + } + + var isSucceed = SettingsManager.GetInstance().SetRepeatDownloadStrategy(repeatDownloadStrategy.RepeatDownloadStrategy); PublishTip(isSucceed); } @@ -276,7 +310,7 @@ public class ViewBasicViewModel : ViewModelBase /// private void PublishTip(bool isSucceed) { - if (isOnNavigatedTo) + if (_isOnNavigatedTo) { return; } diff --git a/DownKyi/Views/Dialogs/ViewAlreadyDownloadedDialog.axaml b/DownKyi/Views/Dialogs/ViewAlreadyDownloadedDialog.axaml new file mode 100644 index 0000000..10e4403 --- /dev/null +++ b/DownKyi/Views/Dialogs/ViewAlreadyDownloadedDialog.axaml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +