mirror of
https://github.com/leiurayer/downkyi.git
synced 2025-01-28 04:40:21 +08:00
添加首页搜索框服务、剪贴板服务,修复一些问题
This commit is contained in:
parent
9392c10779
commit
f01c44a473
@ -50,13 +50,16 @@ public partial class SettingsManager
|
||||
/// <returns></returns>
|
||||
private AppSettings GetSettings()
|
||||
{
|
||||
if (appSettings != null) { return appSettings; }
|
||||
|
||||
try
|
||||
{
|
||||
var fileStream = new FileStream(settingsName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
var streamReader = new StreamReader(fileStream, System.Text.Encoding.UTF8);
|
||||
string jsonWordTemplate = streamReader.ReadToEnd();
|
||||
streamReader.Close();
|
||||
fileStream.Close();
|
||||
string jsonWordTemplate = string.Empty;
|
||||
using (var stream = new FileStream(settingsName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
|
||||
{
|
||||
using var reader = new StreamReader(stream, System.Text.Encoding.UTF8);
|
||||
jsonWordTemplate = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
|
@ -9,8 +9,12 @@ public class BaseServices
|
||||
|
||||
public INotificationEvent NotificationEvent { get; }
|
||||
|
||||
public IClipboardService ClipboardService { get; }
|
||||
|
||||
public IDictionaryResource DictionaryResource { get; }
|
||||
|
||||
public IMainSearchService MainSearchService { get; }
|
||||
|
||||
public INavigationService NavigationService { get; }
|
||||
|
||||
public IStoragePicker StoragePicker { get; }
|
||||
@ -19,14 +23,18 @@ public class BaseServices
|
||||
|
||||
public BaseServices(IBroadcastEvent broadcastEvent,
|
||||
INotificationEvent notificationEvent,
|
||||
IClipboardService clipboardService,
|
||||
IDictionaryResource dictionaryResource,
|
||||
IMainSearchService mainSearchService,
|
||||
INavigationService navigationService,
|
||||
IStoragePicker storagePicker,
|
||||
IStorageService storageService)
|
||||
{
|
||||
BroadcastEvent = broadcastEvent;
|
||||
NotificationEvent = notificationEvent;
|
||||
ClipboardService = clipboardService;
|
||||
DictionaryResource = dictionaryResource;
|
||||
MainSearchService = mainSearchService;
|
||||
NavigationService = navigationService;
|
||||
StoragePicker = storagePicker;
|
||||
StorageService = storageService;
|
||||
|
@ -5,4 +5,4 @@ public interface INavigationAware
|
||||
void OnNavigatedTo(Dictionary<string, object>? parameter);
|
||||
|
||||
void OnNavigatedFrom(Dictionary<string, object>? parameter);
|
||||
}
|
||||
}
|
@ -11,7 +11,9 @@ public abstract class ViewModelBase : ObservableObject, INavigationAware
|
||||
|
||||
protected IBroadcastEvent BroadcastEvent => _baseServices.BroadcastEvent;
|
||||
protected INotificationEvent NotificationEvent => _baseServices.NotificationEvent;
|
||||
protected IClipboardService ClipboardService => _baseServices.ClipboardService;
|
||||
protected IDictionaryResource DictionaryResource => _baseServices.DictionaryResource;
|
||||
protected IMainSearchService MainSearchService => _baseServices.MainSearchService;
|
||||
protected INavigationService NavigationService => _baseServices.NavigationService;
|
||||
protected IStoragePicker StoragePicker => _baseServices.StoragePicker;
|
||||
protected IStorageService StorageService => _baseServices.StorageService;
|
||||
|
6
src/Downkyi.UI/Services/IClipboardService.cs
Normal file
6
src/Downkyi.UI/Services/IClipboardService.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Downkyi.UI.Services;
|
||||
|
||||
public interface IClipboardService
|
||||
{
|
||||
Task<string> GetTextAsync();
|
||||
}
|
28
src/Downkyi.UI/Services/IMainSearchService.cs
Normal file
28
src/Downkyi.UI/Services/IMainSearchService.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace Downkyi.UI.Services;
|
||||
|
||||
public interface IMainSearchService
|
||||
{
|
||||
/// <summary>
|
||||
/// 解析支持的输入,
|
||||
/// 支持的格式有:<para/>
|
||||
/// av号:av170001, AV170001, https://www.bilibili.com/video/av170001 <para/>
|
||||
/// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC <para/>
|
||||
/// 番剧(电影、电视剧)ss号:ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982 <para/>
|
||||
/// 番剧(电影、电视剧)ep号:ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925 <para/>
|
||||
/// 番剧(电影、电视剧)md号:md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367 <para/>
|
||||
/// 课程ss号:https://www.bilibili.com/cheese/play/ss205 <para/>
|
||||
/// 课程ep号:https://www.bilibili.com/cheese/play/ep3489 <para/>
|
||||
/// 收藏夹:ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876, https://www.bilibili.com/medialist/play/ml1329019876/ <para/>
|
||||
/// 用户空间:uid928123, UID928123, uid:928123, UID:928123, https://space.bilibili.com/928123
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
bool BiliInput(string input);
|
||||
|
||||
/// <summary>
|
||||
/// 搜索关键词
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
bool SearchKey(string input);
|
||||
}
|
140
src/Downkyi.UI/Services/MainSearchService.cs
Normal file
140
src/Downkyi.UI/Services/MainSearchService.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using Downkyi.Core.Bili.Utils;
|
||||
using Downkyi.Core.Settings;
|
||||
using Downkyi.Core.Settings.Models;
|
||||
using Downkyi.UI.ViewModels.User;
|
||||
using Downkyi.UI.ViewModels.Video;
|
||||
|
||||
namespace Downkyi.UI.Services;
|
||||
|
||||
public class MainSearchService : IMainSearchService
|
||||
{
|
||||
private readonly INavigationService NavigationService;
|
||||
|
||||
public MainSearchService(INavigationService navigationService)
|
||||
{
|
||||
NavigationService = navigationService;
|
||||
}
|
||||
|
||||
public bool BiliInput(string input)
|
||||
{
|
||||
// 移除剪贴板id
|
||||
//string validId = input.Replace(AppConstant.ClipboardId, "");
|
||||
|
||||
string validId = input;
|
||||
|
||||
// 参数
|
||||
Dictionary<string, object> parameter = new()
|
||||
{
|
||||
{ "key", "MainSearchService" },
|
||||
{ "value", new object() },
|
||||
};
|
||||
|
||||
// 视频
|
||||
if (ParseEntrance.IsAvId(validId))
|
||||
{
|
||||
parameter["value"] = $"{ParseEntrance.VideoUrl}{validId.ToLower()}";
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsAvUrl(validId))
|
||||
{
|
||||
parameter["value"] = validId;
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsBvId(validId))
|
||||
{
|
||||
parameter["value"] = $"{ParseEntrance.VideoUrl}{input}";
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsBvUrl(validId))
|
||||
{
|
||||
parameter["value"] = validId;
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
// 番剧(电影、电视剧)
|
||||
else if (ParseEntrance.IsBangumiSeasonId(validId))
|
||||
{
|
||||
parameter["value"] = $"{ParseEntrance.BangumiUrl}{input.ToLower()}";
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsBangumiSeasonUrl(validId))
|
||||
{
|
||||
parameter["value"] = validId;
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsBangumiEpisodeId(validId))
|
||||
{
|
||||
parameter["value"] = $"{ParseEntrance.BangumiUrl}{input.ToLower()}";
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsBangumiEpisodeUrl(validId))
|
||||
{
|
||||
parameter["value"] = validId;
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsBangumiMediaId(validId))
|
||||
{
|
||||
parameter["value"] = $"{ParseEntrance.BangumiMediaUrl}{input.ToLower()}";
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
else if (ParseEntrance.IsBangumiMediaUrl(validId))
|
||||
{
|
||||
parameter["value"] = validId;
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
// 课程
|
||||
else if (ParseEntrance.IsCheeseSeasonUrl(validId)
|
||||
|| ParseEntrance.IsCheeseEpisodeUrl(validId))
|
||||
{
|
||||
parameter["value"] = validId;
|
||||
NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
|
||||
}
|
||||
// 用户(参数传入mid)
|
||||
else if (ParseEntrance.IsUserId(validId) || ParseEntrance.IsUserUrl(validId))
|
||||
{
|
||||
NavigateToViewUserSpace(ParseEntrance.GetUserId(input));
|
||||
}
|
||||
// 收藏夹
|
||||
else if (ParseEntrance.IsFavoritesId(validId) || ParseEntrance.IsFavoritesUrl(validId))
|
||||
{
|
||||
parameter["value"] = ParseEntrance.GetFavoritesId(input);
|
||||
NavigationService.ForwardAsync(PublicFavoritesViewModel.Key, parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SearchKey(string input)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航到用户空间,
|
||||
/// 如果传入的mid与本地登录的mid一致,
|
||||
/// 则进入我的用户空间。
|
||||
/// </summary>
|
||||
/// <param name="mid"></param>
|
||||
private void NavigateToViewUserSpace(long mid)
|
||||
{
|
||||
Dictionary<string, object> parameter = new()
|
||||
{
|
||||
{ "key", "MainSearchService" },
|
||||
{ "value", mid },
|
||||
};
|
||||
|
||||
UserInfoSettings userInfo = SettingsManager.GetInstance().GetUserInfo();
|
||||
if (userInfo != null && userInfo.Mid == mid)
|
||||
{
|
||||
NavigationService.ForwardAsync(MySpaceViewModel.Key, parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationService.ForwardAsync(UserSpaceViewModel.Key, parameter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,18 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Downkyi.Core.Bili;
|
||||
using Downkyi.Core.Log;
|
||||
using Downkyi.Core.Settings;
|
||||
using Downkyi.Core.Settings.Models;
|
||||
using Downkyi.Core.Storage;
|
||||
using Downkyi.UI.Mvvm;
|
||||
using Downkyi.UI.Services;
|
||||
using Downkyi.UI.ViewModels.DownloadManager;
|
||||
using Downkyi.UI.ViewModels.Login;
|
||||
using Downkyi.UI.ViewModels.Settings;
|
||||
using Downkyi.UI.ViewModels.Toolbox;
|
||||
using Downkyi.UI.ViewModels.User;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Downkyi.UI.ViewModels;
|
||||
|
||||
@ -115,9 +118,29 @@ public partial class IndexViewModel : ViewModelBase
|
||||
|
||||
#region 业务逻辑
|
||||
|
||||
/// <summary>
|
||||
/// 进入B站链接的处理逻辑,
|
||||
/// 只负责处理输入,并跳转到视频详情页。<para/>
|
||||
/// 不是支持的格式,则进入搜索页面。
|
||||
/// </summary>
|
||||
private void EnterBili()
|
||||
{
|
||||
NotificationEvent.Publish("Enter Bili!");
|
||||
if (InputText == string.Empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Log.Logger.Debug(InputText);
|
||||
|
||||
InputText = Regex.Replace(InputText, @"[【]*[^【]*[^】]*[】 ]", "");
|
||||
|
||||
bool isSupport = MainSearchService.BiliInput(InputText);
|
||||
if (!isSupport)
|
||||
{
|
||||
// 关键词搜索
|
||||
MainSearchService.SearchKey(InputText);
|
||||
}
|
||||
|
||||
InputText = string.Empty;
|
||||
}
|
||||
|
||||
private async Task UpdateUserInfo()
|
||||
|
@ -114,14 +114,11 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
for (int i = 1; i <= 10; i++) { Splits.Add(i); }
|
||||
|
||||
// Aria的日志等级
|
||||
AriaLogLevels = new List<string>
|
||||
{
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"NOTICE",
|
||||
"WARN",
|
||||
"ERROR"
|
||||
};
|
||||
AriaLogLevels.Add("DEBUG");
|
||||
AriaLogLevels.Add("INFO");
|
||||
AriaLogLevels.Add("NOTICE");
|
||||
AriaLogLevels.Add("WARN");
|
||||
AriaLogLevels.Add("ERROR");
|
||||
|
||||
// Aria同时下载数
|
||||
for (int i = 1; i <= 10; i++) { AriaMaxConcurrentDownloads.Add(i); }
|
||||
@ -130,12 +127,9 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
for (int i = 1; i <= 10; i++) { AriaSplits.Add(i); }
|
||||
|
||||
// Aria文件预分配
|
||||
AriaFileAllocations = new List<string>
|
||||
{
|
||||
"NONE",
|
||||
"PREALLOC",
|
||||
"FALLOC"
|
||||
};
|
||||
AriaFileAllocations.Add("NONE");
|
||||
AriaFileAllocations.Add("PREALLOC");
|
||||
AriaFileAllocations.Add("FALLOC");
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -288,10 +282,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
[RelayCommand]
|
||||
private void SetMaxCurrentDownloads(object parameter)
|
||||
private void SetMaxCurrentDownloads()
|
||||
{
|
||||
SelectedMaxCurrentDownload = (int)parameter;
|
||||
|
||||
bool isSucceed = SettingsManager.GetInstance().SetMaxCurrentDownloads(SelectedMaxCurrentDownload);
|
||||
PublishTip(Key, isSucceed);
|
||||
}
|
||||
@ -301,10 +293,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
[RelayCommand]
|
||||
private void SetSplits(object parameter)
|
||||
private void SetSplits()
|
||||
{
|
||||
SelectedSplit = (int)parameter;
|
||||
|
||||
bool isSucceed = SettingsManager.GetInstance().SetSplit(SelectedSplit);
|
||||
PublishTip(Key, isSucceed);
|
||||
}
|
||||
@ -389,9 +379,9 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
[RelayCommand]
|
||||
private void SetAriaLogLevels(string parameter)
|
||||
private void SetAriaLogLevels()
|
||||
{
|
||||
var ariaLogLevel = parameter switch
|
||||
var ariaLogLevel = SelectedAriaLogLevel switch
|
||||
{
|
||||
"DEBUG" => AriaConfigLogLevel.DEBUG,
|
||||
"INFO" => AriaConfigLogLevel.INFO,
|
||||
@ -409,10 +399,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
[RelayCommand]
|
||||
private void SetAriaMaxConcurrentDownloads(object parameter)
|
||||
private void SetAriaMaxConcurrentDownloads()
|
||||
{
|
||||
SelectedAriaMaxConcurrentDownload = (int)parameter;
|
||||
|
||||
bool isSucceed = SettingsManager.GetInstance().SetMaxCurrentDownloads(SelectedAriaMaxConcurrentDownload);
|
||||
PublishTip(Key, isSucceed);
|
||||
}
|
||||
@ -422,10 +410,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
[RelayCommand]
|
||||
private void SetAriaSplits(object parameter)
|
||||
private void SetAriaSplits()
|
||||
{
|
||||
SelectedAriaSplit = (int)parameter;
|
||||
|
||||
bool isSucceed = SettingsManager.GetInstance().SetAriaSplit(SelectedAriaSplit);
|
||||
PublishTip(Key, isSucceed);
|
||||
}
|
||||
@ -498,11 +484,10 @@ public partial class NetworkViewModel : BaseSettingsViewModel
|
||||
/// <summary>
|
||||
/// Aria文件预分配事件
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
[RelayCommand]
|
||||
private void SetAriaFileAllocations(string parameter)
|
||||
private void SetAriaFileAllocations()
|
||||
{
|
||||
var ariaFileAllocation = parameter switch
|
||||
var ariaFileAllocation = SelectedAriaFileAllocation switch
|
||||
{
|
||||
"NONE" => AriaConfigFileAllocation.NONE,
|
||||
"PREALLOC" => AriaConfigFileAllocation.PREALLOC,
|
||||
|
29
src/Downkyi.UI/ViewModels/Video/PublicFavoritesViewModel.cs
Normal file
29
src/Downkyi.UI/ViewModels/Video/PublicFavoritesViewModel.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Downkyi.UI.Mvvm;
|
||||
|
||||
namespace Downkyi.UI.ViewModels.Video;
|
||||
|
||||
public partial class PublicFavoritesViewModel : ViewModelBase
|
||||
{
|
||||
public const string Key = "PublicFavorites";
|
||||
|
||||
public PublicFavoritesViewModel(BaseServices baseServices) : base(baseServices)
|
||||
{
|
||||
}
|
||||
|
||||
#region 命令申明
|
||||
|
||||
[RelayCommand(FlowExceptionsToTaskScheduler = true)]
|
||||
private async Task BackwardAsync()
|
||||
{
|
||||
Dictionary<string, object> parameter = new()
|
||||
{
|
||||
{ "key", Key },
|
||||
};
|
||||
|
||||
await NavigationService.BackwardAsync(parameter);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
29
src/Downkyi.UI/ViewModels/Video/VideoDetailViewModel.cs
Normal file
29
src/Downkyi.UI/ViewModels/Video/VideoDetailViewModel.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Downkyi.UI.Mvvm;
|
||||
|
||||
namespace Downkyi.UI.ViewModels.Video;
|
||||
|
||||
public partial class VideoDetailViewModel : ViewModelBase
|
||||
{
|
||||
public const string Key = "VideoDetail";
|
||||
|
||||
public VideoDetailViewModel(BaseServices baseServices) : base(baseServices)
|
||||
{
|
||||
}
|
||||
|
||||
#region 命令申明
|
||||
|
||||
[RelayCommand(FlowExceptionsToTaskScheduler = true)]
|
||||
private async Task BackwardAsync()
|
||||
{
|
||||
Dictionary<string, object> parameter = new()
|
||||
{
|
||||
{ "key", Key },
|
||||
};
|
||||
|
||||
await NavigationService.BackwardAsync(parameter);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
@ -9,6 +9,7 @@ using Downkyi.UI.ViewModels.Login;
|
||||
using Downkyi.UI.ViewModels.Settings;
|
||||
using Downkyi.UI.ViewModels.Toolbox;
|
||||
using Downkyi.UI.ViewModels.User;
|
||||
using Downkyi.UI.ViewModels.Video;
|
||||
using Downkyi.ViewModels;
|
||||
using Downkyi.ViewModels.Login;
|
||||
using Downkyi.ViewModels.Settings;
|
||||
@ -92,31 +93,41 @@ public static class ServiceLocator
|
||||
.AddScoped<BaseServices>()
|
||||
.AddSingleton<IBroadcastEvent, BroadcastEvent>()
|
||||
.AddSingleton<INotificationEvent, NotificationEvent>()
|
||||
.AddSingleton<IClipboardService, ClipboardService>()
|
||||
.AddSingleton<IDictionaryResource, DictionaryResource>()
|
||||
.AddSingleton<IMainSearchService, MainSearchService>()
|
||||
.AddSingleton<INavigationService, NavigationService>()
|
||||
.AddSingleton<IStoragePicker, StoragePicker>()
|
||||
.AddSingleton<IStorageService, StorageService>()
|
||||
//ViewModels
|
||||
.AddSingleton<MainWindowViewModel>()
|
||||
.AddSingleton<IndexViewModel>()
|
||||
//
|
||||
.AddSingleton<DownloadManagerViewModel>()
|
||||
.AddSingleton<DownloadingViewModel>()
|
||||
.AddSingleton<DownloadFinishedViewModel>()
|
||||
//
|
||||
.AddSingleton<LoginViewModel>()
|
||||
.AddSingleton<QRCodeViewModelProxy>()
|
||||
.AddSingleton<CookiesViewModel>()
|
||||
.AddSingleton<MySpaceViewModel>()
|
||||
.AddSingleton<UserSpaceViewModel>()
|
||||
//
|
||||
.AddSingleton<SettingsViewModel>()
|
||||
.AddSingleton<BasicViewModel>()
|
||||
.AddSingleton<NetworkViewModel>()
|
||||
.AddSingleton<VideoViewModelProxy>()
|
||||
.AddSingleton<DanmakuViewModelProxy>()
|
||||
.AddSingleton<AboutViewModelProxy>()
|
||||
.AddSingleton<DownloadManagerViewModel>()
|
||||
.AddSingleton<DownloadingViewModel>()
|
||||
.AddSingleton<DownloadFinishedViewModel>()
|
||||
//
|
||||
.AddSingleton<ToolboxViewModel>()
|
||||
.AddSingleton<BiliHelperViewModel>()
|
||||
.AddSingleton<DelogoViewModelProxy>()
|
||||
.AddSingleton<ExtractMediaViewModelProxy>()
|
||||
//
|
||||
.AddSingleton<MySpaceViewModel>()
|
||||
.AddSingleton<UserSpaceViewModel>()
|
||||
//
|
||||
.AddSingleton<VideoDetailViewModel>()
|
||||
.AddSingleton<PublicFavoritesViewModel>()
|
||||
.BuildServiceProvider());
|
||||
}
|
||||
}
|
||||
|
19
src/Downkyi/Services/ClipboardService.cs
Normal file
19
src/Downkyi/Services/ClipboardService.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Downkyi.UI.Services;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Downkyi.Services;
|
||||
|
||||
public class ClipboardService : IClipboardService
|
||||
{
|
||||
public async Task<string> GetTextAsync()
|
||||
{
|
||||
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop ||
|
||||
desktop.MainWindow?.Clipboard is not { } provider)
|
||||
throw new NullReferenceException("Missing Clipboard instance.");
|
||||
|
||||
return await provider.GetTextAsync() ?? string.Empty;
|
||||
}
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Downkyi.Core.Settings;
|
||||
using Downkyi.Core.Settings.Enum;
|
||||
using Downkyi.Core.Utils;
|
||||
using Downkyi.UI.Mvvm;
|
||||
using Downkyi.UI.ViewModels;
|
||||
@ -8,8 +13,10 @@ using Downkyi.UI.ViewModels.Login;
|
||||
using Downkyi.UI.ViewModels.Settings;
|
||||
using Downkyi.UI.ViewModels.Toolbox;
|
||||
using Downkyi.UI.ViewModels.User;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Downkyi.ViewModels;
|
||||
|
||||
@ -19,6 +26,8 @@ public partial class MainWindowViewModel : ViewModelBase
|
||||
|
||||
private readonly LinkStack<string> _pages = new();
|
||||
|
||||
private readonly CancellationTokenSource? tokenSource;
|
||||
|
||||
#region 页面属性申明
|
||||
|
||||
[ObservableProperty]
|
||||
@ -55,8 +64,61 @@ public partial class MainWindowViewModel : ViewModelBase
|
||||
MessageVisibility = false;
|
||||
});
|
||||
|
||||
// 监听剪贴板线程
|
||||
string oldClip = string.Empty;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
CancellationToken cancellationToken = tokenSource!.Token;
|
||||
|
||||
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop ||
|
||||
desktop.MainWindow?.Clipboard is not { } provider)
|
||||
throw new NullReferenceException("Missing Clipboard instance.");
|
||||
await provider.SetTextAsync(oldClip);
|
||||
|
||||
while (true)
|
||||
{
|
||||
AllowStatus isListenClipboard = SettingsManager.GetInstance().IsListenClipboard();
|
||||
if (isListenClipboard != AllowStatus.YES)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断是否该结束线程,若为true,跳出while循环
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
string clip = await ClipboardService.GetTextAsync();
|
||||
if (clip.Equals(oldClip))
|
||||
{
|
||||
await Task.Delay(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
oldClip = clip;
|
||||
MainSearchService.BiliInput(clip);
|
||||
}
|
||||
}
|
||||
}, (tokenSource = new CancellationTokenSource()).Token);
|
||||
|
||||
}
|
||||
|
||||
#region 命令申明
|
||||
|
||||
/// <summary>
|
||||
/// 退出窗口时执行
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void OnClosing()
|
||||
{
|
||||
// 取消任务
|
||||
tokenSource?.Cancel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Forward(string viewKey, Dictionary<string, object>? parameter = null)
|
||||
{
|
||||
var viewModel = SetContent(viewKey);
|
||||
|
@ -2,6 +2,8 @@
|
||||
x:Class="Downkyi.Views.MainWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
|
||||
xmlns:ia="clr-namespace:Avalonia.Xaml.Interactions.Core;assembly=Avalonia.Xaml.Interactions"
|
||||
xmlns:local="using:Downkyi"
|
||||
xmlns:vm="using:Downkyi.ViewModels"
|
||||
Title="{DynamicResource AppName}"
|
||||
@ -14,6 +16,11 @@
|
||||
Design.DataContext="{x:Static local:ServiceLocator.MainWindowViewModel}"
|
||||
Icon="/Assets/logo.ico"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
<i:Interaction.Behaviors>
|
||||
<ia:EventTriggerBehavior EventName="Closing">
|
||||
<ia:InvokeCommandAction Command="{Binding ClosingCommand}" />
|
||||
</ia:EventTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
|
||||
<Grid>
|
||||
<ContentControl Content="{Binding Content}" />
|
||||
|
@ -87,15 +87,14 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource MaxCurrentDownloads}" />
|
||||
<ComboBox
|
||||
Name="maxCurrentDownloads"
|
||||
Width="100"
|
||||
VerticalContentAlignment="Center"
|
||||
Classes="normal"
|
||||
ItemsSource="{Binding MaxCurrentDownloads}"
|
||||
SelectedValue="{Binding SelectedMaxCurrentDownload}">
|
||||
SelectedItem="{Binding SelectedMaxCurrentDownload}">
|
||||
<i:Interaction.Behaviors>
|
||||
<iac:ValueChangedTriggerBehavior Binding="{Binding SelectedMaxCurrentDownload}">
|
||||
<ia:InvokeCommandAction Command="{Binding SetMaxCurrentDownloadsCommand}" CommandParameter="{Binding ElementName=maxCurrentDownloads, Path=SelectedValue}" />
|
||||
<ia:InvokeCommandAction Command="{Binding SetMaxCurrentDownloadsCommand}" />
|
||||
</iac:ValueChangedTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
@ -107,15 +106,14 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource Split}" />
|
||||
<ComboBox
|
||||
Name="splits"
|
||||
Width="100"
|
||||
VerticalContentAlignment="Center"
|
||||
Classes="normal"
|
||||
ItemsSource="{Binding Splits}"
|
||||
SelectedValue="{Binding SelectedSplit}">
|
||||
SelectedItem="{Binding SelectedSplit}">
|
||||
<i:Interaction.Behaviors>
|
||||
<iac:ValueChangedTriggerBehavior Binding="{Binding SelectedSplit}">
|
||||
<ia:InvokeCommandAction Command="{Binding SetSplitsCommand}" CommandParameter="{Binding ElementName=splits, Path=SelectedValue}" />
|
||||
<ia:InvokeCommandAction Command="{Binding SetSplitsCommand}" />
|
||||
</iac:ValueChangedTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
@ -203,15 +201,14 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource AriaLogLevel}" />
|
||||
<ComboBox
|
||||
Name="ariaLogLevels"
|
||||
Width="100"
|
||||
VerticalContentAlignment="Center"
|
||||
Classes="normal"
|
||||
ItemsSource="{Binding AriaLogLevels}"
|
||||
SelectedValue="{Binding SelectedAriaLogLevel}">
|
||||
SelectedItem="{Binding SelectedAriaLogLevel}">
|
||||
<i:Interaction.Behaviors>
|
||||
<iac:ValueChangedTriggerBehavior Binding="{Binding SelectedAriaLogLevel}">
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaLogLevelsCommand}" CommandParameter="{Binding ElementName=ariaLogLevels, Path=SelectedValue}" />
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaLogLevelsCommand}" />
|
||||
</iac:ValueChangedTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
@ -223,15 +220,14 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource AriaMaxConcurrentDownloads}" />
|
||||
<ComboBox
|
||||
Name="ariaMaxConcurrentDownloads"
|
||||
Width="100"
|
||||
VerticalContentAlignment="Center"
|
||||
Classes="normal"
|
||||
ItemsSource="{Binding AriaMaxConcurrentDownloads}"
|
||||
SelectedValue="{Binding SelectedAriaMaxConcurrentDownload}">
|
||||
SelectedItem="{Binding SelectedAriaMaxConcurrentDownload}">
|
||||
<i:Interaction.Behaviors>
|
||||
<iac:ValueChangedTriggerBehavior Binding="{Binding SelectedAriaMaxConcurrentDownload}">
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaMaxConcurrentDownloadsCommand}" CommandParameter="{Binding ElementName=ariaMaxConcurrentDownloads, Path=SelectedValue}" />
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaMaxConcurrentDownloadsCommand}" />
|
||||
</iac:ValueChangedTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
@ -243,15 +239,14 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource AriaSplit}" />
|
||||
<ComboBox
|
||||
Name="ariaSplits"
|
||||
Width="100"
|
||||
VerticalContentAlignment="Center"
|
||||
Classes="normal"
|
||||
ItemsSource="{Binding AriaSplits}"
|
||||
SelectedValue="{Binding SelectedAriaSplit}">
|
||||
SelectedItem="{Binding SelectedAriaSplit}">
|
||||
<i:Interaction.Behaviors>
|
||||
<iac:ValueChangedTriggerBehavior Binding="{Binding SelectedAriaSplit}">
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaSplitsCommand}" CommandParameter="{Binding ElementName=ariaSplits, Path=SelectedValue}" />
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaSplitsCommand}" />
|
||||
</iac:ValueChangedTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
@ -376,7 +371,6 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource AriaFileAllocation}" />
|
||||
<ComboBox
|
||||
Name="ariaFileAllocations"
|
||||
Width="100"
|
||||
VerticalContentAlignment="Center"
|
||||
Classes="normal"
|
||||
@ -384,7 +378,7 @@
|
||||
SelectedValue="{Binding SelectedAriaFileAllocation}">
|
||||
<i:Interaction.Behaviors>
|
||||
<iac:ValueChangedTriggerBehavior Binding="{Binding SelectedAriaFileAllocation}">
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaFileAllocationsCommand}" CommandParameter="{Binding ElementName=ariaFileAllocations, Path=SelectedValue}" />
|
||||
<ia:InvokeCommandAction Command="{Binding SetAriaFileAllocationsCommand}" />
|
||||
</iac:ValueChangedTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
|
Loading…
Reference in New Issue
Block a user