From 159fd1563226dc9f3b7468090d1898dd7acae0fd Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Sun, 23 Jun 2024 09:52:01 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E8=A7=86=E9=A2=91=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E9=A1=B5=E6=94=B6=E8=97=8F=E8=8F=9C=E5=8D=95=E6=94=B6=E8=97=8F?= =?UTF-8?q?=E5=A4=B9=E5=88=97=E8=A1=A8=E8=AE=BE=E7=BD=AE=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E9=AB=98=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/Pages/VideoDetailPage.xaml | 80 +++++++++++---------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml index 708095d5..a91babc1 100644 --- a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml +++ b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml @@ -120,46 +120,50 @@ 创建 - - - - + + + + + - - - - - - - - + + + + + + + + - - 公开 - 私密 - - - - - + + 公开 + 私密 + + + + + + From 9877038fc5303c82f9ac8c8a23aaa47ebd83eacf Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Sun, 23 Jun 2024 10:09:38 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BF=AB=E6=8D=B7?= =?UTF-8?q?=E9=94=AECtrl+S=E4=BF=9D=E5=AD=98=E6=94=B6=E8=97=8F=E9=80=89?= =?UTF-8?q?=E6=8B=A9=EF=BC=8C=E4=BF=9D=E5=AD=98=E8=A7=86=E9=A2=91=E6=94=B6?= =?UTF-8?q?=E8=97=8F=E5=90=8E=E8=87=AA=E5=8A=A8=E9=9A=90=E8=97=8F=E6=94=B6?= =?UTF-8?q?=E8=97=8F=E5=A4=B9=E9=80=89=E6=8B=A9=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/BiliLite.UWP.csproj | 2 ++ .../Models/Functions/SaveFunction.cs | 16 ++++++++++++++++ src/BiliLite.UWP/Pages/ISavablePage.cs | 9 +++++++++ src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs | 13 +++++++++++-- src/BiliLite.UWP/Services/ShortcutKeyService.cs | 1 + 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/BiliLite.UWP/Models/Functions/SaveFunction.cs create mode 100644 src/BiliLite.UWP/Pages/ISavablePage.cs diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index 39eeff03..9ee94cb8 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -191,6 +191,8 @@ + + diff --git a/src/BiliLite.UWP/Models/Functions/SaveFunction.cs b/src/BiliLite.UWP/Models/Functions/SaveFunction.cs new file mode 100644 index 00000000..8bc65db3 --- /dev/null +++ b/src/BiliLite.UWP/Models/Functions/SaveFunction.cs @@ -0,0 +1,16 @@ +using BiliLite.Pages; +using System.Threading.Tasks; + +namespace BiliLite.Models.Functions +{ + public class SaveFunction : IShortcutFunction + { + public string Name { get; } = "保存操作"; + + public async Task Action(object param) + { + if (!(param is ISavablePage page)) return; + await page.Save(); + } + } +} diff --git a/src/BiliLite.UWP/Pages/ISavablePage.cs b/src/BiliLite.UWP/Pages/ISavablePage.cs new file mode 100644 index 00000000..71ebd635 --- /dev/null +++ b/src/BiliLite.UWP/Pages/ISavablePage.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace BiliLite.Pages +{ + public interface ISavablePage + { + public Task Save(); + } +} diff --git a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs index 88258504..16fc0054 100644 --- a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs +++ b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs @@ -30,7 +30,7 @@ namespace BiliLite.Pages { - public sealed partial class VideoDetailPage : PlayPage, IRefreshablePage + public sealed partial class VideoDetailPage : PlayPage, IRefreshablePage, ISavablePage { private static readonly ILogger logger = GlobalLogger.FromCurrentType(); @@ -725,7 +725,16 @@ private void VideoDetailPage_OnSizeChanged(object sender, SizeChangedEventArgs e private async void SaveFavList_OnClick(object sender, RoutedEventArgs e) { - await m_viewModel.UpdateFav(m_viewModel.VideoInfo.Aid); + await Save(); + } + + public async Task Save() + { + if (BtnFav.Flyout.IsOpen) + { + await m_viewModel.UpdateFav(m_viewModel.VideoInfo.Aid); + BtnFav.Flyout.Hide(); + } } } } diff --git a/src/BiliLite.UWP/Services/ShortcutKeyService.cs b/src/BiliLite.UWP/Services/ShortcutKeyService.cs index e278b73b..48c78bc6 100644 --- a/src/BiliLite.UWP/Services/ShortcutKeyService.cs +++ b/src/BiliLite.UWP/Services/ShortcutKeyService.cs @@ -24,6 +24,7 @@ public ShortcutKeyService() m_shortcutKeyMaps.Add(new AddVolumeFunction(), new List() { VirtualKey.Up }); m_shortcutKeyMaps.Add(new MinusVolumeFunction(), new List() { VirtualKey.Down }); m_shortcutKeyMaps.Add(new CancelFullscreenFunction(), new List() { VirtualKey.Escape }); + m_shortcutKeyMaps.Add(new SaveFunction(), new List() { VirtualKey.Control, VirtualKey.S }); } public void SetMainPage(IMainPage mainPage) From 538f8586989b0d269c0b67692715edd1bd0c6791 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Mon, 24 Jun 2024 20:35:50 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E7=82=B9=E4=B8=8D=E5=96=9C=E6=AC=A2=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/ViewModels/Video/VideoDetailPageViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BiliLite.UWP/ViewModels/Video/VideoDetailPageViewModel.cs b/src/BiliLite.UWP/ViewModels/Video/VideoDetailPageViewModel.cs index 9fec1e05..595b615a 100644 --- a/src/BiliLite.UWP/ViewModels/Video/VideoDetailPageViewModel.cs +++ b/src/BiliLite.UWP/ViewModels/Video/VideoDetailPageViewModel.cs @@ -420,7 +420,8 @@ public async void DoDislike() } - if (!string.IsNullOrEmpty(data.data["toast"]?.ToString())) + if(data.data==null){} + else if (!string.IsNullOrEmpty(data.data["toast"]?.ToString())) { Notify.ShowMessageToast(data.data["toast"].ToString()); } From d373000f8dc2d321982a6f39879beaef2b551571 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Mon, 24 Jun 2024 20:47:52 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E4=B8=AD=E7=94=A8=E6=88=B7=E8=BF=9E=E6=8E=A5=E6=89=93=E5=BC=80?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/BiliLite.UWP.csproj | 1 + .../Extensions/DynamicExtensions.cs | 63 +++++++++++++++++++ src/BiliLite.UWP/MainPage.xaml.cs | 1 - .../UserDynamic/UserDynamicAllViewModel.cs | 38 ++--------- .../UserDynamic/UserDynamicSpaceViewModel.cs | 16 +---- 5 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 src/BiliLite.UWP/Extensions/DynamicExtensions.cs diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index 9ee94cb8..cb0666fd 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -162,6 +162,7 @@ + diff --git a/src/BiliLite.UWP/Extensions/DynamicExtensions.cs b/src/BiliLite.UWP/Extensions/DynamicExtensions.cs new file mode 100644 index 00000000..3363f25d --- /dev/null +++ b/src/BiliLite.UWP/Extensions/DynamicExtensions.cs @@ -0,0 +1,63 @@ +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Windows.UI.Xaml.Controls; +using BiliLite.Models.Common; +using BiliLite.Models.Common.UserDynamic; +using BiliLite.Pages; +using BiliLite.Services; +using BiliLite.ViewModels.UserDynamic; + +namespace BiliLite.Extensions +{ + public static class DynamicExtensions + { + public static void OpenUserEx(this IUserDynamicCommands dynamic, object parameter) + { + long userId = 0; + if (parameter is string userLink) + { + var regex = new Regex("bilibili://space/(\\d+)"); + var match = regex.Match(userLink.ToString()); + userId = !match.Success ? userLink.ToInt64() : match.Groups[1].Value.ToInt64(); + } + + else if (parameter is DynamicV2ItemViewModel dynamicItem) + { + if (dynamicItem.CardType == Constants.DynamicTypes.PGC) + { + var url = dynamicItem.Dynamic.DynPgc != null + ? dynamicItem.Dynamic.DynPgc.Uri + : dynamicItem.Dynamic.DynArchive.Uri; + dynamic.LaunchUrlEx(url); + return; + } + + if (dynamicItem.Author != null) + { + userId = dynamicItem.Author.Author.Mid; + } + else if (dynamicItem.AuthorForward != null) + { + userId = dynamicItem.AuthorForward.Uid; + } + } + + MessageCenter.NavigateToPage(dynamic, new NavigationInfo() + { + icon = Symbol.Contact, + page = typeof(UserInfoPage), + title = "用户中心", + parameters = userId + }); + } + + public static async Task LaunchUrlEx(this IUserDynamicCommands dynamic, string url) + { + var result = await MessageCenter.HandelUrl(url); + if (!result) + { + Notify.ShowMessageToast("无法打开Url"); + } + } + } +} diff --git a/src/BiliLite.UWP/MainPage.xaml.cs b/src/BiliLite.UWP/MainPage.xaml.cs index 1a6cefbc..e7b2ea6e 100644 --- a/src/BiliLite.UWP/MainPage.xaml.cs +++ b/src/BiliLite.UWP/MainPage.xaml.cs @@ -174,7 +174,6 @@ private void Content_PointerPressed(object sender, PointerRoutedEventArgs e) { GoBack(); e.Handled = true; - } } diff --git a/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs b/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs index 6b5e5dfb..f66b5e89 100644 --- a/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs +++ b/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs @@ -50,7 +50,7 @@ public UserDynamicAllViewModel(GrpcService grpcService, IMapper mapper) m_dynamicApi = new DynamicAPI(); m_watchLaterVm = new WatchLaterVM(); LoadMoreCommand = new RelayCommand(LoadMore); - UserCommand = new RelayCommand(OpenUser); + UserCommand = new RelayCommand(OpenUser); DetailCommand = new RelayCommand(OpenDetail); ImageCommand = new RelayCommand(OpenImage); WebDetailCommand = new RelayCommand(OpenWebDetail); @@ -109,35 +109,9 @@ public UserDynamicAllViewModel(GrpcService grpcService, IMapper mapper) #region Private Methods - private void OpenUser(DynamicV2ItemViewModel dynamicItem) + private void OpenUser(object parameter) { - if (dynamicItem.CardType == Constants.DynamicTypes.PGC) - { - var url = dynamicItem.Dynamic.DynPgc != null - ? dynamicItem.Dynamic.DynPgc.Uri - : dynamicItem.Dynamic.DynArchive.Uri; - LaunchUrl(url); - return; - } - - long userId = 0; - - if (dynamicItem.Author != null) - { - userId = dynamicItem.Author.Author.Mid; - } - else if (dynamicItem.AuthorForward != null) - { - userId = dynamicItem.AuthorForward.Uid; - } - - MessageCenter.NavigateToPage(this, new NavigationInfo() - { - icon = Symbol.Contact, - page = typeof(UserInfoPage), - title = "用户中心", - parameters = userId - }); + this.OpenUserEx(parameter); } private void OpenComment(DynamicV2ItemViewModel data) @@ -191,11 +165,7 @@ private void OpenDetail(string dynId) private async void LaunchUrl(string url) { - var result = await MessageCenter.HandelUrl(url); - if (!result) - { - Notify.ShowMessageToast("无法打开Url"); - } + await this.LaunchUrlEx(url); } private async Task DoLikeCore(DynamicV2ItemViewModel item) diff --git a/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicSpaceViewModel.cs b/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicSpaceViewModel.cs index 19a2f2f3..38f6c8d6 100644 --- a/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicSpaceViewModel.cs +++ b/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicSpaceViewModel.cs @@ -109,15 +109,9 @@ public UserDynamicSpaceViewModel(GrpcService grpcService, IMapper mapper) #region Private Methods - private void OpenUser(object userId) + private void OpenUser(object parameter) { - MessageCenter.NavigateToPage(this, new NavigationInfo() - { - icon = Symbol.Contact, - page = typeof(UserInfoPage), - title = "用户中心", - parameters = userId - }); + this.OpenUserEx(parameter); } private void OpenComment(DynamicV2ItemViewModel data) @@ -188,11 +182,7 @@ private void HandleDynamicResults(DynSpaceRsp results) private async void LaunchUrl(string url) { - var result = await MessageCenter.HandelUrl(url); - if (!result) - { - Notify.ShowMessageToast("无法打开Url"); - } + await this.LaunchUrlEx(url); } private async Task DoLikeCore(DynamicV2ItemViewModel item) From c86b7c7e186de33847eaba26c62e010aeb86f1cd Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Mon, 24 Jun 2024 20:48:46 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E9=A1=B5=E6=94=B6=E8=97=8F=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E3=80=81=E6=94=AF=E6=8C=81=E9=BC=A0=E6=A0=87?= =?UTF-8?q?=E4=B8=AD=E9=94=AE=E4=BE=A7=E9=94=AE=E5=BF=AB=E6=8D=B7=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E4=BF=9D=E5=AD=98=E6=94=B6=E8=97=8F=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/Pages/VideoDetailPage.xaml | 21 +++++++++++++++---- .../Pages/VideoDetailPage.xaml.cs | 8 +++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml index a91babc1..689ff719 100644 --- a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml +++ b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml @@ -108,7 +108,7 @@ - + @@ -116,12 +116,20 @@ 选择收藏夹 - - 创建 + + + + 创建 + + - + diff --git a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs index 16fc0054..e2372c90 100644 --- a/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs +++ b/src/BiliLite.UWP/Pages/VideoDetailPage.xaml.cs @@ -736,5 +736,13 @@ public async Task Save() BtnFav.Flyout.Hide(); } } + + private async void FavList_OnPointerPressed(object sender, PointerRoutedEventArgs e) + { + if (e.IsUseMiddleButton(sender)) + { + await Save(); + } + } } } From 848cd8473559f0d40c5266f0aacbf466c59a68b2 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Fri, 28 Jun 2024 23:14:52 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8F=91=E9=80=81?= =?UTF-8?q?=E5=B8=A6=E5=9B=BE=E7=89=87=E8=AF=84=E8=AE=BA=EF=BC=8C=E8=87=AA?= =?UTF-8?q?=E5=B7=B1=E5=8F=91=E9=80=81=E7=9A=84=E8=AF=84=E8=AE=BA=E7=82=B9?= =?UTF-8?q?=E5=8F=B3=E9=94=AE=E5=8F=AF=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/BiliLite.UWP.csproj | 3 + src/BiliLite.UWP/Controls/CommentControl.xaml | 7 +-- .../Controls/CommentControl.xaml.cs | 5 ++ .../Dialogs/SendCommentDialog.xaml | 52 ++++++++++++++-- .../Dialogs/SendCommentDialog.xaml.cs | 60 ++++++++++++++++++- .../Extensions/ApiModelExtensions.cs | 4 +- .../Extensions/StringHttpExtensions.cs | 14 ++--- .../Extensions/ViewModelExtensions.cs | 1 + .../Models/Common/UploadFileInfo.cs | 9 +++ .../Common/UserDynamic/DynamicPicture.cs | 19 ++++++ .../Models/Requests/Api/CommentApi.cs | 47 ++++++++++++++- src/BiliLite.UWP/Models/Requests/ApiModel.cs | 2 + .../Services/BiliRequestBuilder.cs | 56 ++++++++++++++++- .../Comment/SendCommentDialogViewModel.cs | 26 ++++++++ 14 files changed, 280 insertions(+), 25 deletions(-) create mode 100644 src/BiliLite.UWP/Models/Common/UploadFileInfo.cs create mode 100644 src/BiliLite.UWP/Models/Common/UserDynamic/DynamicPicture.cs create mode 100644 src/BiliLite.UWP/ViewModels/Comment/SendCommentDialogViewModel.cs diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index cb0666fd..3fbb24a1 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -170,6 +170,8 @@ + + @@ -196,6 +198,7 @@ + diff --git a/src/BiliLite.UWP/Controls/CommentControl.xaml b/src/BiliLite.UWP/Controls/CommentControl.xaml index abd64332..ae1e80ea 100644 --- a/src/BiliLite.UWP/Controls/CommentControl.xaml +++ b/src/BiliLite.UWP/Controls/CommentControl.xaml @@ -77,8 +77,8 @@ - 删除 - 举报 + 删除 + 举报 @@ -135,7 +135,7 @@ - + [置顶] @@ -183,7 +183,6 @@ Text="{x:Bind Path=Member.UserSailing.Cardbg.Fan.NumDesc,Mode=OneWay}"> - diff --git a/src/BiliLite.UWP/Controls/CommentControl.xaml.cs b/src/BiliLite.UWP/Controls/CommentControl.xaml.cs index 9d629026..a82fb9ae 100644 --- a/src/BiliLite.UWP/Controls/CommentControl.xaml.cs +++ b/src/BiliLite.UWP/Controls/CommentControl.xaml.cs @@ -596,6 +596,11 @@ private void CommentControl_OnSizeChanged(object sender, SizeChangedEventArgs e) } } + private void MenuFlyoutItem_OnClick(object sender, RoutedEventArgs e) + { + throw new NotImplementedException(); + } + #endregion #region Public Methods diff --git a/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml b/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml index b6777381..897b9ef1 100644 --- a/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml +++ b/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml @@ -8,7 +8,10 @@ mc:Ignorable="d" Title="发表评论" xmlns:modules="using:BiliLite.Modules" + xmlns:fa="using:FontAwesome5" xmlns:viewModels="using:BiliLite.ViewModels" + xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls" + xmlns:userDynamic="using:BiliLite.Models.Common.UserDynamic" PrimaryButtonText="发送" SecondaryButtonText="取消" PrimaryButtonClick="ContentDialog_PrimaryButtonClick" @@ -51,12 +54,49 @@ + + + + - + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml.cs b/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml.cs index de6bc867..e7d94824 100644 --- a/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml.cs +++ b/src/BiliLite.UWP/Dialogs/SendCommentDialog.xaml.cs @@ -1,11 +1,20 @@ using BiliLite.Models.Requests.Api; using System; +using System.IO; +using System.Linq; +using Windows.Storage.Pickers; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using BiliLite.Extensions; using BiliLite.ViewModels; using static BiliLite.Models.Requests.Api.CommentApi; using Microsoft.Extensions.DependencyInjection; +using Windows.Storage; +using BiliLite.Models.Common; +using BiliLite.Models.Common.UserDynamic; +using BiliLite.Models.Exceptions; +using BiliLite.Services; +using BiliLite.ViewModels.Comment; // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“内容对话框”项模板 @@ -17,8 +26,12 @@ public sealed partial class SendCommentDialog : ContentDialog readonly EmoteViewModel emoteVM; readonly string oid; readonly CommentType commentType; + private static readonly ILogger _logger = GlobalLogger.FromCurrentType(); + private readonly SendCommentDialogViewModel m_viewModel; + public SendCommentDialog(string oid, CommentType commentType) { + m_viewModel = App.ServiceProvider.GetRequiredService(); emoteVM = App.ServiceProvider.GetService(); this.InitializeComponent(); commentApi = new CommentApi(); @@ -37,7 +50,7 @@ private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, Conten { IsPrimaryButtonEnabled = false; var text = txt_Comment.Text; - var result = await commentApi.AddComment(oid, commentType, text).Request(); + var result = await commentApi.AddComment(oid, commentType, text, m_viewModel.Pictures.ToList()).Request(); var data = await result.GetData(); if (data.code == 0) { @@ -78,5 +91,50 @@ private void GridView_ItemClick(object sender, ItemClickEventArgs e) { txt_Comment.Text += (e.ClickedItem as EmotePackageItemModel).text.ToString(); } + + private async void BtnUploadDraw_OnClick(object sender, RoutedEventArgs e) + { + try + { + var filePicker = new FileOpenPicker(); + filePicker.FileTypeFilter.Add(".jpg"); + filePicker.FileTypeFilter.Add(".png"); + filePicker.FileTypeFilter.Add(".jpeg"); + var file = await filePicker.PickSingleFileAsync(); + if (file == null) return; + using var openFile = await file.OpenAsync(FileAccessMode.Read); + using var stream = openFile.AsStreamForRead(); + var bin = new byte[stream.Length]; + + await stream.ReadAsync(bin, 0, bin.Length); + var fileInfo = new UploadFileInfo() + { + Data = bin, + FileName = file.Name, + }; + + var api = commentApi.UploadDraw(fileInfo); + var result = await api.Request(); + if (!result.status) + throw new CustomizedErrorException(result.message); + var uploadDrawResult = await result.GetData(); + if (!uploadDrawResult.success) + throw new CustomizedErrorException(uploadDrawResult.message); + m_viewModel.AddPicture(uploadDrawResult.data); + } + catch (Exception ex) + { + _logger.Error(ex.Message, ex); + Notify.ShowMessageToast(ex.Message); + } + } + + private void BtnRemovePicture_OnClick(object sender, RoutedEventArgs e) + { + if (sender is Button { DataContext: DynamicPicture picture }) + { + m_viewModel.RemovePicture(picture); + } + } } } diff --git a/src/BiliLite.UWP/Extensions/ApiModelExtensions.cs b/src/BiliLite.UWP/Extensions/ApiModelExtensions.cs index f36c74f1..ee85e329 100644 --- a/src/BiliLite.UWP/Extensions/ApiModelExtensions.cs +++ b/src/BiliLite.UWP/Extensions/ApiModelExtensions.cs @@ -36,10 +36,10 @@ public static async Task Request(this ApiModel api, [CallerMemberNa { if (api.need_cookie) { - return await api.url.PostHttpResultsWithCookie(api.body, api.headers, api.ExtraCookies); + return await api.url.PostHttpResultsWithCookie(api.body, api.FormData, api.headers, api.ExtraCookies); } - return await api.url.PostHttpResultsAsync(api.body, api.headers); + return await api.url.PostHttpResultsAsync(api.body, api.FormData, api.headers); } } } diff --git a/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs b/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs index 9be6d292..13af63e5 100644 --- a/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs +++ b/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs @@ -92,7 +92,7 @@ public static async Task GetRedirectHttpResultsWithWebCookie(this s /// /// /// - public static async Task GetHttpResultsWithWebCookie(this string url, IDictionary headers = null, IDictionary extraCookies = null) + public static async Task GetHttpResultsWithWebCookie(this string url, IDictionary headers = null, IDictionary extraCookies = null) { try { @@ -100,7 +100,7 @@ public static async Task GetHttpResultsWithWebCookie(this string ur if (extraCookies != null) { - foreach(var kvp in extraCookies.ToList()) + foreach (var kvp in extraCookies.ToList()) { cookies.Add(kvp.Key, kvp.Value); } @@ -196,19 +196,19 @@ public static async Task GetString(this string url, IDictionary /// /// - public static async Task PostHttpResultsAsync(this string url, string body, IDictionary headers = null, IDictionary cookies = null) + public static async Task PostHttpResultsAsync(this string url, string body, Dictionary formBody, IDictionary headers = null, IDictionary cookies = null) { Debug.WriteLine("POST:" + url + "\r\nBODY:" + body); var biliRequestBuilder = new BiliRequestBuilder(url) .SetHeaders(headers) .SetCookies(cookies) - .SetPostBody(body); + .SetPostBody(body, formBody); var biliRequest = biliRequestBuilder.Build(); var httpResult = await biliRequest.Send(); return httpResult; } - public static async Task PostHttpResultsWithCookie(this string url, string body, IDictionary headers = null, IDictionary extraCookies = null) + public static async Task PostHttpResultsWithCookie(this string url, string body, Dictionary formBody, IDictionary headers = null, IDictionary extraCookies = null) { try { @@ -218,7 +218,7 @@ public static async Task PostHttpResultsWithCookie(this string url, if (cookies == null || cookies.Count == 0) { //访问一遍bilibili.com - var getCookieResult = await Constants.BILIBILI_DOMAIN.GetHttpResultsAsync(); + var getCookieResult = await Constants.BILIBILI_DOMAIN.GetHttpResultsAsync(); cookieService.Cookies = getCookieResult.cookies; } cookies = cookieService.Cookies; @@ -232,7 +232,7 @@ public static async Task PostHttpResultsWithCookie(this string url, } } - return await url.PostHttpResultsAsync(body, headers, cookiesCollection); + return await url.PostHttpResultsAsync(body, formBody, headers, cookiesCollection); } catch (Exception ex) { diff --git a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs index fa42c78e..8f854d9a 100644 --- a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs +++ b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs @@ -44,6 +44,7 @@ public static IServiceCollection AddViewModels(this IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); return services; } } diff --git a/src/BiliLite.UWP/Models/Common/UploadFileInfo.cs b/src/BiliLite.UWP/Models/Common/UploadFileInfo.cs new file mode 100644 index 00000000..b5e4eea0 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/UploadFileInfo.cs @@ -0,0 +1,9 @@ +namespace BiliLite.Models.Common +{ + public class UploadFileInfo + { + public string FileName { get; set; } + + public byte[] Data { get; set; } + } +} diff --git a/src/BiliLite.UWP/Models/Common/UserDynamic/DynamicPicture.cs b/src/BiliLite.UWP/Models/Common/UserDynamic/DynamicPicture.cs new file mode 100644 index 00000000..8b51d0bb --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/UserDynamic/DynamicPicture.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace BiliLite.Models.Common.UserDynamic +{ + public class DynamicPicture + { + [JsonProperty("image_height")] + public double ImageHeight { get; set; } + + [JsonProperty("image_width")] + public double ImageWidth { get; set; } + + [JsonProperty("image_url")] + public string ImageUrl { get; set; } + + [JsonProperty("img_size")] + public double ImgSize { get; set; } + } +} diff --git a/src/BiliLite.UWP/Models/Requests/Api/CommentApi.cs b/src/BiliLite.UWP/Models/Requests/Api/CommentApi.cs index 25a48aee..fc9cd8fa 100644 --- a/src/BiliLite.UWP/Models/Requests/Api/CommentApi.cs +++ b/src/BiliLite.UWP/Models/Requests/Api/CommentApi.cs @@ -1,8 +1,11 @@ using System; -using BiliLite.Extensions; +using System.Collections.Generic; +using System.Linq; +using BiliLite.Models.Common; using BiliLite.Services; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; +using BiliLite.Models.Common.UserDynamic; namespace BiliLite.Models.Requests.Api { @@ -136,7 +139,8 @@ public ApiModel DeleteComment(string oid, string rpid, int type) // api.body += ApiHelper.GetSign(api.body, appKey); return api; } - public ApiModel AddComment(string oid, CommentType type, string message) + + public ApiModel AddComment(string oid, CommentType type, string message, List pictures = null) { var csrf = m_cookieService.GetCSRFToken(); var api = new ApiModel() @@ -146,6 +150,45 @@ public ApiModel AddComment(string oid, CommentType type, string message) body = $"&oid={oid}&type={(int)type}&message={Uri.EscapeDataString(message)}&csrf={csrf}", need_cookie = true, }; + + if (pictures != null && pictures.Any()) + { + var pictureList = new List(); + foreach (var picture in pictures) + { + pictureList.Add(new + { + img_src = picture.ImageUrl, + img_width = picture.ImageWidth, + img_height = picture.ImageHeight, + img_size = picture.ImgSize + }); + } + + var picturesArgs = JsonConvert.SerializeObject(pictureList); + api.body += $"&pictures={picturesArgs}"; + } + + //api.body += ApiHelper.GetSign(api.body, appKey); + return api; + } + + public ApiModel UploadDraw(UploadFileInfo file) + { + var csrf = m_cookieService.GetCSRFToken(); + var api = new ApiModel() + { + method = RestSharp.Method.Post, + baseUrl = $"{ApiHelper.API_BASE_URL}/x/dynamic/feed/draw/upload_bfs", + FormData = new Dictionary() + { + { "file_up", file }, + { "biz", "new_dyn" }, + { "category", "daily" }, + { "csrf", csrf } + }, + need_cookie = true, + }; //api.body += ApiHelper.GetSign(api.body, appKey); return api; } diff --git a/src/BiliLite.UWP/Models/Requests/ApiModel.cs b/src/BiliLite.UWP/Models/Requests/ApiModel.cs index c5e39249..01ed0228 100644 --- a/src/BiliLite.UWP/Models/Requests/ApiModel.cs +++ b/src/BiliLite.UWP/Models/Requests/ApiModel.cs @@ -48,5 +48,7 @@ public string url return baseUrl + "?" + parameter; } } + + public Dictionary FormData { get; set; } } } \ No newline at end of file diff --git a/src/BiliLite.UWP/Services/BiliRequestBuilder.cs b/src/BiliLite.UWP/Services/BiliRequestBuilder.cs index 792b5875..b568cd71 100644 --- a/src/BiliLite.UWP/Services/BiliRequestBuilder.cs +++ b/src/BiliLite.UWP/Services/BiliRequestBuilder.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Net.Http; using BiliLite.Models.Requests; +using BiliLite.Models.Common; namespace BiliLite.Services { @@ -21,14 +22,39 @@ public BiliRequestBuilder(string url) m_url = url; } - public BiliRequestBuilder SetPostBody(string body) + public BiliRequestBuilder SetPostBody(string body, Dictionary formBody) { - m_body = string.IsNullOrEmpty(body) ? null : new StringContent( - body, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); + if (formBody != null && formBody.Count > 0) + { + SetFormBody(formBody); + } + else + { + SetUrlEncodeBody(body); + } + m_method = HttpMethod.Post; return this; } + public BiliRequestBuilder SetPostForm(Dictionary formBody) + { + var content = new MultipartFormDataContent(); + foreach (var formKeyValuePair in formBody) + { + if (formKeyValuePair.Value is UploadFileInfo file) + { + content.Add(new ByteArrayContent(file.Data), formKeyValuePair.Key, file.FileName); + }else if (formKeyValuePair.Value is string valueStr) + { + content.Add(new StringContent(valueStr), formKeyValuePair.Key); + } + } + + m_body = content; + return this; + } + public BiliRequestBuilder SetHeaders(IDictionary headers = null) { m_headers = headers; @@ -51,5 +77,29 @@ public BiliRequest Build() { return new BiliRequest(m_url, m_headers, m_cookies, m_method, m_body, m_needRedirect); } + + private void SetUrlEncodeBody(string body) + { + m_body = string.IsNullOrEmpty(body) ? null : new StringContent( + body, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); + } + + private void SetFormBody(Dictionary formBody) + { + var content = new MultipartFormDataContent(); + foreach (var formKeyValuePair in formBody) + { + if (formKeyValuePair.Value is UploadFileInfo file) + { + content.Add(new ByteArrayContent(file.Data), formKeyValuePair.Key, file.FileName); + } + else if (formKeyValuePair.Value is string valueStr) + { + content.Add(new StringContent(valueStr), formKeyValuePair.Key); + } + } + + m_body = content; + } } } diff --git a/src/BiliLite.UWP/ViewModels/Comment/SendCommentDialogViewModel.cs b/src/BiliLite.UWP/ViewModels/Comment/SendCommentDialogViewModel.cs new file mode 100644 index 00000000..c6282a85 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Comment/SendCommentDialogViewModel.cs @@ -0,0 +1,26 @@ +using System.Collections.ObjectModel; +using System.Linq; +using BiliLite.Models.Common.UserDynamic; +using BiliLite.ViewModels.Common; + +namespace BiliLite.ViewModels.Comment +{ + public class SendCommentDialogViewModel : BaseViewModel + { + public ObservableCollection Pictures { get; set; } = new ObservableCollection(); + + public bool ShowPictures { get; set; } = false; + + public void AddPicture(DynamicPicture picture) + { + Pictures.Add(picture); + ShowPictures = true; + } + + public void RemovePicture(DynamicPicture picture) + { + Pictures.Remove(picture); + ShowPictures = Pictures.Any(); + } + } +} From 420570f3161159df1492b34d3368da7710a64971 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Tue, 2 Jul 2024 22:05:39 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BF=AB=E6=8D=B7?= =?UTF-8?q?=E9=94=AE=E8=AE=BE=E7=BD=AE=E5=80=8D=E9=80=9F=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/Controls/PlayerControl.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs b/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs index 8d40955a..7e77495f 100644 --- a/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs +++ b/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs @@ -385,14 +385,14 @@ private async void PlayerControl_KeyDown(CoreWindow sender, KeyEventArgs args) case Windows.System.VirtualKey.F1: case (Windows.System.VirtualKey)186: //慢速播放 - if (BottomCBSpeed.SelectedIndex == 5) + if (BottomCBSpeed.SelectedIndex == m_playSpeedMenuService.MenuItems.Count - 1) { Notify.ShowMessageToast("不能再慢啦"); return; } BottomCBSpeed.SelectedIndex += 1; - m_playerToastService.Show(PlayerToastService.SPEED_KEY,(BottomCBSpeed.SelectedItem as ComboBoxItem).Content.ToString()); + m_playerToastService.Show(PlayerToastService.SPEED_KEY,(BottomCBSpeed.SelectedItem as PlaySpeedMenuItem).Content); break; case Windows.System.VirtualKey.F2: case (Windows.System.VirtualKey)222: @@ -403,7 +403,7 @@ private async void PlayerControl_KeyDown(CoreWindow sender, KeyEventArgs args) return; } BottomCBSpeed.SelectedIndex -= 1; - m_playerToastService.Show(PlayerToastService.SPEED_KEY, (BottomCBSpeed.SelectedItem as ComboBoxItem).Content.ToString()); + m_playerToastService.Show(PlayerToastService.SPEED_KEY, (BottomCBSpeed.SelectedItem as PlaySpeedMenuItem).Content); break; case Windows.System.VirtualKey.F3: case Windows.System.VirtualKey.V: From aa5e7d2276d32bd4bb268453fde3e07a9ae3aa3d Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Wed, 3 Jul 2024 19:59:52 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E6=97=A5=E5=BF=97=E4=B8=AD=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=BF=A1=E6=81=AF=E5=86=85=E5=90=AB=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/Services/LogService.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/BiliLite.UWP/Services/LogService.cs b/src/BiliLite.UWP/Services/LogService.cs index 4f1cb956..4ea4a4ec 100644 --- a/src/BiliLite.UWP/Services/LogService.cs +++ b/src/BiliLite.UWP/Services/LogService.cs @@ -46,7 +46,12 @@ public static void Init() Name = "logfile", CreateDirs = true, FileName = storageFolder.Path + @"\log\" + DateTime.Now.ToString("yyyyMMdd") + ".log", - Layout = "${longdate}|${level:uppercase=true}|${threadid}|${event-properties:item=type}.${event-properties:item=method}|${message}|${exception:format=Message,StackTrace}" + Layout = "${longdate}" + + "|${level:uppercase=true}" + + "|${threadid}" + + "|${event-properties:item=type}.${event-properties:item=method}" + + "|${message}" + + "|${event-properties:item=exception}" }; config.AddRule(LogLevel.Trace, LogLevel.Trace, logfile); config.AddRule(LogLevel.Debug, LogLevel.Debug, logfile); @@ -94,6 +99,12 @@ public static void Log(string message, LogType type, Exception ex = null, [Calle if ((int)type < LogLowestLevel) return; if (IsProtectLogInfo) message = message.ProtectValues("access_key", "csrf", "access_token", "sign"); + var exception = ""; + if (ex != null && IsProtectLogInfo) + { + exception = ex.Message.ProtectValues("access_key", "csrf", "access_token", "sign") + "\n" + + ex.StackTrace.ProtectValues("access_key", "csrf", "access_token", "sign"); + } var logEvent = new LogEventInfo(LogLevel.Info, null, message); switch (type) @@ -109,15 +120,15 @@ public static void Log(string message, LogType type, Exception ex = null, [Calle break; case LogType.Warn: logEvent.Level = LogLevel.Warn; - logEvent.Exception = ex; + logEvent.Properties["exception"] = exception; break; case LogType.Error: logEvent.Level = LogLevel.Error; - logEvent.Exception = ex; + logEvent.Properties["exception"] = exception; break; case LogType.Fatal: logEvent.Level = LogLevel.Fatal; - logEvent.Exception = ex; + logEvent.Properties["exception"] = exception; break; case LogType.Necessary: logEvent.Level = LogLevel.Info; From 12e851b4a14141d67d7a7bf05dacd4482c6472f9 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Sun, 7 Jul 2024 10:44:17 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E5=85=B3=E9=97=ADnativ?= =?UTF-8?q?eToolchain=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/BiliLite.UWP.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index 3fbb24a1..fd99cab2 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -128,7 +128,7 @@ false prompt true - true + false False false From a81dcb50b41382972bfdba1ac8d8c4a16d441123 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Tue, 9 Jul 2024 20:42:48 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E6=8E=A8=E8=8D=90=E9=A1=B5=E3=80=81=E6=90=9C=E7=B4=A2=E9=A1=B5?= =?UTF-8?q?=E3=80=81=E5=8A=A8=E6=80=81=E9=A1=B5=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/BiliLite.UWP.csproj | 16 ++ .../Controls/FilterSettingsControl.xaml | 156 +++++++++++++ .../Controls/FilterSettingsControl.xaml.cs | 112 +++++++++ .../Converters/FilterRuleTypeConverter.cs | 48 ++++ .../Extensions/MapperExtensions.cs | 3 + .../Extensions/ViewModelExtensions.cs | 1 + src/BiliLite.UWP/Models/Common/Enumerates.cs | 25 ++ .../Models/Common/SettingConstants.cs | 12 + .../Models/Common/Settings/FilterRule.cs | 17 ++ .../Models/Common/Settings/FilterRuleTypes.cs | 48 ++++ src/BiliLite.UWP/Modules/SearchVM.cs | 8 +- src/BiliLite.UWP/Pages/SettingPage.xaml | 9 + .../Services/ContentFilterService.cs | 215 ++++++++++++++++++ src/BiliLite.UWP/Startup.cs | 3 +- .../ViewModels/Home/RecommendPageViewModel.cs | 23 +- .../Settings/FilterRuleViewModel.cs | 53 +++++ .../Settings/FilterSettingsViewModel.cs | 14 ++ .../UserDynamic/UserDynamicAllViewModel.cs | 7 +- 18 files changed, 759 insertions(+), 11 deletions(-) create mode 100644 src/BiliLite.UWP/Controls/FilterSettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/FilterSettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Converters/FilterRuleTypeConverter.cs create mode 100644 src/BiliLite.UWP/Models/Common/Settings/FilterRule.cs create mode 100644 src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs create mode 100644 src/BiliLite.UWP/Services/ContentFilterService.cs create mode 100644 src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs create mode 100644 src/BiliLite.UWP/ViewModels/Settings/FilterSettingsViewModel.cs diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index fd99cab2..a1b8a1b1 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -143,6 +143,9 @@ DynamicItemV2Control.xaml + + FilterSettingsControl.xaml + PlayerToast.xaml @@ -152,6 +155,7 @@ VideoListView.xaml + EditPlaySpeedMenuDialog.xaml @@ -170,6 +174,8 @@ + + @@ -197,10 +203,13 @@ + + + UserDynamicPage.xaml @@ -1017,6 +1026,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -1310,6 +1323,9 @@ 10.1.1 + + 8.0.240109 + 1.0.2 diff --git a/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml b/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml new file mode 100644 index 00000000..71443821 --- /dev/null +++ b/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml @@ -0,0 +1,156 @@ + + + + + + + + + + + + 推荐页过滤 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 搜索页过滤 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 动态页过滤 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml.cs new file mode 100644 index 00000000..c3385e04 --- /dev/null +++ b/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using AutoMapper; +using BiliLite.Models.Common; +using BiliLite.Models.Common.Settings; +using BiliLite.Services; +using BiliLite.ViewModels.Settings; +using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls +{ + public sealed partial class FilterSettingsControl : UserControl + { + private readonly ContentFilterService m_contentFilterService; + private readonly FilterSettingsViewModel m_viewModel; + private readonly IMapper m_mapper; + + public FilterSettingsControl() + { + m_mapper = App.ServiceProvider.GetRequiredService(); + m_viewModel = App.ServiceProvider.GetRequiredService(); + DataContext = m_viewModel; + m_contentFilterService = App.ServiceProvider.GetRequiredService(); + m_viewModel.RecommendFilterRules = + new ObservableCollection( + m_mapper.Map>(m_contentFilterService.RecommendFilterRules) + ); + m_viewModel.SearchFilterRules = + new ObservableCollection( + m_mapper.Map>(m_contentFilterService.SearchFilterRules) + ); + m_viewModel.DynamicFilterRules = + new ObservableCollection( + m_mapper.Map>(m_contentFilterService.DynamicFilterRules) + ); + this.InitializeComponent(); + } + + private FilterRule CreateNewFilterRule(FilterRuleType filterRuleType) + { + var rule = new FilterRule() + { + Id = Guid.NewGuid().ToString(), + Rule = "新规则", + FilterRuleType = filterRuleType, + ContentType = FilterContentType.Title, + FilterType = FilterType.Word, + Enable = true, + }; + return rule; + } + + private void BtnAddRecommendFilterRule_OnClick(object sender, RoutedEventArgs e) + { + var rule = CreateNewFilterRule(FilterRuleType.Recommend); + m_contentFilterService.AddRecommendFilterRule(rule); + var ruleViewModel = m_mapper.Map(rule); + m_viewModel.RecommendFilterRules.Add(ruleViewModel); + } + + private void UpdateFilterRule(FilterRuleViewModel filterRuleViewModel) + { + var rule = m_mapper.Map(filterRuleViewModel); + m_contentFilterService.UpdateFilterRule(rule); + } + + private async void OnFilterRuleChanged(object sender, T e) + { + if (sender is FrameworkElement { DataContext: FilterRuleViewModel filterRuleViewModel }) + { + // 等待数据源更新 + await Task.Delay(50); + UpdateFilterRule(filterRuleViewModel); + } + } + + private void BtnDeleteFilterRule_OnClick(object sender, RoutedEventArgs e) + { + if (sender is FrameworkElement { DataContext: FilterRuleViewModel filterRuleViewModel }) + { + var rule = m_mapper.Map(filterRuleViewModel); + m_contentFilterService.DeleteFilterRule(rule); + + m_viewModel.RecommendFilterRules.Remove(filterRuleViewModel); + m_viewModel.SearchFilterRules.Remove(filterRuleViewModel); + m_viewModel.DynamicFilterRules.Remove(filterRuleViewModel); + } + } + + private void BtnAddSearchFilterRule_OnClick(object sender, RoutedEventArgs e) + { + var rule = CreateNewFilterRule(FilterRuleType.Search); + m_contentFilterService.AddSearchFilterRule(rule); + var ruleViewModel = m_mapper.Map(rule); + m_viewModel.SearchFilterRules.Add(ruleViewModel); + } + + private void BtnAddDynamicFilterRule_OnClick(object sender, RoutedEventArgs e) + { + var rule = CreateNewFilterRule(FilterRuleType.Dynamic); + m_contentFilterService.AddDynamicFilterRule(rule); + var ruleViewModel = m_mapper.Map(rule); + m_viewModel.DynamicFilterRules.Add(ruleViewModel); + } + } +} diff --git a/src/BiliLite.UWP/Converters/FilterRuleTypeConverter.cs b/src/BiliLite.UWP/Converters/FilterRuleTypeConverter.cs new file mode 100644 index 00000000..238eebb5 --- /dev/null +++ b/src/BiliLite.UWP/Converters/FilterRuleTypeConverter.cs @@ -0,0 +1,48 @@ +using BiliLite.Models.Common; +using System; +using System.Linq; +using Windows.UI.Xaml.Data; +using BiliLite.Models.Common.Settings; + +namespace BiliLite.Converters +{ + public class FilterRuleTypeConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + if (value is FilterType filterType) + { + return FilterRuleTypes.FilterTypeOptions.FirstOrDefault(x => x.Type == filterType); + } + else if(value is FilterContentType contentType) + { + return FilterRuleTypes.FilterTargetOptions.FirstOrDefault(x => x.Type == contentType); + } + + return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + if (value is FilterTypeOption filterType) + { + return filterType.Type; + } + else if (value is FilterTargetOption contentType) + { + return contentType.Type; + } + + if (targetType == typeof(FilterType)) + { + return FilterType.Word; + } + if (targetType == typeof(FilterContentType)) + { + return FilterContentType.Title; + } + + return null; + } + } +} diff --git a/src/BiliLite.UWP/Extensions/MapperExtensions.cs b/src/BiliLite.UWP/Extensions/MapperExtensions.cs index f3d90e76..5495d9b7 100644 --- a/src/BiliLite.UWP/Extensions/MapperExtensions.cs +++ b/src/BiliLite.UWP/Extensions/MapperExtensions.cs @@ -13,6 +13,7 @@ using BiliLite.Models.Common.Dynamic; using BiliLite.Models.Common.Home; using BiliLite.Models.Common.Season; +using BiliLite.Models.Common.Settings; using BiliLite.Models.Common.User; using BiliLite.Models.Common.User.UserDetails; using BiliLite.Models.Common.UserDynamic; @@ -26,6 +27,7 @@ using BiliLite.ViewModels.Download; using BiliLite.ViewModels.Home; using BiliLite.ViewModels.Season; +using BiliLite.ViewModels.Settings; using BiliLite.ViewModels.User; using BiliLite.ViewModels.UserDynamic; using BiliLite.ViewModels.Video; @@ -70,6 +72,7 @@ public static IServiceCollection AddMapper(this IServiceCollection services) .ForMember(dest => dest.Author, opt => opt.MapFrom(src => src.Upper.Name)); + expression.CreateMap().ReverseMap(); var danmakuModeConvertDic = new Dictionary() { diff --git a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs index 8f854d9a..f7110d20 100644 --- a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs +++ b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs @@ -45,6 +45,7 @@ public static IServiceCollection AddViewModels(this IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); return services; } } diff --git a/src/BiliLite.UWP/Models/Common/Enumerates.cs b/src/BiliLite.UWP/Models/Common/Enumerates.cs index 76916e36..1106d71c 100644 --- a/src/BiliLite.UWP/Models/Common/Enumerates.cs +++ b/src/BiliLite.UWP/Models/Common/Enumerates.cs @@ -490,4 +490,29 @@ public enum RankRegionType /// Rookie } + + public enum FilterRuleType + { + Recommend, + Search, + Dynamic, + } + + public enum FilterType + { + /// + /// 关键词 + /// + Word, + /// + /// 正则 + /// + Regular, + } + + public enum FilterContentType + { + Title, + User, + } } \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/SettingConstants.cs b/src/BiliLite.UWP/Models/Common/SettingConstants.cs index 6128a677..48fa1dac 100644 --- a/src/BiliLite.UWP/Models/Common/SettingConstants.cs +++ b/src/BiliLite.UWP/Models/Common/SettingConstants.cs @@ -778,6 +778,18 @@ public class Player public const string PLAY_SPEED_MENU = "PlaySpeedMenu"; } + public class Filter + { + [SettingKey(typeof(object))] + public const string RECOMMEND_FILTER_RULE = "RecommendFilterRule"; + + [SettingKey(typeof(object))] + public const string SEARCH_FILTER_RULE = "SearchFilterRule"; + + [SettingKey(typeof(object))] + public const string DYNAMIC_FILTER_RULE = "DynamicFilterRule"; + } + public class Roaming { /// diff --git a/src/BiliLite.UWP/Models/Common/Settings/FilterRule.cs b/src/BiliLite.UWP/Models/Common/Settings/FilterRule.cs new file mode 100644 index 00000000..ddd751a5 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Settings/FilterRule.cs @@ -0,0 +1,17 @@ +namespace BiliLite.Models.Common.Settings +{ + public class FilterRule + { + public string Id { get; set; } + + public FilterRuleType FilterRuleType { get; set; } + + public FilterType FilterType { get; set; } + + public FilterContentType ContentType { get; set; } + + public string Rule { get; set; } + + public bool Enable { get; set; } + } +} diff --git a/src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs b/src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs new file mode 100644 index 00000000..e713190b --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; + +namespace BiliLite.Models.Common.Settings +{ + public class FilterRuleTypes + { + public static List FilterTypeOptions = new List() + { + new FilterTypeOption(FilterType.Word, "关键词"), + new FilterTypeOption(FilterType.Regular, "正则"), + }; + public static List FilterTargetOptions = new List() + { + new FilterTargetOption(FilterContentType.Title, "标题"), + new FilterTargetOption(FilterContentType.User, "用户"), + }; + } + + public class FilterTypeOption + { + public FilterTypeOption(){} + + public FilterTypeOption(FilterType type,string text) + { + Type = type; + Text = text; + } + + public FilterType Type { get; set; } + + public string Text { get; set; } + } + + public class FilterTargetOption + { + public FilterTargetOption() { } + + public FilterTargetOption(FilterContentType type, string text) + { + Type = type; + Text = text; + } + + public FilterContentType Type { get; set; } + + public string Text { get; set; } + } +} diff --git a/src/BiliLite.UWP/Modules/SearchVM.cs b/src/BiliLite.UWP/Modules/SearchVM.cs index e9dd9309..08dc5303 100644 --- a/src/BiliLite.UWP/Modules/SearchVM.cs +++ b/src/BiliLite.UWP/Modules/SearchVM.cs @@ -13,6 +13,7 @@ using BiliLite.Pages; using BiliLite.Models.Requests.Api; using BiliLite.Services; +using Microsoft.Extensions.DependencyInjection; namespace BiliLite.Modules { @@ -178,9 +179,11 @@ public ObservableCollection SuggestSearchContents public class SearchVideoVM : ISearchVM { ILogger _logger = GlobalLogger.FromCurrentType(); + private readonly ContentFilterService m_contentFilterService; public SearchVideoVM() { + m_contentFilterService = App.ServiceProvider.GetRequiredService(); OrderFilters = new List() { new SearchFilterItem("综合排序",""), new SearchFilterItem("最多点击","click"), @@ -260,7 +263,10 @@ public async override Task LoadData() { throw new CustomizedErrorException(data.message); } - var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); + var searchVideoItems = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); + searchVideoItems = m_contentFilterService.FilterSearchItems(searchVideoItems); + var result = new ObservableCollection(searchVideoItems); + if (Page == 1) { if (result == null || result.Count == 0) diff --git a/src/BiliLite.UWP/Pages/SettingPage.xaml b/src/BiliLite.UWP/Pages/SettingPage.xaml index 81fa15f0..8120d214 100644 --- a/src/BiliLite.UWP/Pages/SettingPage.xaml +++ b/src/BiliLite.UWP/Pages/SettingPage.xaml @@ -11,6 +11,7 @@ xmlns:covert="using:BiliLite.Converters" xmlns:controls="using:Microsoft.UI.Xaml.Controls" xmlns:controls1="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:common="using:BiliLite.Models.Common" xmlns:home="using:BiliLite.Models.Common.Home" + xmlns:controls2="using:BiliLite.Controls" Background="Transparent"> @@ -614,6 +615,14 @@ + + + 过滤 + + + + + 开发者选项 diff --git a/src/BiliLite.UWP/Services/ContentFilterService.cs b/src/BiliLite.UWP/Services/ContentFilterService.cs new file mode 100644 index 00000000..79b312ed --- /dev/null +++ b/src/BiliLite.UWP/Services/ContentFilterService.cs @@ -0,0 +1,215 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using BiliLite.Models.Common; +using BiliLite.Models.Common.Recommend; +using BiliLite.Models.Common.Settings; +using BiliLite.Modules; +using BiliLite.ViewModels.UserDynamic; + +namespace BiliLite.Services +{ + public class ContentFilterService + { + private static readonly ILogger _logger = GlobalLogger.FromCurrentType(); + + public List RecommendFilterRules { get; set; } + + public List SearchFilterRules { get; set; } + + public List DynamicFilterRules { get; set; } + + public ContentFilterService() + { + LoadFilterRules(); + } + + private void LoadFilterRules() + { + RecommendFilterRules = + SettingService.GetValue(SettingConstants.Filter.RECOMMEND_FILTER_RULE, new List()); + SearchFilterRules = + SettingService.GetValue(SettingConstants.Filter.SEARCH_FILTER_RULE, new List()); + DynamicFilterRules = + SettingService.GetValue(SettingConstants.Filter.DYNAMIC_FILTER_RULE, new List()); + } + + private void UpdateFilterRule(FilterRule target, FilterRule source) + { + target.ContentType = source.ContentType; + target.FilterType = source.FilterType; + target.Rule = source.Rule; + target.Enable = source.Enable; + } + + public void AddRecommendFilterRule(FilterRule filterRule) + { + RecommendFilterRules.Add(filterRule); + SettingService.SetValue(SettingConstants.Filter.RECOMMEND_FILTER_RULE, RecommendFilterRules); + } + + public void AddSearchFilterRule(FilterRule filterRule) + { + SearchFilterRules.Add(filterRule); + SettingService.SetValue(SettingConstants.Filter.SEARCH_FILTER_RULE, SearchFilterRules); + } + + public void AddDynamicFilterRule(FilterRule filterRule) + { + DynamicFilterRules.Add(filterRule); + SettingService.SetValue(SettingConstants.Filter.DYNAMIC_FILTER_RULE, DynamicFilterRules); + } + + public void DeleteFilterRule(FilterRule filterRule) + { + var recommendFilterRule = RecommendFilterRules.FirstOrDefault(x => x.Id == filterRule.Id); + if (recommendFilterRule != null) + { + RecommendFilterRules.Remove(recommendFilterRule); + SettingService.SetValue(SettingConstants.Filter.RECOMMEND_FILTER_RULE, RecommendFilterRules); + return; + } + var searchFilterRule = SearchFilterRules.FirstOrDefault(x => x.Id == filterRule.Id); + if (searchFilterRule != null) + { + SearchFilterRules.Remove(searchFilterRule); + SettingService.SetValue(SettingConstants.Filter.SEARCH_FILTER_RULE, SearchFilterRules); + return; + } + var dynamicFilterRule = DynamicFilterRules.FirstOrDefault(x => x.Id == filterRule.Id); + if (dynamicFilterRule != null) + { + DynamicFilterRules.Remove(dynamicFilterRule); + SettingService.SetValue(SettingConstants.Filter.DYNAMIC_FILTER_RULE, DynamicFilterRules); + return; + } + } + + public void UpdateFilterRule(FilterRule filterRule) + { + var recommendFilterRule = RecommendFilterRules.FirstOrDefault(x => x.Id == filterRule.Id); + if (recommendFilterRule != null) + { + UpdateFilterRule(recommendFilterRule,filterRule); + SettingService.SetValue(SettingConstants.Filter.RECOMMEND_FILTER_RULE, RecommendFilterRules); + return; + } + var searchFilterRule = SearchFilterRules.FirstOrDefault(x => x.Id == filterRule.Id); + if (searchFilterRule != null) + { + UpdateFilterRule(searchFilterRule, filterRule); + SettingService.SetValue(SettingConstants.Filter.SEARCH_FILTER_RULE, SearchFilterRules); + return; + } + var dynamicFilterRule = DynamicFilterRules.FirstOrDefault(x => x.Id == filterRule.Id); + if (dynamicFilterRule != null) + { + UpdateFilterRule(dynamicFilterRule, filterRule); + SettingService.SetValue(SettingConstants.Filter.DYNAMIC_FILTER_RULE, DynamicFilterRules); + return; + } + } + + public List FilterRecommendItems(List recommendItems) + { + if (RecommendFilterRules.Count == 0) + { + return recommendItems; + } + var query = recommendItems.AsEnumerable(); + query = RecommendFilterRules.Where(rule => rule.Enable) + .Aggregate(query, (current, rule) => rule.ContentType switch + { + FilterContentType.Title => rule.FilterType switch + { + FilterType.Word => current.Where(x => !x.Title.Contains(rule.Rule)), + FilterType.Regular => current.Where(x => !new Regex(rule.Rule).IsMatch(x.Title)), + _ => current + }, + FilterContentType.User => rule.FilterType switch + { + FilterType.Word => current.Where(x => !x.Args.UpName.Contains(rule.Rule)), + FilterType.Regular => current.Where(x => !new Regex(rule.Rule).IsMatch(x.Args.UpName)), + _ => current + }, + _ => current + }); + + var result = query.ToList(); + + _logger.Debug($"source recommendItems count:{recommendItems.Count};after filter:{result.Count}"); + //if (recommendItems.Count - result.Count > 0) + //{ + // Notify.ShowMessageToast($"过滤:{recommendItems.Count - result.Count}"); + //} + + return result; + } + + public List FilterSearchItems(List searchItems) + { + if (SearchFilterRules.Count == 0) + { + return searchItems; + } + var query = searchItems.AsEnumerable(); + query = SearchFilterRules.Where(rule => rule.Enable) + .Aggregate(query, (current, rule) => rule.ContentType switch + { + FilterContentType.Title => rule.FilterType switch + { + FilterType.Word => current.Where(x => !x.title.Contains(rule.Rule)), + FilterType.Regular => current.Where(x => !new Regex(rule.Rule).IsMatch(x.title)), + _ => current + }, + FilterContentType.User => rule.FilterType switch + { + FilterType.Word => current.Where(x => !x.author.Contains(rule.Rule)), + FilterType.Regular => current.Where(x => !new Regex(rule.Rule).IsMatch(x.author)), + _ => current + }, + _ => current + }); + + var result = query.ToList(); + + _logger.Debug($"source searchItems count:{searchItems.Count};after filter:{result.Count}"); + //if (searchItems.Count - result.Count > 0) + //{ + // Notify.ShowMessageToast($"过滤:{searchItems.Count - result.Count}"); + //} + + return result; + } + + public List FilterDynamicItems(List dynItems) + { + if (DynamicFilterRules.Count == 0) + { + return dynItems; + } + var query = dynItems.AsEnumerable(); + query = DynamicFilterRules.Where(rule => rule.Enable) + .Aggregate(query, (current, rule) => rule.ContentType switch + { + FilterContentType.User => rule.FilterType switch + { + FilterType.Word => current.Where(x => !(x.Author != null && x.Author.Author.Name.Contains(rule.Rule))), + FilterType.Regular => current.Where(x => !(x.Author != null && new Regex(rule.Rule).IsMatch(x.Author.Author.Name))), + _ => current + }, + _ => current + }); + + var result = query.ToList(); + + _logger.Debug($"source dynItems count:{dynItems.Count};after filter:{result.Count}"); + //if (dynItems.Count - result.Count > 0) + //{ + // Notify.ShowMessageToast($"过滤:{dynItems.Count - result.Count}"); + //} + + return result; + } + } +} diff --git a/src/BiliLite.UWP/Startup.cs b/src/BiliLite.UWP/Startup.cs index a1512da7..0ef8e47e 100644 --- a/src/BiliLite.UWP/Startup.cs +++ b/src/BiliLite.UWP/Startup.cs @@ -21,7 +21,8 @@ public void ConfigureServices(HostBuilderContext context, IServiceCollection ser services.AddQrCodeService(); services.AddBizServices(); services.AddSingleton(); - + services.AddSingleton(); + services.AddSingleton(); } } diff --git a/src/BiliLite.UWP/ViewModels/Home/RecommendPageViewModel.cs b/src/BiliLite.UWP/ViewModels/Home/RecommendPageViewModel.cs index 1646d83c..8300fb2c 100644 --- a/src/BiliLite.UWP/ViewModels/Home/RecommendPageViewModel.cs +++ b/src/BiliLite.UWP/ViewModels/Home/RecommendPageViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; @@ -21,13 +22,15 @@ public class RecommendPageViewModel : BaseViewModel private readonly RecommendAPI m_recommendApi; private static readonly ILogger _logger = GlobalLogger.FromCurrentType(); + private readonly ContentFilterService m_contentFilterService; #endregion #region Constructors - public RecommendPageViewModel() + public RecommendPageViewModel(ContentFilterService contentFilterService) { + m_contentFilterService = contentFilterService; m_recommendApi = new RecommendAPI(); Banner = new ObservableCollection(); RefreshCommand = new RelayCommand(Refresh); @@ -125,22 +128,23 @@ public async Task GetRecommend(string idx = "0") throw new CustomizedErrorException(obj["message"].ToString()); } - var items = JsonConvert.DeserializeObject>(obj["data"]["items"].ToString().Replace("left_bottom_rcmd_reason_style", "rcmd_reason_style")); - var banner = items.FirstOrDefault(x => x.CardGoto == "banner"); + var recommendItems = JsonConvert.DeserializeObject>(obj["data"]["items"].ToString().Replace("left_bottom_rcmd_reason_style", "rcmd_reason_style")); + + var banner = recommendItems.FirstOrDefault(x => x.CardGoto == "banner"); if (banner != null) { //处理banner LoadBanner(banner); - items.Remove(banner); + recommendItems.Remove(banner); } - for (var i = items.Count - 1; i >= 0; i--) + for (var i = recommendItems.Count - 1; i >= 0; i--) { - if (items[i].ShowAd) + if (recommendItems[i].ShowAd) { - items.Remove(items[i]); + recommendItems.Remove(recommendItems[i]); continue; } - var item = items[i]; + var item = recommendItems[i]; if (item.ThreePointV2 != null && item.ThreePointV2.Count > 0 && item.CardGoto == "av") { item.ThreePointV2.Insert(1, new RecommendThreePointV2ItemModel() @@ -153,6 +157,9 @@ public async Task GetRecommend(string idx = "0") } } + recommendItems = m_contentFilterService.FilterRecommendItems(recommendItems); + var items = new ObservableCollection(recommendItems); + if (Items == null) { Items = items; diff --git a/src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs b/src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs new file mode 100644 index 00000000..ee20292f --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs @@ -0,0 +1,53 @@ +using BiliLite.Models.Common; +using BiliLite.ViewModels.Common; +using PropertyChanged; + +namespace BiliLite.ViewModels.Settings +{ + public class FilterRuleViewModel : BaseViewModel + { + public string Id { get; set; } + + public FilterRuleType FilterRuleType { get; set; } + + public FilterType FilterType { get; set; } + + public FilterContentType ContentType { get; set; } + + public string Rule { get; set; } + + public bool Enable { get; set; } = true; + + [DependsOn(nameof(FilterType))] + public string RuleDesc + { + get + { + return FilterType switch + { + FilterType.Word => "输入关键词", + FilterType.Regular => "输入正则表达式", + _ => "" + }; + } + } + + [DoNotNotify] + public string FilterTypeDesc => "选择使用关键词过滤或正则表达式过滤"; + + [DoNotNotify] + public string FilterContentTypeDesc + { + get + { + var desc = "选择过滤目标对象属性"; + if (FilterRuleType == FilterRuleType.Dynamic) + { + return desc + "(动态不支持过滤标题)"; + } + + return desc; + } + } + } +} diff --git a/src/BiliLite.UWP/ViewModels/Settings/FilterSettingsViewModel.cs b/src/BiliLite.UWP/ViewModels/Settings/FilterSettingsViewModel.cs new file mode 100644 index 00000000..23c7b197 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Settings/FilterSettingsViewModel.cs @@ -0,0 +1,14 @@ +using System.Collections.ObjectModel; +using BiliLite.ViewModels.Common; + +namespace BiliLite.ViewModels.Settings +{ + public class FilterSettingsViewModel : BaseViewModel + { + public ObservableCollection RecommendFilterRules { get; set; } + + public ObservableCollection SearchFilterRules { get; set; } + + public ObservableCollection DynamicFilterRules { get; set; } + } +} diff --git a/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs b/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs index f66b5e89..240c819c 100644 --- a/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs +++ b/src/BiliLite.UWP/ViewModels/UserDynamic/UserDynamicAllViewModel.cs @@ -34,6 +34,7 @@ public class UserDynamicAllViewModel : BaseViewModel, IUserDynamicCommands private readonly IMapper m_mapper; private readonly DynamicAPI m_dynamicApi; private readonly WatchLaterVM m_watchLaterVm; + private readonly ContentFilterService m_contentFilterService; private int m_page = 1; private string m_offset = null; private string m_baseline = null; @@ -43,10 +44,11 @@ public class UserDynamicAllViewModel : BaseViewModel, IUserDynamicCommands #region Constructors - public UserDynamicAllViewModel(GrpcService grpcService, IMapper mapper) + public UserDynamicAllViewModel(GrpcService grpcService, IMapper mapper, ContentFilterService contentFilterService) { m_grpcService = grpcService; m_mapper = mapper; + m_contentFilterService = contentFilterService; m_dynamicApi = new DynamicAPI(); m_watchLaterVm = new WatchLaterVM(); LoadMoreCommand = new RelayCommand(LoadMore); @@ -238,6 +240,9 @@ private void HandleDynamicResults(DynAllReply results) m_offset = results.DynamicList.HistoryOffset; var items = m_mapper.Map>(results.DynamicList.List .Where(x => x.CardType != DynamicType.Banner).ToList()); + + items = m_contentFilterService.FilterDynamicItems(items); + foreach (var item in items) { item.Parent = this; From 4cacaa7348576470828ddd8cb2288484fa6de51a Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Mon, 15 Jul 2024 21:56:05 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E5=8F=98=E6=9B=B4=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E9=A1=B9=E6=8E=A7=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/BiliLite.UWP.csproj | 66 +- .../Controls/PlayerControl.xaml.cs | 27 +- .../Settings/AboutSettingsControl.xaml | 116 ++ .../Settings/AboutSettingsControl.xaml.cs | 42 + .../Controls/Settings/DevSettingsControl.xaml | 126 ++ .../Settings/DevSettingsControl.xaml.cs | 187 +++ .../Settings/DownloadSettingsControl.xaml | 103 ++ .../Settings/DownloadSettingsControl.xaml.cs | 125 ++ .../{ => Settings}/FilterSettingsControl.xaml | 13 +- .../FilterSettingsControl.xaml.cs | 2 +- .../Settings/LiveSettingsControl.xaml | 83 ++ .../Settings/LiveSettingsControl.xaml.cs | 70 + .../Settings/PlaySettingsControl.xaml | 283 ++++ .../Settings/PlaySettingsControl.xaml.cs | 286 ++++ .../Settings/ProxySettingsControl.xaml | 73 + .../Settings/ProxySettingsControl.xaml.cs | 145 ++ .../Controls/Settings/UISettingsControl.xaml | 302 +++++ .../Settings/UISettingsControl.xaml.cs | 323 +++++ .../Settings/VideoDanmakuSettingsControl.xaml | 159 +++ .../VideoDanmakuSettingsControl.xaml.cs | 156 +++ .../Extensions/ViewModelExtensions.cs | 3 + .../Models/Common/Danmaku/DanmuFilterItem.cs | 19 + src/BiliLite.UWP/Modules/SettingVM.cs | 330 ----- src/BiliLite.UWP/Modules/User/Account.cs | 2 - src/BiliLite.UWP/Pages/LiveDetailPage.xaml | 2 +- src/BiliLite.UWP/Pages/LiveDetailPage.xaml.cs | 19 +- src/BiliLite.UWP/Pages/SettingPage.xaml | 615 +-------- src/BiliLite.UWP/Pages/SettingPage.xaml.cs | 1196 +---------------- src/BiliLite.UWP/Services/MessageCenter.cs | 3 +- src/BiliLite.UWP/Themes/Dark.xaml | 3 +- src/BiliLite.UWP/Themes/Light.xaml | 3 +- .../Settings/CDNServerItemViewModel.cs | 25 + .../Settings/LiveSettingsControlViewModel.cs | 22 + .../Settings/PlaySettingsControlViewModel.cs | 63 + .../VideoDanmakuSettingsControlViewModel.cs | 146 ++ 35 files changed, 2974 insertions(+), 2164 deletions(-) create mode 100644 src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml.cs rename src/BiliLite.UWP/Controls/{ => Settings}/FilterSettingsControl.xaml (95%) rename src/BiliLite.UWP/Controls/{ => Settings}/FilterSettingsControl.xaml.cs (99%) create mode 100644 src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml.cs create mode 100644 src/BiliLite.UWP/Models/Common/Danmaku/DanmuFilterItem.cs delete mode 100644 src/BiliLite.UWP/Modules/SettingVM.cs create mode 100644 src/BiliLite.UWP/ViewModels/Settings/CDNServerItemViewModel.cs create mode 100644 src/BiliLite.UWP/ViewModels/Settings/LiveSettingsControlViewModel.cs create mode 100644 src/BiliLite.UWP/ViewModels/Settings/PlaySettingsControlViewModel.cs create mode 100644 src/BiliLite.UWP/ViewModels/Settings/VideoDanmakuSettingsControlViewModel.cs diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index a1b8a1b1..0cd55a56 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -143,12 +143,36 @@ DynamicItemV2Control.xaml - + + AboutSettingsControl.xaml + + + DevSettingsControl.xaml + + + DownloadSettingsControl.xaml + + FilterSettingsControl.xaml PlayerToast.xaml + + LiveSettingsControl.xaml + + + PlaySettingsControl.xaml + + + ProxySettingsControl.xaml + + + UISettingsControl.xaml + + + VideoDanmakuSettingsControl.xaml + UserFollowingTagsFlyout.xaml @@ -201,6 +225,8 @@ + + @@ -210,6 +236,9 @@ + + + UserDynamicPage.xaml @@ -732,7 +761,6 @@ - @@ -1026,7 +1054,19 @@ MSBuild:Compile Designer - + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + Designer MSBuild:Compile @@ -1034,6 +1074,26 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs b/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs index 7e77495f..0c333aaa 100644 --- a/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs +++ b/src/BiliLite.UWP/Controls/PlayerControl.xaml.cs @@ -42,6 +42,7 @@ using BiliLite.Models.Common.Video.PlayUrlInfos; using BiliLite.Services.Interfaces; using BiliLite.ViewModels; +using BiliLite.ViewModels.Settings; using Microsoft.Extensions.DependencyInjection; //https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 @@ -53,6 +54,7 @@ public sealed partial class PlayerControl : UserControl, IDisposable private static readonly ILogger _logger = GlobalLogger.FromCurrentType(); private readonly bool m_useNsDanmaku = true; private readonly IDanmakuController m_danmakuController; + private readonly VideoDanmakuSettingsControlViewModel m_danmakuSettingsControlViewModel; private readonly PlayControlViewModel m_viewModel; private readonly PlayerToastService m_playerToastService; private readonly PlaySpeedMenuService m_playSpeedMenuService; @@ -118,7 +120,6 @@ public BiliPlayUrlQualitesInfo playUrlInfo /// IDictionary> danmakuPool = new Dictionary>(); List danmakuLoadedSegment; - SettingVM settingVM; DisplayRequest dispRequest; SystemMediaTransportControls _systemMediaTransportControls; DispatcherTimer timer_focus; @@ -139,7 +140,7 @@ public PlayerControl() this.InitializeComponent(); dispRequest = new DisplayRequest(); playerHelper = new PlayerVM(); - settingVM = new SettingVM(); + m_danmakuSettingsControlViewModel = App.ServiceProvider.GetRequiredService(); danmakuParse = new NSDanmaku.Helper.DanmakuParse(); //每过2秒就设置焦点 @@ -627,7 +628,7 @@ private void LoadDanmuSetting() { m_danmakuController.Hide(); } - DanmuSettingWords.ItemsSource = settingVM.ShieldWords; + DanmuSettingWords.ItemsSource = m_danmakuSettingsControlViewModel.ShieldWords; } private void LoadPlayerSetting() { @@ -828,17 +829,17 @@ private List FilterFrostDanmaku(IEnumerable danmakus) danmakus = danmakus.DistinctIf(needDistinct, new CompareDanmakuItem()); //关键词 - foreach (var item in settingVM.ShieldWords) + foreach (var item in m_danmakuSettingsControlViewModel.ShieldWords) { danmakus = danmakus.Where(x => !x.Text.Contains(item)); } //用户 - foreach (var item in settingVM.ShieldUsers) + foreach (var item in m_danmakuSettingsControlViewModel.ShieldUsers) { danmakus = danmakus.Where(x => !x.MidHash.Equals(item)); } //正则 - foreach (var item in settingVM.ShieldRegulars) + foreach (var item in m_danmakuSettingsControlViewModel.ShieldRegulars) { danmakus = danmakus.Where(x => !Regex.IsMatch(x.Text, item)); } @@ -880,17 +881,17 @@ private async Task SelectNsDanmakuAndLoad(int position, double level, bool needD data = data.Distinct(new CompareDanmakuModel()); } //关键词 - foreach (var item in settingVM.ShieldWords) + foreach (var item in m_danmakuSettingsControlViewModel.ShieldWords) { data = data.Where(x => !x.text.Contains(item)); } //用户 - foreach (var item in settingVM.ShieldUsers) + foreach (var item in m_danmakuSettingsControlViewModel.ShieldUsers) { data = data.Where(x => !x.sendID.Equals(item)); } //正则 - foreach (var item in settingVM.ShieldRegulars) + foreach (var item in m_danmakuSettingsControlViewModel.ShieldRegulars) { data = data.Where(x => !Regex.IsMatch(x.text, item)); } @@ -2650,7 +2651,7 @@ private async void BottomBtnSendDanmakuWide_Click(object sender, RoutedEventArgs private async void DanmuSettingSyncWords_Click(object sender, RoutedEventArgs e) { - await settingVM.SyncDanmuFilter(); + await m_danmakuSettingsControlViewModel.SyncDanmuFilter(); } private async void DanmuSettingAddWord_Click(object sender, RoutedEventArgs e) @@ -2660,9 +2661,9 @@ private async void DanmuSettingAddWord_Click(object sender, RoutedEventArgs e) Notify.ShowMessageToast("关键词不能为空"); return; } - settingVM.ShieldWords.Add(DanmuSettingTxtWord.Text); - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, settingVM.ShieldWords); - var result = await settingVM.AddDanmuFilterItem(DanmuSettingTxtWord.Text, 0); + m_danmakuSettingsControlViewModel.ShieldWords.Add(DanmuSettingTxtWord.Text); + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, m_danmakuSettingsControlViewModel.ShieldWords); + var result = await m_danmakuSettingsControlViewModel.AddDanmuFilterItem(DanmuSettingTxtWord.Text, 0); DanmuSettingTxtWord.Text = ""; if (!result) { diff --git a/src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml new file mode 100644 index 00000000..28758a24 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml @@ -0,0 +1,116 @@ + + + + + + 版本 1.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 开发者 + xiaoyaocz + 维护者 + ywmoyue + Logo绘制 + xiaoyaomengo + + + + + + + + + + + + + + + + Github Discussions : https://github.com/ywmoyue/biliuwp-lite/discussions + 邮箱(请在发邮件时附带Github Discussion贴子链接) : ruamuyan@outlook.com + + + + + + + + + + + + + + + + 这是一个第三方客户端,应用所有数据来源均来自哔哩哔哩。 + 本程序仅供学习交流编程技术使用。 + 如果侵犯您的合法权益,请及时联系本人以第一时间删除。 + + + + + + + + + + + + + + + + 哔哩哔哩官网 + 隐私策略 + 开源代码许可/项目引用 + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml.cs new file mode 100644 index 00000000..18df4bcf --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/AboutSettingsControl.xaml.cs @@ -0,0 +1,42 @@ +using System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Extensions; +using BiliLite.Models.Common; +using BiliLite.Services; +using Microsoft.Toolkit.Uwp.Helpers; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class AboutSettingsControl : UserControl + { + public AboutSettingsControl() + { + this.InitializeComponent(); + } + + private async void btnCheckUpdate_Click(object sender, RoutedEventArgs e) + { + await BiliExtensions.CheckVersion(); + } + + private void btnCleanUpdateIgnore_Click(object sender, RoutedEventArgs e) + { + SettingService.SetValue(SettingConstants.Other.IGNORE_VERSION, ""); + } + + private async void AboutSettingsControl_OnLoaded(object sender, RoutedEventArgs e) + { + try + { + version.Text = $"版本 {SystemInformation.ApplicationVersion.Major}.{SystemInformation.ApplicationVersion.Minor}.{SystemInformation.ApplicationVersion.Build}.{SystemInformation.ApplicationVersion.Revision}"; + } + catch (Exception) + { + throw; + } + } + } +} diff --git a/src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml new file mode 100644 index 00000000..cca3bbd5 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Trace + Debug + Info + Warn + Error + Fatal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 用于解决github在国内访问不佳的问题 + 第三方公益镜像捐赠地址-赠人玫瑰, 手有余香. + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml.cs new file mode 100644 index 00000000..0fe6adb9 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/DevSettingsControl.xaml.cs @@ -0,0 +1,187 @@ +using System; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Extensions; +using BiliLite.Models.Common; +using BiliLite.Services; +using Microsoft.Extensions.DependencyInjection; +using Windows.ApplicationModel.Core; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class DevSettingsControl : UserControl + { + public DevSettingsControl() + { + this.InitializeComponent(); + LoadDev(); + } + + private void LoadDev() + { + //自动清理日志文件 + swAutoClearLogFile.IsOn = SettingService.GetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE, true); + swAutoClearLogFile.Toggled += new RoutedEventHandler((e, args) => + { + SettingService.SetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE, swAutoClearLogFile.IsOn); + }); + //自动清理多少天前的日志文件 + numAutoClearLogDay.Value = SettingService.GetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE_DAY, 7); + numAutoClearLogDay.ValueChanged += ((e, args) => + { + SettingService.SetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE_DAY, numAutoClearLogDay.Value); + }); + //保护日志敏感信息 + swProtectLogInfo.IsOn = SettingService.GetValue(SettingConstants.Other.PROTECT_LOG_INFO, true); + swProtectLogInfo.Toggled += ((e, args) => + { + SettingService.SetValue(SettingConstants.Other.PROTECT_LOG_INFO, swProtectLogInfo.IsOn); + }); + // 日志级别 + cbLogLevel.SelectedIndex = SettingService.GetValue(SettingConstants.Other.LOG_LEVEL, 2); + cbLogLevel.Loaded += (sender, e) => + { + cbLogLevel.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.Other.LOG_LEVEL, cbLogLevel.SelectedIndex); + }; + }; + + // 优先使用Grpc请求动态 + swFirstGrpcRequestDynamic.IsOn = SettingService.GetValue(SettingConstants.Other.FIRST_GRPC_REQUEST_DYNAMIC, true); + swFirstGrpcRequestDynamic.Toggled += ((e, args) => + { + SettingService.SetValue(SettingConstants.Other.FIRST_GRPC_REQUEST_DYNAMIC, swFirstGrpcRequestDynamic.IsOn); + }); + + RequestBuildTextBox.Text = SettingService.GetValue(SettingConstants.Other.REQUEST_BUILD, + SettingConstants.Other.DEFAULT_REQUEST_BUILD); + + // BiliLiteWebApi + BiliLiteWebApiTextBox.Text = SettingService.GetValue(SettingConstants.Other.BILI_LITE_WEB_API_BASE_URL, ApiConstants.BILI_LITE_WEB_API_DEFAULT_BASE_URL); + BiliLiteWebApiTextBox.Loaded += (sender, e) => + { + BiliLiteWebApiTextBox.QuerySubmitted += (sender2, args) => + { + var text = sender2.Text; + if (string.IsNullOrEmpty(text)) + { + Notify.ShowMessageToast("已取消自定义BiliLiteWebApi服务器"); + SettingService.SetValue(SettingConstants.Other.BILI_LITE_WEB_API_BASE_URL, ""); + return; + } + if (!text.EndsWith("/")) text += "/"; + if (!Uri.IsWellFormedUriString(text, UriKind.Absolute)) + { + Notify.ShowMessageToast("地址格式错误"); + return; + } + SettingService.SetValue(SettingConstants.Other.BILI_LITE_WEB_API_BASE_URL, text); + sender2.Text = text; + Notify.ShowMessageToast("保存成功"); + }; + }; + + // 更新json来源 + var selectedValue = SettingService.GetValue(SettingConstants.Other.UPDATE_JSON_ADDRESS, UpdateJsonAddressOptions.DEFAULT_UPDATE_JSON_ADDRESS); + selectedValue = selectedValue.Replace("\"", ""); // 解决取出的值有奇怪的转义符 + updateJsonAddress.SelectedItem = UpdateJsonAddressOptions.GetOption(selectedValue); + mirrorComboboxSelectAction(selectedValue); + updateJsonAddress.Loaded += (sender, e) => + { + updateJsonAddress.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.Other.UPDATE_JSON_ADDRESS, updateJsonAddress.SelectedValue); + mirrorComboboxSelectAction(updateJsonAddress.SelectedValue); + }; + }; + } + + private void RequestBuildSaveBtn_OnClick(object sender, RoutedEventArgs e) + { + var build = RequestBuildTextBox.Text; + if (string.IsNullOrWhiteSpace(build)) + { + Notify.ShowMessageToast("请输入正确的build值"); + return; + } + + SettingService.SetValue(SettingConstants.Other.REQUEST_BUILD, build); + Notify.ShowMessageToast("已保存"); + } + + private void RequestBuildDefaultBtn_OnClick(object sender, RoutedEventArgs e) + { + var build = SettingConstants.Other.DEFAULT_REQUEST_BUILD; + SettingService.SetValue(SettingConstants.Other.REQUEST_BUILD, build); + RequestBuildTextBox.Text = build; + Notify.ShowMessageToast("已恢复默认"); + } + + private void mirrorComboboxSelectAction(object selectedValue) + { + switch (selectedValue) + { + case ApiHelper.GHPROXY_GIT_RAW_URL: + { + mirrorDonateText.Visibility = Visibility.Visible; + mirrorDonateUrl.NavigateUri = new Uri("https://mirror.ghproxy.com/donate"); + break; + } + case ApiHelper.KGITHUB_GIT_RAW_URL: + { + mirrorDonateText.Visibility = Visibility.Visible; + mirrorDonateUrl.NavigateUri = new Uri("https://help.kkgithub.com/donate"); + break; + } + case ApiHelper.GIT_RAW_URL: + { + mirrorDonateText.Visibility = Visibility.Collapsed; break; + } + default: + { + mirrorDonateText.Visibility = Visibility.Collapsed; break; + } + } + } + + private async void BtnExportSettings_OnClick(object sender, RoutedEventArgs e) + { + var exportService = App.ServiceProvider.GetRequiredService(); + await exportService.ExportSettings(); + } + + private async void BtnImportSettings_OnClick(object sender, RoutedEventArgs e) + { + var importService = App.ServiceProvider.GetRequiredService(); + if (!await importService.ImportSettings()) + { + return; + } + Notify.ShowMessageToast("导入成功,正在重启应用"); + // 等用户看提示 + await Task.Delay(3000); + var result = await CoreApplication.RequestRestartAsync(""); + + if (result == AppRestartFailureReason.NotInForeground || result == AppRestartFailureReason.Other) + { + Notify.ShowMessageToast("重启失败,请手动重启应用"); + } + } + + private async void BtnExportSettingsWithAccount_OnClick(object sender, RoutedEventArgs e) + { + var exportService = App.ServiceProvider.GetRequiredService(); + await exportService.ExportSettingsWithAccount(); + } + + private async void BtnOpenLogFolder_OnClick(object sender, RoutedEventArgs e) + { + var path = Windows.Storage.ApplicationData.Current.LocalFolder.Path + @"\log\"; + await Windows.System.Launcher.LaunchFolderPathAsync(path); + } + } +} diff --git a/src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml new file mode 100644 index 00000000..80e269af --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml.cs new file mode 100644 index 00000000..1e653050 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/DownloadSettingsControl.xaml.cs @@ -0,0 +1,125 @@ +using System; +using Windows.Storage; +using Windows.Storage.Pickers; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Models.Common; +using BiliLite.Services; +using BiliLite.ViewModels.Download; +using Microsoft.Extensions.DependencyInjection; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class DownloadSettingsControl : UserControl + { + private readonly DownloadPageViewModel m_downloadPageViewModel; + + public DownloadSettingsControl() + { + m_downloadPageViewModel = App.ServiceProvider.GetRequiredService(); + this.InitializeComponent(); + LoadDownlaod(); + } + + private void LoadDownlaod() + { + //下载路径 + txtDownloadPath.Text = SettingService.GetValue(SettingConstants.Download.DOWNLOAD_PATH, SettingConstants.Download.DEFAULT_PATH); + DownloadOpenPath.Click += new RoutedEventHandler(async (e, args) => + { + if (txtDownloadPath.Text == SettingConstants.Download.DEFAULT_PATH) + { + var videosLibrary = Windows.Storage.KnownFolders.VideosLibrary; + videosLibrary = await videosLibrary.CreateFolderAsync("哔哩哔哩下载", CreationCollisionOption.OpenIfExists); + + await Windows.System.Launcher.LaunchFolderAsync(videosLibrary); + } + else + { + await Windows.System.Launcher.LaunchFolderPathAsync(txtDownloadPath.Text); + } + }); + DownloadChangePath.Click += new RoutedEventHandler(async (e, args) => + { + FolderPicker folderPicker = new FolderPicker(); + folderPicker.FileTypeFilter.Add("*"); + folderPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary; + var folder = await folderPicker.PickSingleFolderAsync(); + if (folder != null) + { + SettingService.SetValue(SettingConstants.Download.DOWNLOAD_PATH, folder.Path); + txtDownloadPath.Text = folder.Path; + Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(folder); + m_downloadPageViewModel.RefreshDownloaded(); + } + }); + //旧版下载目录 + txtDownloadOldPath.Text = SettingService.GetValue(SettingConstants.Download.OLD_DOWNLOAD_PATH, SettingConstants.Download.DEFAULT_OLD_PATH); + DownloadOpenOldPath.Click += new RoutedEventHandler(async (e, args) => + { + if (txtDownloadOldPath.Text == SettingConstants.Download.DEFAULT_OLD_PATH) + { + var videosLibrary = Windows.Storage.KnownFolders.VideosLibrary; + videosLibrary = await videosLibrary.CreateFolderAsync("BiliBiliDownload", CreationCollisionOption.OpenIfExists); + await Windows.System.Launcher.LaunchFolderAsync(videosLibrary); + } + else + { + await Windows.System.Launcher.LaunchFolderPathAsync(txtDownloadOldPath.Text); + } + }); + DownloadChangeOldPath.Click += new RoutedEventHandler(async (e, args) => + { + FolderPicker folderPicker = new FolderPicker(); + folderPicker.FileTypeFilter.Add("*"); + folderPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary; + var folder = await folderPicker.PickSingleFolderAsync(); + if (folder != null) + { + SettingService.SetValue(SettingConstants.Download.OLD_DOWNLOAD_PATH, folder.Path); + txtDownloadOldPath.Text = folder.Path; + Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(folder); + } + }); + + //并行下载 + swDownloadParallelDownload.IsOn = SettingService.GetValue(SettingConstants.Download.PARALLEL_DOWNLOAD, true); + swDownloadParallelDownload.Toggled += new RoutedEventHandler((e, args) => + { + SettingService.SetValue(SettingConstants.Download.PARALLEL_DOWNLOAD, swDownloadParallelDownload.IsOn); + m_downloadPageViewModel.UpdateSetting(); + }); + //付费网络下载 + swDownloadAllowCostNetwork.IsOn = SettingService.GetValue(SettingConstants.Download.ALLOW_COST_NETWORK, false); + swDownloadAllowCostNetwork.Toggled += new RoutedEventHandler((e, args) => + { + SettingService.SetValue(SettingConstants.Download.ALLOW_COST_NETWORK, swDownloadAllowCostNetwork.IsOn); + m_downloadPageViewModel.UpdateSetting(); + }); + //下载完成发送通知 + swDownloadSendToast.IsOn = SettingService.GetValue(SettingConstants.Download.SEND_TOAST, false); + swDownloadSendToast.Toggled += new RoutedEventHandler((e, args) => + { + SettingService.SetValue(SettingConstants.Download.SEND_TOAST, swDownloadSendToast.IsOn); + }); + //下载类型 + var selectedValue = (PlayUrlCodecMode)SettingService.GetValue(SettingConstants.Download.DEFAULT_VIDEO_TYPE, (int)DefaultVideoTypeOptions.DEFAULT_VIDEO_TYPE); + cbDownloadVideoType.SelectedItem = DefaultVideoTypeOptions.GetOption(selectedValue); + cbDownloadVideoType.Loaded += (sender, e) => + { + cbDownloadVideoType.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.Download.DEFAULT_VIDEO_TYPE, (int)cbDownloadVideoType.SelectedValue); + }; + }; + //加载旧版本下载的视频 + swDownloadLoadOld.IsOn = SettingService.GetValue(SettingConstants.Download.LOAD_OLD_DOWNLOAD, false); + swDownloadLoadOld.Toggled += new RoutedEventHandler((e, args) => + { + SettingService.SetValue(SettingConstants.Download.LOAD_OLD_DOWNLOAD, swDownloadLoadOld.IsOn); + }); + } + } +} diff --git a/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/FilterSettingsControl.xaml similarity index 95% rename from src/BiliLite.UWP/Controls/FilterSettingsControl.xaml rename to src/BiliLite.UWP/Controls/Settings/FilterSettingsControl.xaml index 71443821..afb997fa 100644 --- a/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml +++ b/src/BiliLite.UWP/Controls/Settings/FilterSettingsControl.xaml @@ -1,8 +1,8 @@  - + @@ -64,7 +65,10 @@ @@ -109,7 +113,10 @@ diff --git a/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/FilterSettingsControl.xaml.cs similarity index 99% rename from src/BiliLite.UWP/Controls/FilterSettingsControl.xaml.cs rename to src/BiliLite.UWP/Controls/Settings/FilterSettingsControl.xaml.cs index c3385e04..ced8fd70 100644 --- a/src/BiliLite.UWP/Controls/FilterSettingsControl.xaml.cs +++ b/src/BiliLite.UWP/Controls/Settings/FilterSettingsControl.xaml.cs @@ -13,7 +13,7 @@ //https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 -namespace BiliLite.Controls +namespace BiliLite.Controls.Settings { public sealed partial class FilterSettingsControl : UserControl { diff --git a/src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml new file mode 100644 index 00000000..275bd85e --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml.cs new file mode 100644 index 00000000..280dab1e --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/LiveSettingsControl.xaml.cs @@ -0,0 +1,70 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Extensions; +using BiliLite.Models.Common; +using BiliLite.Services; +using BiliLite.ViewModels.Settings; +using Microsoft.Extensions.DependencyInjection; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class LiveSettingsControl : UserControl + { + private readonly LiveSettingsControlViewModel m_viewModel; + + public LiveSettingsControl() + { + m_viewModel = App.ServiceProvider.GetRequiredService(); + this.InitializeComponent(); + LoadLiveDanmu(); + } + + private void LoadLiveDanmu() + { + // 弹幕引擎 + cbLiveDanmakuEngine.SelectedValue = SettingService.GetValue(SettingConstants.Live.DANMAKU_ENGINE, (int)SettingConstants.Live.DEFAULT_DANMAKU_ENGINE); + cbLiveDanmakuEngine.Loaded += (sender, e) => + { + cbLiveDanmakuEngine.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.Live.DANMAKU_ENGINE, cbLiveDanmakuEngine.SelectedValue); + }; + }; + //弹幕开关 + var state = SettingService.GetValue(SettingConstants.Live.SHOW, Visibility.Visible) == Visibility.Visible; + LiveDanmuSettingState.IsOn = state; + LiveDanmuSettingState.Toggled += new RoutedEventHandler((e, args) => + { + SettingService.SetValue(SettingConstants.Live.SHOW, LiveDanmuSettingState.IsOn ? Visibility.Visible : Visibility.Collapsed); + }); + //弹幕关键词 + LiveDanmuSettingListWords.ItemsSource = m_viewModel.LiveShieldWords; + } + + private void LiveDanmuSettingAddWord_Click(object sender, RoutedEventArgs e) + { + if (string.IsNullOrEmpty(LiveDanmuSettingTxtWord.Text)) + { + Notify.ShowMessageToast("关键字不能为空"); + return; + } + if (!m_viewModel.LiveShieldWords.Contains(LiveDanmuSettingTxtWord.Text)) + { + m_viewModel.LiveShieldWords.Add(LiveDanmuSettingTxtWord.Text); + SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, m_viewModel.LiveShieldWords); + } + + LiveDanmuSettingTxtWord.Text = ""; + SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, m_viewModel.LiveShieldWords); + } + + private void RemoveLiveDanmuWord_Click(object sender, RoutedEventArgs e) + { + var word = (sender as AppBarButton).DataContext as string; + m_viewModel.LiveShieldWords.Remove(word); + SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, m_viewModel.LiveShieldWords); + } + } +} diff --git a/src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml new file mode 100644 index 00000000..6f97b1d1 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml @@ -0,0 +1,283 @@ + + + + + + + + + 视频编码为HEVC时系统需要 + 安装HEVC扩展 + + + + + 视频编码为AV1时系统需要 + 安装AV1扩展 + ,部分清晰度可能也需要HEVC扩展 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 部分自动生成的AI字幕会与视频自带字幕冲突 + 建议关闭,有需要时再手动打开字幕 + + + + + + + + + + + + + + + + + + + + + + + + + + 替换CDN链接可以有效的提升视频加载速度 + 开启替换后读取播放地址可能需要更长时间 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 【】 + + + + 超时 + ms + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml.cs new file mode 100644 index 00000000..55013533 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/PlaySettingsControl.xaml.cs @@ -0,0 +1,286 @@ +using BiliLite.Dialogs; +using Microsoft.Extensions.DependencyInjection; +using System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Models.Common; +using BiliLite.Services; +using BiliLite.ViewModels.Settings; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class PlaySettingsControl : UserControl + { + private readonly PlaySettingsControlViewModel m_viewModel; + + public PlaySettingsControl() + { + m_viewModel = App.ServiceProvider.GetRequiredService(); + this.InitializeComponent(); + LoadPlayer(); + } + + private void LoadPlayer() + { + //播放类型 + var selectedValue = (PlayUrlCodecMode)SettingService.GetValue(SettingConstants.Player.DEFAULT_VIDEO_TYPE, (int)DefaultVideoTypeOptions.DEFAULT_VIDEO_TYPE); + cbVideoType.SelectedItem = DefaultVideoTypeOptions.GetOption(selectedValue); + cbVideoType.SelectionChanged += (e, args) => + { + SettingService.SetValue(SettingConstants.Player.DEFAULT_VIDEO_TYPE, (int)cbVideoType.SelectedValue); + }; + //视频倍速 + //cbVideoSpeed.SelectedIndex = SettingConstants.Player.VideoSpeed.IndexOf(SettingService.GetValue(SettingConstants.Player.DEFAULT_VIDEO_SPEED, 1.0d)); + //cbVideoSpeed.Loaded += new RoutedEventHandler((sender, e) => + //{ + // cbVideoSpeed.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + // { + // SettingService.SetValue(SettingConstants.Player.DEFAULT_VIDEO_SPEED, SettingConstants.Player.VideoSpeed[cbVideoSpeed.SelectedIndex]); + // }); + //}); + + //硬解视频 + //swHardwareDecode.IsOn = SettingService.GetValue(SettingConstants.Player.HARDWARE_DECODING, true); + //swHardwareDecode.Loaded += new RoutedEventHandler((sender, e) => + //{ + // swHardwareDecode.Toggled += new RoutedEventHandler((obj, args) => + // { + // SettingService.SetValue(SettingConstants.Player.HARDWARE_DECODING, swHardwareDecode.IsOn); + // }); + //}); + //自动播放 + swAutoPlay.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_PLAY, false); + swAutoPlay.Loaded += new RoutedEventHandler((sender, e) => + { + swAutoPlay.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.AUTO_PLAY, swAutoPlay.IsOn); + }); + }); + //自动跳转下一P + swAutoNext.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_NEXT, true); + swAutoNext.Loaded += new RoutedEventHandler((sender, e) => + { + swAutoNext.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.AUTO_NEXT, swAutoNext.IsOn); + }); + }); + //使用其他网站 + //swPlayerSettingUseOtherSite.IsOn = SettingService.GetValue(SettingConstants.Player.USE_OTHER_SITEVIDEO, false); + //swPlayerSettingUseOtherSite.Loaded += new RoutedEventHandler((sender, e) => + //{ + // swPlayerSettingUseOtherSite.Toggled += new RoutedEventHandler((obj, args) => + // { + // SettingService.SetValue(SettingConstants.Player.USE_OTHER_SITEVIDEO, swPlayerSettingUseOtherSite.IsOn); + // }); + //}); + + //自动跳转进度 + swPlayerSettingAutoToPosition.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_TO_POSITION, true); + swPlayerSettingAutoToPosition.Loaded += new RoutedEventHandler((sender, e) => + { + swPlayerSettingAutoToPosition.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.AUTO_TO_POSITION, swPlayerSettingAutoToPosition.IsOn); + }); + }); + //自动铺满屏幕 + swPlayerSettingAutoFullWindows.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_FULL_WINDOW, false); + swPlayerSettingAutoFullWindows.Loaded += new RoutedEventHandler((sender, e) => + { + swPlayerSettingAutoFullWindows.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.AUTO_FULL_WINDOW, swPlayerSettingAutoFullWindows.IsOn); + }); + }); + //自动全屏 + swPlayerSettingAutoFullScreen.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_FULL_SCREEN, false); + swPlayerSettingAutoFullScreen.Loaded += new RoutedEventHandler((sender, e) => + { + swPlayerSettingAutoFullScreen.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.AUTO_FULL_SCREEN, swPlayerSettingAutoFullScreen.IsOn); + }); + }); + + + //双击全屏 + swPlayerSettingDoubleClickFullScreen.IsOn = SettingService.GetValue(SettingConstants.Player.DOUBLE_CLICK_FULL_SCREEN, false); + swPlayerSettingDoubleClickFullScreen.Loaded += new RoutedEventHandler((sender, e) => + { + swPlayerSettingDoubleClickFullScreen.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.DOUBLE_CLICK_FULL_SCREEN, swPlayerSettingDoubleClickFullScreen.IsOn); + }); + }); + + // 方向键右键行为 + cbPlayerKeyRightAction.SelectedIndex = SettingService.GetValue(SettingConstants.Player.PLAYER_KEY_RIGHT_ACTION, (int)PlayerKeyRightAction.ControlProgress); + cbPlayerKeyRightAction.Loaded += (sender, e) => + { + cbPlayerKeyRightAction.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.PLAYER_KEY_RIGHT_ACTION, cbPlayerKeyRightAction.SelectedIndex); + }; + }; + + // 按住手势行为 + cbPlayerHoldingGestureAction.SelectedIndex = SettingService.GetValue(SettingConstants.Player.HOLDING_GESTURE_ACTION, (int)PlayerHoldingAction.None); + cbPlayerHoldingGestureAction.Loaded += (sender, e) => + { + cbPlayerHoldingGestureAction.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.HOLDING_GESTURE_ACTION, cbPlayerHoldingGestureAction.SelectedIndex); + }; + }; + + // 按住手势可被其他手势取消 + swPlayerHoldingGestureCanCancel.IsOn = SettingService.GetValue(SettingConstants.Player.HOLDING_GESTURE_CAN_CANCEL, true); + swPlayerHoldingGestureCanCancel.Loaded += (sender, e) => + { + swPlayerHoldingGestureCanCancel.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.HOLDING_GESTURE_CAN_CANCEL, swPlayerHoldingGestureCanCancel.IsOn); + }; + }; + + // 倍速播放速度 + cbRatePlaySpeed.SelectedIndex = SettingConstants.Player.HIGH_RATE_PLAY_SPEED_LIST.IndexOf(SettingService.GetValue(SettingConstants.Player.HIGH_RATE_PLAY_SPEED, 2.0d)); + cbRatePlaySpeed.Loaded += (sender, e) => + { + cbRatePlaySpeed.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.HIGH_RATE_PLAY_SPEED, SettingConstants.Player.HIGH_RATE_PLAY_SPEED_LIST[cbRatePlaySpeed.SelectedIndex]); + }; + }; + + // 音量 + NumBoxVolume.Value = Math.Round((SettingService.GetValue(SettingConstants.Player.PLAYER_VOLUME, + SettingConstants.Player.DEFAULT_PLAYER_VOLUME)) * 100, 2); + NumBoxVolume.Loaded += (sender, e) => + { + NumBoxVolume.ValueChanged += (obj, args) => + { + if (NumBoxVolume.Value > 100) + { + NumBoxVolume.Value = 100; + } + + if (NumBoxVolume.Value < 0) + { + NumBoxVolume.Value = 0; + } + SettingService.SetValue(SettingConstants.Player.PLAYER_VOLUME, NumBoxVolume.Value / 100); + }; + }; + + // 锁定播放器音量设置 + SwLockPlayerVolume.IsOn = SettingService.GetValue(SettingConstants.Player.LOCK_PLAYER_VOLUME, SettingConstants.Player.DEFAULT_LOCK_PLAYER_VOLUME); + SwLockPlayerVolume.Loaded += (sender, e) => + { + SwLockPlayerVolume.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.LOCK_PLAYER_VOLUME, SwLockPlayerVolume.IsOn); + }; + }; + + // 亮度 + NumBoxBrightness.Value = Math.Round( + (Math.Abs(SettingService.GetValue( + SettingConstants.Player.PLAYER_BRIGHTNESS, + SettingConstants.Player.DEFAULT_PLAYER_BRIGHTNESS) - 1)) * 100, 2); + NumBoxBrightness.Loaded += (sender, e) => + { + NumBoxBrightness.ValueChanged += (obj, args) => + { + if (NumBoxBrightness.Value > 100) + { + NumBoxBrightness.Value = 100; + } + + if (NumBoxBrightness.Value < 0) + { + NumBoxBrightness.Value = 0; + } + + var brightness = Math.Abs((NumBoxBrightness.Value / 100) - 1); + SettingService.SetValue(SettingConstants.Player.PLAYER_BRIGHTNESS, brightness); + }; + }; + + // 锁定播放器亮度设置 + SwLockPlayerBrightness.IsOn = SettingService.GetValue(SettingConstants.Player.LOCK_PLAYER_BRIGHTNESS, SettingConstants.Player.DEFAULT_LOCK_PLAYER_BRIGHTNESS); + SwLockPlayerBrightness.Loaded += (sender, e) => + { + SwLockPlayerBrightness.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.LOCK_PLAYER_BRIGHTNESS, SwLockPlayerBrightness.IsOn); + }; + }; + + //自动打开AI字幕 + swPlayerSettingAutoOpenAISubtitle.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_OPEN_AI_SUBTITLE, false); + swPlayerSettingAutoOpenAISubtitle.Loaded += new RoutedEventHandler((sender, e) => + { + swPlayerSettingAutoOpenAISubtitle.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.AUTO_OPEN_AI_SUBTITLE, swPlayerSettingAutoOpenAISubtitle.IsOn); + }); + }); + //上报历史纪录 + SwitchPlayerReportHistory.IsOn = SettingService.GetValue(SettingConstants.Player.REPORT_HISTORY, SettingConstants.Player.DEFAULT_REPORT_HISTORY); + SwitchPlayerReportHistory.Loaded += (sender, e) => + { + SwitchPlayerReportHistory.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.REPORT_HISTORY, SwitchPlayerReportHistory.IsOn); + }; + }; + + //视频结束上报历史纪录0 + SwitchReportHistoryZeroWhenVideoEnd.IsOn = SettingService.GetValue(SettingConstants.Player.REPORT_HISTORY_ZERO_WHEN_VIDEO_END, SettingConstants.Player.DEFAULT_REPORT_HISTORY_ZERO_WHEN_VIDEO_END); + SwitchReportHistoryZeroWhenVideoEnd.Loaded += (sender, e) => + { + SwitchReportHistoryZeroWhenVideoEnd.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.Player.REPORT_HISTORY_ZERO_WHEN_VIDEO_END, SwitchReportHistoryZeroWhenVideoEnd.IsOn); + }; + }; + //替换CDN + cbPlayerReplaceCDN.SelectedIndex = SettingService.GetValue(SettingConstants.Player.REPLACE_CDN, 3); + cbPlayerReplaceCDN.Loaded += new RoutedEventHandler((sender, e) => + { + cbPlayerReplaceCDN.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Player.REPLACE_CDN, cbPlayerReplaceCDN.SelectedIndex); + }); + }); + //CDN服务器 + var cdnServer = SettingService.GetValue(SettingConstants.Player.CDN_SERVER, "upos-sz-mirrorhwo1.bilivideo.com"); + RoamingSettingCDNServer.SelectedIndex = m_viewModel.CDNServers.FindIndex(x => x.Server == cdnServer); + RoamingSettingCDNServer.Loaded += new RoutedEventHandler((sender, e) => + { + RoamingSettingCDNServer.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + var server = m_viewModel.CDNServers[RoamingSettingCDNServer.SelectedIndex]; + SettingService.SetValue(SettingConstants.Player.CDN_SERVER, server.Server); + + }); + }); + } + + private async void BtnEditPlaySpeedMenu_OnClick(object sender, RoutedEventArgs e) + { + var dialog = App.ServiceProvider.GetRequiredService(); + await dialog.ShowAsync(); + } + + private void RoamingSettingTestCDN_Click(object sender, RoutedEventArgs e) + { + m_viewModel.CDNServerDelayTest(); + } + } +} diff --git a/src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml new file mode 100644 index 00000000..3af16c99 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml @@ -0,0 +1,73 @@ + + + + + + + + + + 默认服务器不稳定,建议自定义服务器 + 查看公共服务器 + + + 部分解析服务器需要登录后才能使用,请选择自己信任的服务器 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 如播放港澳台视频卡顿,建议到「播放」设置中打开替换CDN选项,并且选择延迟较低的CDN服务器 + + diff --git a/src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml.cs new file mode 100644 index 00000000..ed514e09 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/ProxySettingsControl.xaml.cs @@ -0,0 +1,145 @@ +using Windows.Foundation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Extensions; +using BiliLite.Models.Common; +using BiliLite.Services; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class ProxySettingsControl : UserControl + { + public ProxySettingsControl() + { + this.InitializeComponent(); + LoadRoaming(); + } + + private void LoadRoaming() + { + //使用自定义服务器 + RoamingSettingSetDefault.Click += RoamingSettingSetDefault_Click; + RoamingSettingCustomServer.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, ApiHelper.ROMAING_PROXY_URL); + RoamingSettingCustomServer.Loaded += new RoutedEventHandler((sender, e) => + { + RoamingSettingCustomServer.QuerySubmitted += RoamingSettingCustomServer_QuerySubmitted; + }); + + //自定义HK服务器 + RoamingSettingCustomServerHK.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_HK, ""); + RoamingSettingCustomServerHK.Loaded += new RoutedEventHandler((sender, e) => + { + RoamingSettingCustomServerHK.QuerySubmitted += new TypedEventHandler((sender2, args) => + { + var text = sender2.Text; + if (string.IsNullOrEmpty(text)) + { + Notify.ShowMessageToast("已取消自定义香港代理服务器"); + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_HK, ""); + return; + } + if (!text.Contains("http")) + { + text = "https://" + text; + } + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_HK, text); + sender2.Text = text; + Notify.ShowMessageToast("保存成功"); + }); + }); + + //自定义TW服务器 + RoamingSettingCustomServerTW.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_TW, ""); + RoamingSettingCustomServerTW.Loaded += new RoutedEventHandler((sender, e) => + { + RoamingSettingCustomServerTW.QuerySubmitted += new TypedEventHandler((sender2, args) => + { + var text = sender2.Text; + if (string.IsNullOrEmpty(text)) + { + Notify.ShowMessageToast("已取消自定义台湾代理服务器"); + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_TW, ""); + return; + } + if (!text.Contains("http")) + { + text = "https://" + text; + } + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_TW, text); + sender2.Text = text; + Notify.ShowMessageToast("保存成功"); + }); + }); + + //自定义大陆服务器 + RoamingSettingCustomServerCN.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_CN, ""); + RoamingSettingCustomServerCN.Loaded += new RoutedEventHandler((sender, e) => + { + RoamingSettingCustomServerCN.QuerySubmitted += new TypedEventHandler((sender2, args) => + { + var text = sender2.Text; + if (string.IsNullOrEmpty(text)) + { + Notify.ShowMessageToast("已取消自定义大陆代理服务器"); + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_CN, ""); + return; + } + if (!text.Contains("http")) + { + text = "https://" + text; + } + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_CN, text); + sender2.Text = text; + Notify.ShowMessageToast("保存成功"); + }); + }); + + //Akamai + //RoamingSettingAkamaized.IsOn = SettingService.GetValue(SettingConstants.Roaming.AKAMAI_CDN, false); + //RoamingSettingAkamaized.Loaded += new RoutedEventHandler((sender, e) => + //{ + // RoamingSettingAkamaized.Toggled += new RoutedEventHandler((obj, args) => + // { + // SettingService.SetValue(SettingConstants.Roaming.AKAMAI_CDN, RoamingSettingAkamaized.IsOn); + // }); + //}); + //转简体 + RoamingSettingToSimplified.IsOn = SettingService.GetValue(SettingConstants.Roaming.TO_SIMPLIFIED, true); + RoamingSettingToSimplified.Loaded += new RoutedEventHandler((sender, e) => + { + RoamingSettingToSimplified.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.Roaming.TO_SIMPLIFIED, RoamingSettingToSimplified.IsOn); + }); + }); + + } + + private void RoamingSettingSetDefault_Click(object sender, RoutedEventArgs e) + { + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, ApiHelper.ROMAING_PROXY_URL); + RoamingSettingCustomServer.Text = ApiHelper.ROMAING_PROXY_URL; + Notify.ShowMessageToast("保存成功"); + } + + private void RoamingSettingCustomServer_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) + { + var text = sender.Text; + if (text.Length == 0 || !text.Contains(".")) + { + Notify.ShowMessageToast("输入服务器链接有误"); + sender.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, ApiHelper.ROMAING_PROXY_URL); + return; + } + if (!text.Contains("http")) + { + text = "https://" + text; + } + SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, text); + sender.Text = text; + Notify.ShowMessageToast("保存成功"); + } + } +} diff --git a/src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml new file mode 100644 index 00000000..a75137dd --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml @@ -0,0 +1,302 @@ + + + + + + + + + + 跟随系统 + 浅色 + 深色 + + + + + + + + + + + 标签页 + 单窗口 + 多窗口(测试) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 移除 + + + + + + + + + + + + + 点击添加 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 详情 + 评论 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 网格 + 列表 + + + + + + + + + + + 列表 + 瀑布流 + + + + + + + + + + + 关闭页面 + 新标签页打开视频但不进入 + 无操作 + + + + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml.cs new file mode 100644 index 00000000..88cc7dbb --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/UISettingsControl.xaml.cs @@ -0,0 +1,323 @@ +using System.Collections.ObjectModel; +using System.Linq; +using Windows.Foundation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Extensions; +using BiliLite.Models.Common; +using BiliLite.Models.Common.Home; +using BiliLite.Services; +using Microsoft.UI.Xaml.Controls; +using Microsoft.Toolkit.Uwp.UI; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class UISettingsControl : UserControl + { + public UISettingsControl() + { + this.InitializeComponent(); + LoadUI(); + } + private void LoadUI() + { + //主题 + cbTheme.SelectedIndex = SettingService.GetValue(SettingConstants.UI.THEME, 0); + cbTheme.Loaded += new RoutedEventHandler((sender, e) => + { + cbTheme.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.THEME, cbTheme.SelectedIndex); + Frame rootFrame = Window.Current.Content as Frame; + switch (cbTheme.SelectedIndex) + { + case 1: + rootFrame.RequestedTheme = ElementTheme.Light; + break; + case 2: + rootFrame.RequestedTheme = ElementTheme.Dark; + break; + //case 3: + // // TODO: 切换自定义主题 + // rootFrame.Resources = Application.Current.Resources.ThemeDictionaries["Pink"] as ResourceDictionary; + // break; + default: + rootFrame.RequestedTheme = ElementTheme.Default; + break; + } + App.ExtendAcrylicIntoTitleBar(); + }); + }); + + + //显示模式 + cbDisplayMode.SelectedIndex = SettingService.GetValue(SettingConstants.UI.DISPLAY_MODE, 0); + cbDisplayMode.Loaded += new RoutedEventHandler((sender, e) => + { + cbDisplayMode.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.DISPLAY_MODE, cbDisplayMode.SelectedIndex); + if (cbDisplayMode.SelectedIndex == 2) + { + Notify.ShowMessageToast("多窗口模式正在开发测试阶段,可能会有一堆问题"); + } + else + { + Notify.ShowMessageToast("重启生效"); + } + + }); + }); + //加载原图 + swPictureQuality.IsOn = SettingService.GetValue(SettingConstants.UI.ORTGINAL_IMAGE, false); + swPictureQuality.Loaded += new RoutedEventHandler((sender, e) => + { + swPictureQuality.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.ORTGINAL_IMAGE, swPictureQuality.IsOn); + SettingService.UI.LoadOriginalImage = null; + }); + }); + //缓存页面 + swHomeCache.IsOn = SettingService.GetValue(SettingConstants.UI.CACHE_HOME, true); + swHomeCache.Loaded += new RoutedEventHandler((sender, e) => + { + swHomeCache.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.CACHE_HOME, swHomeCache.IsOn); + + }); + }); + + //右侧详情宽度 + numRightWidth.Value = SettingService.GetValue(SettingConstants.UI.RIGHT_DETAIL_WIDTH, 320); + numRightWidth.Loaded += new RoutedEventHandler((sender, e) => + { + numRightWidth.ValueChanged += new TypedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.RIGHT_DETAIL_WIDTH, args.NewValue); + }); + }); + + //右侧详情宽度可调整 + swRightWidthChangeable.IsOn = SettingService.GetValue(SettingConstants.UI.RIGHT_WIDTH_CHANGEABLE, false); + swRightWidthChangeable.Loaded += new RoutedEventHandler((sender, e) => + { + swRightWidthChangeable.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.RIGHT_WIDTH_CHANGEABLE, swRightWidthChangeable.IsOn); + }); + }); + + //视频详情页分集列表设计宽度 + NumListEpisodeDesiredWidth.Value = SettingService.GetValue(SettingConstants.UI.VIDEO_DETAIL_LIST_EPISODE_DESIRED_WIDTH, SettingConstants.UI.DEFAULT_VIDEO_DETAIL_LIST_EPISODE_DESIRED_WIDTH); + NumListEpisodeDesiredWidth.Loaded += (sender, e) => + { + NumListEpisodeDesiredWidth.ValueChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.UI.VIDEO_DETAIL_LIST_EPISODE_DESIRED_WIDTH, args.NewValue); + }; + }; + + //动态评论宽度 + NumBoxDynamicCommentWidth.Value = SettingService.GetValue(SettingConstants.UI.DYNAMIC_COMMENT_WIDTH, SettingConstants.UI.DEFAULT_DYNAMIC_COMMENT_WIDTH); + NumBoxDynamicCommentWidth.Loaded += (sender, e) => + { + NumBoxDynamicCommentWidth.ValueChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.UI.DYNAMIC_COMMENT_WIDTH, args.NewValue); + }; + }; + + //图片圆角半径 + numImageCornerRadius.Value = SettingService.GetValue(SettingConstants.UI.IMAGE_CORNER_RADIUS, 0); + ImageCornerRadiusExample.CornerRadius = new CornerRadius(numImageCornerRadius.Value); + numImageCornerRadius.Loaded += new RoutedEventHandler((sender, e) => + { + numImageCornerRadius.ValueChanged += new TypedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.IMAGE_CORNER_RADIUS, args.NewValue); + ImageCornerRadiusExample.CornerRadius = new CornerRadius(args.NewValue); + App.Current.Resources["ImageCornerRadius"] = new CornerRadius(args.NewValue); + }); + }); + + //显示视频封面 + swVideoDetailShowCover.IsOn = SettingService.GetValue(SettingConstants.UI.SHOW_DETAIL_COVER, true); + swVideoDetailShowCover.Loaded += new RoutedEventHandler((sender, e) => + { + swVideoDetailShowCover.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.SHOW_DETAIL_COVER, swVideoDetailShowCover.IsOn); + }); + }); + + //新窗口浏览图片 + swPreviewImageNavigateToPage.IsOn = SettingService.GetValue(SettingConstants.UI.NEW_WINDOW_PREVIEW_IMAGE, false); + swPreviewImageNavigateToPage.Loaded += new RoutedEventHandler((sender, e) => + { + swPreviewImageNavigateToPage.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.NEW_WINDOW_PREVIEW_IMAGE, swPreviewImageNavigateToPage.IsOn); + }); + }); + + // 鼠标中键/侧键行为 + cbMouseMiddleAction.SelectedIndex = SettingService.GetValue(SettingConstants.UI.MOUSE_MIDDLE_ACTION, (int)MouseMiddleActions.Back); + cbMouseMiddleAction.Loaded += new RoutedEventHandler((sender, e) => + { + cbMouseMiddleAction.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.MOUSE_MIDDLE_ACTION, cbMouseMiddleAction.SelectedIndex); + }); + }); + + //动态显示 + cbDetailDisplay.SelectedIndex = SettingService.GetValue(SettingConstants.UI.DETAIL_DISPLAY, 0); + cbDetailDisplay.Loaded += new RoutedEventHandler((sender, e) => + { + cbDetailDisplay.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.DETAIL_DISPLAY, cbDetailDisplay.SelectedIndex); + }); + }); + + // 启用长评论收起 + swEnableCommentShrink.IsOn = SettingService.GetValue(SettingConstants.UI.ENABLE_COMMENT_SHRINK, true); + swEnableCommentShrink.Loaded += (sender, e) => + { + swEnableCommentShrink.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.UI.ENABLE_COMMENT_SHRINK, swEnableCommentShrink.IsOn); + }; + }; + + // 评论收起长度 + numCommentShrinkLength.Value = SettingService.GetValue(SettingConstants.UI.COMMENT_SHRINK_LENGTH, SettingConstants.UI.COMMENT_SHRINK_DEFAULT_LENGTH); + numCommentShrinkLength.Loaded += (sender, e) => + { + numCommentShrinkLength.ValueChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.UI.COMMENT_SHRINK_LENGTH, (int)numCommentShrinkLength.Value); + }; + }; + + // 展示评论热门回复 + swShowHotReplies.IsOn = SettingService.GetValue(SettingConstants.UI.SHOW_HOT_REPLIES, SettingConstants.UI.DEFAULT_SHOW_HOT_REPLIES); + swShowHotReplies.Loaded += (sender, e) => + { + swShowHotReplies.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.UI.SHOW_HOT_REPLIES, swShowHotReplies.IsOn); + }; + }; + + //动态显示 + cbDynamicDisplayMode.SelectedIndex = SettingService.GetValue(SettingConstants.UI.DYNAMIC_DISPLAY_MODE, 0); + cbDynamicDisplayMode.Loaded += new RoutedEventHandler((sender, e) => + { + cbDynamicDisplayMode.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.DYNAMIC_DISPLAY_MODE, cbDynamicDisplayMode.SelectedIndex); + }); + }); + + //推荐显示 + cbRecommendDisplayMode.SelectedIndex = SettingService.GetValue(SettingConstants.UI.RECMEND_DISPLAY_MODE, 0); + cbRecommendDisplayMode.Loaded += new RoutedEventHandler((sender, e) => + { + cbRecommendDisplayMode.SelectionChanged += new SelectionChangedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.RECMEND_DISPLAY_MODE, cbRecommendDisplayMode.SelectedIndex); + }); + }); + + //浏览器打开无法处理的链接 + swOpenUrlWithBrowser.IsOn = SettingService.GetValue(SettingConstants.UI.OPEN_URL_BROWSER, false); + swOpenUrlWithBrowser.Loaded += new RoutedEventHandler((sender, e) => + { + swOpenUrlWithBrowser.Toggled += new RoutedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.UI.OPEN_URL_BROWSER, swOpenUrlWithBrowser.IsOn); + }); + }); + + //显示视频底部进度条 + SwShowVideoBottomProgress.IsOn = SettingService.GetValue(SettingConstants.UI.SHOW_VIDEO_BOTTOM_VIRTUAL_PROGRESS_BAR, SettingConstants.UI.DEFAULT_SHOW_VIDEO_BOTTOM_VIRTUAL_PROGRESS_BAR); + SwShowVideoBottomProgress.Loaded += (sender, e) => + { + SwShowVideoBottomProgress.Toggled += (obj, args) => + { + SettingService.SetValue(SettingConstants.UI.SHOW_VIDEO_BOTTOM_VIRTUAL_PROGRESS_BAR, SwShowVideoBottomProgress.IsOn); + }; + }; + + var navItems = SettingService.GetValue(SettingConstants.UI.HOEM_ORDER, DefaultHomeNavItems.GetDefaultHomeNavItems()); + gridHomeCustom.ItemsSource = new ObservableCollection(navItems); + ExceptHomeNavItems(); + } + + private void ExceptHomeNavItems() + { + var defaultNavItems = DefaultHomeNavItems.GetDefaultHomeNavItems(); + var hideNavItems = DefaultHomeNavItems.GetDefaultHideHomeNavItems(); + var customNavItem = gridHomeCustom.ItemsSource as ObservableCollection; + + var customDontHideNavItems = hideNavItems.Where(hideNavItem => + customNavItem.Any(x => x.Title == hideNavItem.Title)).ToList(); + + foreach (var customDontHideNavItem in customDontHideNavItems) + { + hideNavItems.Remove(customDontHideNavItem); + } + + foreach (var navItem in defaultNavItems) + { + if (!customNavItem.Any(x => x.Title == navItem.Title)) + { + hideNavItems.Add(navItem); + } + } + + gridHomeNavItem.ItemsSource = hideNavItems; + } + private void gridHomeCustom_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args) + { + if (!(gridHomeCustom.ItemsSource is ObservableCollection navItems)) return; + SettingService.SetValue(SettingConstants.UI.HOEM_ORDER, navItems.ToList()); + Notify.ShowMessageToast("更改成功,重启生效"); + } + + private void gridHomeNavItem_ItemClick(object sender, ItemClickEventArgs e) + { + var item = e.ClickedItem as HomeNavItem; + if (!(gridHomeCustom.ItemsSource is ObservableCollection navItems)) return; + navItems.Add(item); + SettingService.SetValue(SettingConstants.UI.HOEM_ORDER, navItems.ToList()); + ExceptHomeNavItems(); + Notify.ShowMessageToast("更改成功,重启生效"); + } + + private async void btnCleanImageCache_Click(object sender, RoutedEventArgs e) + { + await ImageCache.Instance.ClearAsync(); + Notify.ShowMessageToast("已清除图片缓存"); + } + + private void menuRemoveHomeItem_Click(object sender, RoutedEventArgs e) + { + var item = (sender as MenuFlyoutItem).DataContext as HomeNavItem; + if (gridHomeCustom.Items.Count == 1) + { + Notify.ShowMessageToast("至少要留一个页面"); + return; + } + (gridHomeCustom.ItemsSource as ObservableCollection).Remove(item); + SettingService.SetValue(SettingConstants.UI.HOEM_ORDER, gridHomeCustom.ItemsSource as ObservableCollection); + ExceptHomeNavItems(); + Notify.ShowMessageToast("更改成功,重启生效"); + } + } +} diff --git a/src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml b/src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml new file mode 100644 index 00000000..4f4fa078 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 关键词屏蔽 + + + + + + + + + + + + + + + + + + + + + + + + + + + 正则屏蔽 + + + + + + + + + + + + + + + + + + + + + + + + + + 用户屏蔽 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml.cs b/src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml.cs new file mode 100644 index 00000000..0db1f169 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Settings/VideoDanmakuSettingsControl.xaml.cs @@ -0,0 +1,156 @@ +using Windows.Foundation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Extensions; +using BiliLite.Models.Common; +using BiliLite.Services; +using BiliLite.ViewModels.Settings; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.UI.Xaml.Controls; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Settings +{ + public sealed partial class VideoDanmakuSettingsControl : UserControl + { + private readonly VideoDanmakuSettingsControlViewModel m_viewModel; + + public VideoDanmakuSettingsControl() + { + m_viewModel = App.ServiceProvider.GetRequiredService(); + this.InitializeComponent(); + LoadDanmu(); + } + + private void LoadDanmu() + { + // 弹幕引擎 + cbDanmakuEngine.SelectedValue = SettingService.GetValue(SettingConstants.VideoDanmaku.DANMAKU_ENGINE, (int)SettingConstants.VideoDanmaku.DEFAULT_DANMAKU_ENGINE); + cbDanmakuEngine.Loaded += (sender, e) => + { + cbDanmakuEngine.SelectionChanged += (obj, args) => + { + SettingService.SetValue(SettingConstants.VideoDanmaku.DANMAKU_ENGINE, cbDanmakuEngine.SelectedValue); + }; + }; + //弹幕开关 + var state = SettingService.GetValue(SettingConstants.VideoDanmaku.SHOW, Visibility.Visible) == Visibility.Visible; + DanmuSettingState.IsOn = state; + DanmuSettingState.Toggled += new RoutedEventHandler((e, args) => + { + SettingService.SetValue(SettingConstants.VideoDanmaku.SHOW, DanmuSettingState.IsOn ? Visibility.Visible : Visibility.Collapsed); + }); + //弹幕关键词 + DanmuSettingListWords.ItemsSource = m_viewModel.ShieldWords; + + //正则关键词 + DanmuSettingListRegulars.ItemsSource = m_viewModel.ShieldRegulars; + + //用户 + DanmuSettingListUsers.ItemsSource = m_viewModel.ShieldUsers; + + //弹幕顶部距离 + numDanmakuTopMargin.Value = SettingService.GetValue(SettingConstants.VideoDanmaku.TOP_MARGIN, 0); + numDanmakuTopMargin.Loaded += new RoutedEventHandler((sender, e) => + { + numDanmakuTopMargin.ValueChanged += new TypedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.VideoDanmaku.TOP_MARGIN, args.NewValue); + }); + }); + //弹幕最大数量 + numDanmakuMaxNum.Value = SettingService.GetValue(SettingConstants.VideoDanmaku.MAX_NUM, 0); + numDanmakuMaxNum.Loaded += new RoutedEventHandler((sender, e) => + { + numDanmakuMaxNum.ValueChanged += new TypedEventHandler((obj, args) => + { + SettingService.SetValue(SettingConstants.VideoDanmaku.MAX_NUM, args.NewValue); + }); + }); + } + + private async void DanmuSettingAddWord_Click(object sender, RoutedEventArgs e) + { + if (string.IsNullOrEmpty(DanmuSettingTxtWord.Text)) + { + Notify.ShowMessageToast("关键词不能为空"); + return; + } + m_viewModel.ShieldWords.Add(DanmuSettingTxtWord.Text); + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, m_viewModel.ShieldWords); + var result = await m_viewModel.AddDanmuFilterItem(DanmuSettingTxtWord.Text, 0); + DanmuSettingTxtWord.Text = ""; + if (!result) + { + Notify.ShowMessageToast("已经添加到本地,但远程同步失败"); + } + } + + private async void DanmuSettingFilterImport_OnClick(object sender, RoutedEventArgs e) + { + await m_viewModel.ImportDanmuFilter(); + } + + private async void DanmuSettingSyncWords_Click(object sender, RoutedEventArgs e) + { + await m_viewModel.SyncDanmuFilter(); + } + + private void RemoveDanmuWord_Click(object sender, RoutedEventArgs e) + { + var word = (sender as AppBarButton).DataContext as string; + m_viewModel.ShieldWords.Remove(word); + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, m_viewModel.ShieldWords); + } + + private void RemoveDanmuRegular_Click(object sender, RoutedEventArgs e) + { + var word = (sender as AppBarButton).DataContext as string; + m_viewModel.ShieldRegulars.Remove(word); + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_REGULAR, m_viewModel.ShieldRegulars); + } + + private void RemoveDanmuUser_Click(object sender, RoutedEventArgs e) + { + var word = (sender as AppBarButton).DataContext as string; + m_viewModel.ShieldUsers.Remove(word); + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_USER, m_viewModel.ShieldUsers); + } + + private async void DanmuSettingAddRegex_Click(object sender, RoutedEventArgs e) + { + if (string.IsNullOrEmpty(DanmuSettingTxtRegex.Text)) + { + Notify.ShowMessageToast("正则表达式不能为空"); + return; + } + var txt = DanmuSettingTxtRegex.Text.Trim('/'); + m_viewModel.ShieldRegulars.Add(txt); + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_REGULAR, m_viewModel.ShieldRegulars); + var result = await m_viewModel.AddDanmuFilterItem(txt, 1); + DanmuSettingTxtRegex.Text = ""; + if (!result) + { + Notify.ShowMessageToast("已经添加到本地,但远程同步失败"); + } + } + + private async void DanmuSettingAddUser_Click(object sender, RoutedEventArgs e) + { + if (string.IsNullOrEmpty(DanmuSettingTxtUser.Text)) + { + Notify.ShowMessageToast("用户ID不能为空"); + return; + } + m_viewModel.ShieldUsers.Add(DanmuSettingTxtUser.Text); + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, m_viewModel.ShieldUsers); + var result = await m_viewModel.AddDanmuFilterItem(DanmuSettingTxtUser.Text, 2); + DanmuSettingTxtUser.Text = ""; + if (!result) + { + Notify.ShowMessageToast("已经添加到本地,但远程同步失败"); + } + } + } +} diff --git a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs index f7110d20..914f7d03 100644 --- a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs +++ b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs @@ -46,6 +46,9 @@ public static IServiceCollection AddViewModels(this IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); return services; } } diff --git a/src/BiliLite.UWP/Models/Common/Danmaku/DanmuFilterItem.cs b/src/BiliLite.UWP/Models/Common/Danmaku/DanmuFilterItem.cs new file mode 100644 index 00000000..21baedd7 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Danmaku/DanmuFilterItem.cs @@ -0,0 +1,19 @@ +namespace BiliLite.Models.Common.Danmaku +{ + public class DanmuFilterItem + { + public int Id { get; set; } + + public long Mid { get; set; } + + public int Type { get; set; } + + public string Filter { get; set; } + + public string Comment { get; set; } + + public long Ctime { get; set; } + + public long Mtime { get; set; } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Modules/SettingVM.cs b/src/BiliLite.UWP/Modules/SettingVM.cs deleted file mode 100644 index 3f9caf5e..00000000 --- a/src/BiliLite.UWP/Modules/SettingVM.cs +++ /dev/null @@ -1,330 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading.Tasks; -using Newtonsoft.Json; -using System.Diagnostics; -using System.Net.Http; -using System.Text; -using Windows.Storage.Pickers; -using BiliLite.Extensions; -using BiliLite.Models.Requests.Api; -using BiliLite.Models.Common; -using BiliLite.Services; -using Microsoft.Toolkit.Uwp.Helpers; - -namespace BiliLite.Modules -{ - public class SettingVM : IModules - { - private static readonly ILogger logger = GlobalLogger.FromCurrentType(); - - PlayerAPI playerAPI; - public SettingVM() - { - playerAPI = new PlayerAPI(); - ThemeColors = new List() - { - new AppThemeColor() - { - use_system_color=true, - name="跟随系统" - }, - new AppThemeColor() - { - color="#FFDF85A0", - name="少女粉", - theme="Pink", - }, - new AppThemeColor() - { - color="#FFF70D0D", - name="姨妈红", - theme="Red", - }, - new AppThemeColor() - { - color="#FFF9EF23", - name="咸蛋黄", - theme="Yellow", - }, - new AppThemeColor() - { - color="#FF71F923", - name="早苗绿", - theme="Green", - }, - new AppThemeColor() - { - color="#FF18BDFB", - name="胖次蓝", - theme="Blue", - }, - new AppThemeColor() - { - color="#FFB92CBF", - name="基佬紫", - theme="Purple", - } - }; - CDNServers = new List() - { - new CDNServerItem("upos-sz-mirrorhwo1.bilivideo.com","华为云"), - new CDNServerItem("upos-sz-mirrorcos.bilivideo.com","腾讯云"), - new CDNServerItem("upos-sz-mirrorali.bilivideo.com","阿里云"), - new CDNServerItem("upos-sz-mirrorhw.bilivideo.com","华为云"), - new CDNServerItem("upos-sz-mirrorks3.bilivideo.com","金山云"), - new CDNServerItem("upos-tf-all-js.bilivideo.com","JS"), - new CDNServerItem("cn-hk-eq-bcache-01.bilivideo.com","香港"), - new CDNServerItem("cn-hk-eq-bcache-16.bilivideo.com","香港"), - new CDNServerItem("upos-hz-mirrorakam.akamaized.net","Akamaized"), - }; - LoadShieldSetting(); - } - - /// - /// 弹幕屏蔽关键词列表 - /// - public ObservableCollection ShieldWords { get; set; } - public ObservableCollection LiveShieldWords { get; set; } - public ObservableCollection ShieldUsers { get; set; } - public ObservableCollection ShieldRegulars { get; set; } - public List CDNServers { get; set; } - public List ThemeColors { get; set; } - - public void LoadShieldSetting() - { - LiveShieldWords = SettingService.GetValue>(SettingConstants.Live.SHIELD_WORD, new ObservableCollection() { }); - ShieldWords = SettingService.GetValue>(SettingConstants.VideoDanmaku.SHIELD_WORD, new ObservableCollection() { }); - - //正则关键词 - ShieldRegulars = SettingService.GetValue>(SettingConstants.VideoDanmaku.SHIELD_REGULAR, new ObservableCollection() { }); - - //用户 - ShieldUsers = SettingService.GetValue>(SettingConstants.VideoDanmaku.SHIELD_USER, new ObservableCollection() { }); - } - - public async Task ImportDanmuFilter() - { - var filePicker = new FileOpenPicker(); - filePicker.FileTypeFilter.Add(".json"); - var file = await filePicker.PickSingleFileAsync(); - if (file == null) return; - using var stream = await file.OpenReadAsync(); - var text = await stream.ReadTextAsync(Encoding.UTF8); - var filterList = JsonConvert.DeserializeObject>(text); - - ImportDanmakuFilterCore(filterList); - } - - public async Task SyncDanmuFilter() - { - try - { - var result = await playerAPI.GetDanmuFilterWords().Request(); - if (!result.status) - { - Notify.ShowMessageToast(result.message); - return; - } - var obj = result.GetJObject(); - if (obj["code"].ToInt32() == 0) - { - var items = JsonConvert.DeserializeObject>(obj["data"]["rule"].ToString()); - - ImportDanmakuFilterCore(items); - } - else - { - Notify.ShowMessageToast(obj["message"].ToString()); - } - } - catch (Exception ex) - { - logger.Log("读取弹幕屏蔽词失败", LogType.Error, ex); - } - } - - public async Task AddDanmuFilterItem(string word, int type) - { - try - { - var result = await playerAPI.AddDanmuFilterWord(word: word, type: type).Request(); - if (!result.status) - { - return false; - } - var obj = result.GetJObject(); - return obj["code"].ToInt32() == 0; - } - catch (Exception ex) - { - logger.Log("添加弹幕屏蔽词失败", LogType.Error, ex); - return false; - } - } - /// - /// CDN延迟测试 - /// - public async void CDNServerDelayTest() - { - foreach (var item in CDNServers) - { - var time = await GetDelay(item.Server); - item.Delay = time; - } - } - private HttpClient _httpClient = new HttpClient() - { - Timeout = TimeSpan.FromSeconds(2) - }; - private async Task GetDelay(string server) - { - //随便整个链接 - var testUrl = $"https://{server}/upgcxcode/76/62/729206276/729206276_nb2-1-30112.m4s"; - - try - { - Stopwatch sw = Stopwatch.StartNew(); - var res = await _httpClient.GetAsync(new Uri(testUrl)); - sw.Stop(); - return sw.ElapsedMilliseconds; - } - catch (Exception) - { - return -1; - } - - } - - private void ImportDanmakuFilterCore(List filterList) - { - { - var words = filterList.Where(x => x.type == 0).Select(x => x.filter).ToList(); - var ls = ShieldWords.Union(words); - ShieldWords.Clear(); - foreach (var item in ls) - { - ShieldWords.Add(item); - } - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, ShieldWords); - } - { - var users = filterList.Where(x => x.type == 1).Select(x => x.filter).ToList(); - var ls = ShieldRegulars.Union(users); - ShieldRegulars.Clear(); - foreach (var item in ls) - { - if (!item.IsValidRegex()) - { - logger.Warn("非法正则表达式: " + item); - continue; - } - ShieldRegulars.Add(item); - } - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_REGULAR, ShieldRegulars); - } - { - var users = filterList.Where(x => x.type == 2).Select(x => x.filter).ToList(); - var ls = ShieldUsers.Union(users); - ShieldUsers.Clear(); - foreach (var item in ls) - { - ShieldUsers.Add(item); - } - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_USER, ShieldUsers); - } - } - - //傻逼微软,UWP连个Ping都不支持 - //private async Task GetPing(string address) - //{ - // try - // { - // Ping ping = new Ping(); - // PingOptions options = new PingOptions(); - // options.DontFragment = true; - // byte[] buffer = new byte[32]; - // for (int i = 0; i < 32; i++) - // { - // buffer[i] = 0; - // } - // int timeout = 3000; - // PingReply reply = await ping.SendPingAsync(address, timeout, buffer, options); - // if (reply.Status == IPStatus.Success) - // { - // return reply.RoundtripTime; - // } - // else - // { - // return -1; - // } - // } - // catch (Exception ex) - // { - // Debug.WriteLine(ex); - // return -1; - // } - - - //} - - } - public class DanmuFilterItem - { - public int id { get; set; } - public long mid { get; set; } - public int type { get; set; } - public string filter { get; set; } - public string comment { get; set; } - public long ctime { get; set; } - public long mtime { get; set; } - - } - public class AppThemeColor - { - public bool use_system_color { get; set; } = false; - public string color { get; set; } - public string name { get; set; } - public string theme { get; set; } - } - public class CDNServerItem : IModules - { - public CDNServerItem(string server, string remark) - { - this.Server = server; - this.Remark = remark; - } - public string Server { get; set; } - public string Remark { get; set; } - - public bool ShowDelay - { - get - { - return Delay > 0; - } - } - public bool ShowTimeOut - { - get - { - return Delay < 0; - } - } - private long _Delay = 0; - public long Delay - { - get { return _Delay; } - set - { - _Delay = value; - DoPropertyChanged("Delay"); - DoPropertyChanged("ShowDelay"); - DoPropertyChanged("ShowTimeOut"); - } - } - - } -} diff --git a/src/BiliLite.UWP/Modules/User/Account.cs b/src/BiliLite.UWP/Modules/User/Account.cs index 0cdd6f11..3105c3c6 100644 --- a/src/BiliLite.UWP/Modules/User/Account.cs +++ b/src/BiliLite.UWP/Modules/User/Account.cs @@ -27,14 +27,12 @@ public class Account private static readonly ILogger _logger = GlobalLogger.FromCurrentType(); private readonly CookieService m_cookieService; - private SettingVM settingVM; public AccountApi accountApi; string guid = ""; public Account() { m_cookieService = App.ServiceProvider.GetRequiredService(); accountApi = new AccountApi(); - settingVM = new SettingVM(); guid = Guid.NewGuid().ToString(); } public async Task EncryptedPassword(string passWord) diff --git a/src/BiliLite.UWP/Pages/LiveDetailPage.xaml b/src/BiliLite.UWP/Pages/LiveDetailPage.xaml index 1f1977c5..a363db1a 100644 --- a/src/BiliLite.UWP/Pages/LiveDetailPage.xaml +++ b/src/BiliLite.UWP/Pages/LiveDetailPage.xaml @@ -522,7 +522,7 @@ - + diff --git a/src/BiliLite.UWP/Pages/LiveDetailPage.xaml.cs b/src/BiliLite.UWP/Pages/LiveDetailPage.xaml.cs index 022b0cb0..b73c616d 100644 --- a/src/BiliLite.UWP/Pages/LiveDetailPage.xaml.cs +++ b/src/BiliLite.UWP/Pages/LiveDetailPage.xaml.cs @@ -35,6 +35,7 @@ using Windows.UI.Xaml.Documents; using System.Text.RegularExpressions; using BiliLite.Services.Interfaces; +using BiliLite.ViewModels.Settings; using Microsoft.Extensions.DependencyInjection; // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板 @@ -55,10 +56,10 @@ public sealed partial class LiveDetailPage : BasePage private readonly LiveDetailPageViewModel m_viewModel; private readonly bool m_useNsDanmaku = true; private readonly IDanmakuController m_danmakuController; + private readonly LiveSettingsControlViewModel m_liveSettingsControlViewModel; DisplayRequest dispRequest; LiveRoomViewModel m_liveRoomViewModel; - SettingVM settingVM; DispatcherTimer timer_focus; DispatcherTimer controlTimer; DispatcherTimer chatScrollTimer; @@ -97,7 +98,7 @@ public LiveDetailPage() chatScrollTimer.Tick += ChatScrollTimer_Tick; chatScrollTimer.Start(); - settingVM = new SettingVM(); + m_liveSettingsControlViewModel = App.ServiceProvider.GetRequiredService(); m_liveRoomViewModel = new LiveRoomViewModel(); m_liveRoomViewModel.ChangedPlayUrl += LiveRoomViewModelChangedPlayUrl; @@ -225,9 +226,9 @@ private void LiveRoomViewModelAddNewDanmu(object sender, DanmuMsgModel e) { if (m_danmakuController.DanmakuViewModel.IsHide) return; - if (settingVM.LiveShieldWords != null && settingVM.LiveShieldWords.Count > 0) + if (m_liveSettingsControlViewModel.LiveShieldWords != null && m_liveSettingsControlViewModel.LiveShieldWords.Count > 0) { - if (settingVM.LiveShieldWords.FirstOrDefault(x => e.Text.Contains(x)) != null) return; + if (m_liveSettingsControlViewModel.LiveShieldWords.FirstOrDefault(x => e.Text.Contains(x)) != null) return; } try { @@ -1158,17 +1159,17 @@ private void btnAddShieldWord_Click(object sender, RoutedEventArgs e) private void AddShieldWord(string word) { - if (!settingVM.LiveShieldWords.Contains(word)) + if (!m_liveSettingsControlViewModel.LiveShieldWords.Contains(word)) { - settingVM.LiveShieldWords.Add(word); - SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, settingVM.LiveShieldWords); + m_liveSettingsControlViewModel.LiveShieldWords.Add(word); + SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, m_liveSettingsControlViewModel.LiveShieldWords); } } private void DelShieldWord(string word) { - settingVM.LiveShieldWords.Remove(word); - SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, settingVM.LiveShieldWords); + m_liveSettingsControlViewModel.LiveShieldWords.Remove(word); + SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, m_liveSettingsControlViewModel.LiveShieldWords); } #region 播放器手势 diff --git a/src/BiliLite.UWP/Pages/SettingPage.xaml b/src/BiliLite.UWP/Pages/SettingPage.xaml index 8120d214..b694c6a4 100644 --- a/src/BiliLite.UWP/Pages/SettingPage.xaml +++ b/src/BiliLite.UWP/Pages/SettingPage.xaml @@ -11,15 +11,12 @@ xmlns:covert="using:BiliLite.Converters" xmlns:controls="using:Microsoft.UI.Xaml.Controls" xmlns:controls1="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:common="using:BiliLite.Models.Common" xmlns:home="using:BiliLite.Models.Common.Home" - xmlns:controls2="using:BiliLite.Controls" + xmlns:settings="using:BiliLite.Controls.Settings" Background="Transparent"> - - + @@ -30,221 +27,8 @@ - - 主题 - - - 跟随系统 - 浅色 - 深色 - - - - - 颜色 - - - - - - - - - - - - - - - - - - - - - 显示模式(重启生效) - - - 标签页 - 单窗口 - 多窗口(测试) - - - - - 语言 - - - 跟随系统 - 简体中文 - 繁體中文 - English - - - - - 加载原图 - - - - - 缓存首页 - - - - 首页自定义(重启生效) - 拖动排序,右键或长按移除选项 - - - - - - - - - - 移除 - - - - - - - - - - - - - 点击添加 - - - - - - - - - - - - - - - - - - 右侧视频详情 - 右侧视频详情宽度(下次打开视频生效) - - - - 视频详情页分集列表设计宽度(下次打开视频生效) - - - - - 动态 - 动态评论宽度(下次打开应用生效) - - - - 图片圆角半径(重启生效) - - - - - - 视频详情显示封面 - - - - 详情页右侧默认选项卡 - - - 详情 - 评论 - - - - - - 启用长评论折叠 - - - - - 评论折叠长度 - - - - - 展示评论热门回复 - - - - - 新窗口打开图片预览 - - - - 推荐页显示方式(重启应用生效) - - - 网格 - 列表 - - - - - 关注动态显示方式(重启应用生效) - - - 列表 - 瀑布流 - - - - - 鼠标中键/侧键行为 - - - 关闭页面 - 新标签页打开视频但不进入 - 无操作 - - - - - 使用浏览器打开无法处理的链接 - - - - 隐藏首页右上角广告按钮 - - - - - 是否在视频底部显示进度条 - - - + - @@ -254,140 +38,7 @@ - 优先视频编码 - - - - 视频编码为HEVC时系统需要 - 安装HEVC扩展 - - - - - 视频编码为AV1时系统需要 - 安装AV1扩展 - ,部分清晰度可能也需要HEVC扩展 - - - 优先使用FFmpeg播放器 - - - 使用FFmpeg播放时硬解视频 - - 视频默认倍速 - - - - - - - - - - - 视频自动播放 - - 播放完成自动切换下一P - - - 自动跳转至上次观看进度 - - 进入播放自动全屏 - - 进入播放自动铺满窗口 - - 双击播放器全屏(默认双击暂停) - - - 播放器方向键右键行为 - - - - - - - - 播放器按住手势行为 - - - - - - - 播放器按住手势可被其他手势取消 - - 倍速播放速度 - - - - - - - - 音量 - - - 亮度 - - - 锁定播放器音量设置(播放器内修改音量时不写设置) - - - 锁定播放器亮度设置(播放器内修改亮度时不写设置) - - - 播放速度菜单 - - - 自动打开AI字幕 - - 部分自动生成的AI字幕会与视频自带字幕冲突 - 建议关闭,有需要时再手动打开字幕 - - 上报历史纪录 - - - 视频结束上报历史纪录位置0 - - - 替换CDN链接 - - - - - - - - - - 替换CDN链接可以有效的提升视频加载速度 - 开启替换后读取播放地址可能需要更长时间 - - - 替换CDN服务器选择 - - - - - - - - 【】 - - - - 超时 - ms - - - - + @@ -397,39 +48,7 @@ - 首选代理服务器 - - - - - - - 默认服务器不稳定,建议自定义服务器 - 查看公共服务器 - - - 部分解析服务器需要登录后才能使用,请选择自己信任的服务器 - - 自定义香港代理服务器 - - - - 自定义台湾代理服务器 - - - - 自定义大陆代理服务器 - - - - 繁体字幕转简体 - - - - 如播放港澳台视频卡顿,建议到「播放」设置中打开替换CDN选项,并且选择延迟较低的CDN服务器 - + @@ -439,86 +58,7 @@ - 弹幕引擎 - - - - - - - - - - - - 默认弹幕状态 - - 弹幕顶部距离 - - 弹幕每秒最大数量(0为不限制) - - - - 关键词屏蔽 - - - - - - - - - - - - - - - - - - - - - 正则屏蔽 - - - - - - - - - - - - - - - - - - - 用户屏蔽 - - - - - - - - - - - - - - - - - - - + @@ -528,42 +68,7 @@ - 弹幕引擎 - - - - - - - - - - - - 默认弹幕状态 - - - 关键词屏蔽 - - - - - - - - - - - - - - - - - - - - + @@ -573,45 +78,7 @@ - 下载存放目录 - - - 旧版下载目录 - - - 加载旧版下载的视频 - - - 优先下载视频类型 - - - 同时下载多个任务 - - 允许使用流量下载 - - 下载完成发送通知 - + @@ -620,7 +87,7 @@ 过滤 - + @@ -629,49 +96,7 @@ - 自动清理日志文件 - - 自动清理几天前的日志 - - 保护日志中敏感信息 - - 日志级别 - - - Trace - Debug - Info - Warn - Error - Fatal - - - 优先使用Grpc请求动态 - - 发起请求时使用的build值 - - - - - - BiliLite-WebApi(用于处理UWP无法完成的事项) - - - - - - - - - 更新json请求地址(用于解决github在国内访问不佳的问题) - - - - - 第三方公益镜像捐赠地址-赠人玫瑰, 手有余香. + @@ -689,25 +114,7 @@ - 哔哩哔哩 Lite - 版本 1.0.0 - - - 开发 - 开发者 : xiaoyaocz - 维护者 : ywmoyue - Logo绘制 : xiaoyaomengo - 反馈 - Github Discussions : https://github.com/ywmoyue/biliuwp-lite/discussions - 邮箱(请在发邮件时附带Github Discussion贴子链接) : ruamuyan@outlook.com - 说明 - 这是一个第三方客户端,应用所有数据来源均来自哔哩哔哩。 - 本程序仅供学习交流编程技术使用。 - 如果侵犯您的合法权益,请及时联系本人以第一时间删除。 - 参考及引用 - 哔哩哔哩官网 - 隐私策略 - 开源代码许可/项目引用 + diff --git a/src/BiliLite.UWP/Pages/SettingPage.xaml.cs b/src/BiliLite.UWP/Pages/SettingPage.xaml.cs index a46bb7ce..083566d1 100644 --- a/src/BiliLite.UWP/Pages/SettingPage.xaml.cs +++ b/src/BiliLite.UWP/Pages/SettingPage.xaml.cs @@ -1,27 +1,6 @@ -using BiliLite.Extensions; -using BiliLite.Models.Common; -using BiliLite.Modules; -using BiliLite.Services; -using Microsoft.Toolkit.Uwp.Helpers; -using Microsoft.Toolkit.Uwp.UI; -using Microsoft.UI.Xaml.Controls; -using System; -using System.Collections.ObjectModel; -using System.Linq; -using Windows.Foundation; +using System; using Windows.Storage; -using Windows.Storage.Pickers; -using Windows.UI; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -using BiliLite.Models.Common.Home; -using BiliLite.ViewModels.Download; -using Microsoft.Extensions.DependencyInjection; -using System.Threading.Tasks; -using Windows.ApplicationModel.Core; -using BiliLite.Dialogs; // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板 @@ -32,975 +11,17 @@ namespace BiliLite.Pages /// public sealed partial class SettingPage : BasePage { - SettingVM settingVM; - private readonly DownloadPageViewModel m_downloadPageViewModel; - public SettingPage() { this.InitializeComponent(); Title = "设置"; - settingVM = new SettingVM(); - m_downloadPageViewModel = App.ServiceProvider.GetRequiredService(); - LoadUI(); - LoadPlayer(); - LoadRoaming(); - LoadDanmu(); - LoadLiveDanmu(); - LoadDownlaod(); - LoadOther(); - } - private void LoadUI() - { - //主题 - cbTheme.SelectedIndex = SettingService.GetValue(SettingConstants.UI.THEME, 0); - cbTheme.Loaded += new RoutedEventHandler((sender, e) => - { - cbTheme.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.THEME, cbTheme.SelectedIndex); - Frame rootFrame = Window.Current.Content as Frame; - switch (cbTheme.SelectedIndex) - { - case 1: - rootFrame.RequestedTheme = ElementTheme.Light; - break; - case 2: - rootFrame.RequestedTheme = ElementTheme.Dark; - break; - //case 3: - // // TODO: 切换自定义主题 - // rootFrame.Resources = Application.Current.Resources.ThemeDictionaries["Pink"] as ResourceDictionary; - // break; - default: - rootFrame.RequestedTheme = ElementTheme.Default; - break; - } - App.ExtendAcrylicIntoTitleBar(); - }); - }); - - cbColor.SelectedIndex = SettingService.GetValue(SettingConstants.UI.THEME_COLOR, 0); - cbColor.Loaded += new RoutedEventHandler((sender, e) => - { - cbColor.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.THEME_COLOR, cbColor.SelectedIndex); - Color color = new Color(); - if (cbColor.SelectedIndex == 0) - { - var uiSettings = new Windows.UI.ViewManagement.UISettings(); - color = uiSettings.GetColorValue(Windows.UI.ViewManagement.UIColorType.Accent); - } - else - { - color = (cbColor.SelectedItem as AppThemeColor).color.StrToColor(); - } - (Application.Current.Resources["SystemControlHighlightAltAccentBrush"] as SolidColorBrush).Color = color; - (Application.Current.Resources["SystemControlHighlightAccentBrush"] as SolidColorBrush).Color = color; - //(App.Current.Resources.ThemeDictionaries["Light"] as ResourceDictionary)["SystemAccentColor"] = Utils.ToColor(item.color); - - }); - }); - - - //显示模式 - cbDisplayMode.SelectedIndex = SettingService.GetValue(SettingConstants.UI.DISPLAY_MODE, 0); - cbDisplayMode.Loaded += new RoutedEventHandler((sender, e) => - { - cbDisplayMode.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.DISPLAY_MODE, cbDisplayMode.SelectedIndex); - if (cbDisplayMode.SelectedIndex == 2) - { - Notify.ShowMessageToast("多窗口模式正在开发测试阶段,可能会有一堆问题"); - } - else - { - Notify.ShowMessageToast("重启生效"); - } - - }); - }); - //加载原图 - swPictureQuality.IsOn = SettingService.GetValue(SettingConstants.UI.ORTGINAL_IMAGE, false); - swPictureQuality.Loaded += new RoutedEventHandler((sender, e) => - { - swPictureQuality.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.ORTGINAL_IMAGE, swPictureQuality.IsOn); - SettingService.UI.LoadOriginalImage = null; - }); - }); - //缓存页面 - swHomeCache.IsOn = SettingService.GetValue(SettingConstants.UI.CACHE_HOME, true); - swHomeCache.Loaded += new RoutedEventHandler((sender, e) => - { - swHomeCache.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.CACHE_HOME, swHomeCache.IsOn); - - }); - }); - - //右侧详情宽度 - numRightWidth.Value = SettingService.GetValue(SettingConstants.UI.RIGHT_DETAIL_WIDTH, 320); - numRightWidth.Loaded += new RoutedEventHandler((sender, e) => - { - numRightWidth.ValueChanged += new TypedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.RIGHT_DETAIL_WIDTH, args.NewValue); - }); - }); - - //右侧详情宽度可调整 - swRightWidthChangeable.IsOn = SettingService.GetValue(SettingConstants.UI.RIGHT_WIDTH_CHANGEABLE, false); - swRightWidthChangeable.Loaded += new RoutedEventHandler((sender, e) => - { - swRightWidthChangeable.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.RIGHT_WIDTH_CHANGEABLE, swRightWidthChangeable.IsOn); - }); - }); - - //视频详情页分集列表设计宽度 - NumListEpisodeDesiredWidth.Value = SettingService.GetValue(SettingConstants.UI.VIDEO_DETAIL_LIST_EPISODE_DESIRED_WIDTH, SettingConstants.UI.DEFAULT_VIDEO_DETAIL_LIST_EPISODE_DESIRED_WIDTH); - NumListEpisodeDesiredWidth.Loaded += (sender, e) => - { - NumListEpisodeDesiredWidth.ValueChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.UI.VIDEO_DETAIL_LIST_EPISODE_DESIRED_WIDTH, args.NewValue); - }; - }; - - //动态评论宽度 - NumBoxDynamicCommentWidth.Value = SettingService.GetValue(SettingConstants.UI.DYNAMIC_COMMENT_WIDTH, SettingConstants.UI.DEFAULT_DYNAMIC_COMMENT_WIDTH); - NumBoxDynamicCommentWidth.Loaded += (sender, e) => - { - NumBoxDynamicCommentWidth.ValueChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.UI.DYNAMIC_COMMENT_WIDTH, args.NewValue); - }; - }; - - //图片圆角半径 - numImageCornerRadius.Value = SettingService.GetValue(SettingConstants.UI.IMAGE_CORNER_RADIUS, 0); - ImageCornerRadiusExample.CornerRadius = new CornerRadius(numImageCornerRadius.Value); - numImageCornerRadius.Loaded += new RoutedEventHandler((sender, e) => - { - numImageCornerRadius.ValueChanged += new TypedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.IMAGE_CORNER_RADIUS, args.NewValue); - ImageCornerRadiusExample.CornerRadius = new CornerRadius(args.NewValue); - App.Current.Resources["ImageCornerRadius"] = new CornerRadius(args.NewValue); - }); - }); - - //显示视频封面 - swVideoDetailShowCover.IsOn = SettingService.GetValue(SettingConstants.UI.SHOW_DETAIL_COVER, true); - swVideoDetailShowCover.Loaded += new RoutedEventHandler((sender, e) => - { - swVideoDetailShowCover.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.SHOW_DETAIL_COVER, swVideoDetailShowCover.IsOn); - }); - }); - - //新窗口浏览图片 - swPreviewImageNavigateToPage.IsOn = SettingService.GetValue(SettingConstants.UI.NEW_WINDOW_PREVIEW_IMAGE, false); - swPreviewImageNavigateToPage.Loaded += new RoutedEventHandler((sender, e) => - { - swPreviewImageNavigateToPage.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.NEW_WINDOW_PREVIEW_IMAGE, swPreviewImageNavigateToPage.IsOn); - }); - }); - - // 鼠标中键/侧键行为 - cbMouseMiddleAction.SelectedIndex = SettingService.GetValue(SettingConstants.UI.MOUSE_MIDDLE_ACTION, (int)MouseMiddleActions.Back); - cbMouseMiddleAction.Loaded += new RoutedEventHandler((sender, e) => - { - cbMouseMiddleAction.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.MOUSE_MIDDLE_ACTION, cbMouseMiddleAction.SelectedIndex); - }); - }); - - //动态显示 - cbDetailDisplay.SelectedIndex = SettingService.GetValue(SettingConstants.UI.DETAIL_DISPLAY, 0); - cbDetailDisplay.Loaded += new RoutedEventHandler((sender, e) => - { - cbDetailDisplay.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.DETAIL_DISPLAY, cbDetailDisplay.SelectedIndex); - }); - }); - - // 启用长评论收起 - swEnableCommentShrink.IsOn = SettingService.GetValue(SettingConstants.UI.ENABLE_COMMENT_SHRINK, true); - swEnableCommentShrink.Loaded += (sender, e) => - { - swEnableCommentShrink.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.UI.ENABLE_COMMENT_SHRINK, swEnableCommentShrink.IsOn); - }; - }; - - // 评论收起长度 - numCommentShrinkLength.Value = SettingService.GetValue(SettingConstants.UI.COMMENT_SHRINK_LENGTH, SettingConstants.UI.COMMENT_SHRINK_DEFAULT_LENGTH); - numCommentShrinkLength.Loaded += (sender, e) => - { - numCommentShrinkLength.ValueChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.UI.COMMENT_SHRINK_LENGTH, (int)numCommentShrinkLength.Value); - }; - }; - - // 展示评论热门回复 - swShowHotReplies.IsOn = SettingService.GetValue(SettingConstants.UI.SHOW_HOT_REPLIES, SettingConstants.UI.DEFAULT_SHOW_HOT_REPLIES); - swShowHotReplies.Loaded += (sender, e) => - { - swShowHotReplies.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.UI.SHOW_HOT_REPLIES, swShowHotReplies.IsOn); - }; - }; - - //动态显示 - cbDynamicDisplayMode.SelectedIndex = SettingService.GetValue(SettingConstants.UI.DYNAMIC_DISPLAY_MODE, 0); - cbDynamicDisplayMode.Loaded += new RoutedEventHandler((sender, e) => - { - cbDynamicDisplayMode.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.DYNAMIC_DISPLAY_MODE, cbDynamicDisplayMode.SelectedIndex); - }); - }); - - //推荐显示 - cbRecommendDisplayMode.SelectedIndex = SettingService.GetValue(SettingConstants.UI.RECMEND_DISPLAY_MODE, 0); - cbRecommendDisplayMode.Loaded += new RoutedEventHandler((sender, e) => - { - cbRecommendDisplayMode.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.RECMEND_DISPLAY_MODE, cbRecommendDisplayMode.SelectedIndex); - }); - }); - - //隐藏首页右上角广告按钮 - swHideADBtn.IsOn = SettingService.GetValue(SettingConstants.UI.HIDE_AD, false); - swHideADBtn.Loaded += new RoutedEventHandler((sender, e) => - { - swHideADBtn.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.HIDE_AD, swHideADBtn.IsOn); - }); - }); - - //浏览器打开无法处理的链接 - swOpenUrlWithBrowser.IsOn = SettingService.GetValue(SettingConstants.UI.OPEN_URL_BROWSER, false); - swOpenUrlWithBrowser.Loaded += new RoutedEventHandler((sender, e) => - { - swOpenUrlWithBrowser.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.UI.OPEN_URL_BROWSER, swOpenUrlWithBrowser.IsOn); - }); - }); - - //显示视频底部进度条 - SwShowVideoBottomProgress.IsOn = SettingService.GetValue(SettingConstants.UI.SHOW_VIDEO_BOTTOM_VIRTUAL_PROGRESS_BAR, SettingConstants.UI.DEFAULT_SHOW_VIDEO_BOTTOM_VIRTUAL_PROGRESS_BAR); - SwShowVideoBottomProgress.Loaded += (sender, e) => - { - SwShowVideoBottomProgress.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.UI.SHOW_VIDEO_BOTTOM_VIRTUAL_PROGRESS_BAR, SwShowVideoBottomProgress.IsOn); - }; - }; - - var navItems = SettingService.GetValue(SettingConstants.UI.HOEM_ORDER, DefaultHomeNavItems.GetDefaultHomeNavItems()); - gridHomeCustom.ItemsSource = new ObservableCollection(navItems); - ExceptHomeNavItems(); } - private void LoadPlayer() - { - //播放类型 - var selectedValue = (PlayUrlCodecMode)SettingService.GetValue(SettingConstants.Player.DEFAULT_VIDEO_TYPE, (int)DefaultVideoTypeOptions.DEFAULT_VIDEO_TYPE); - cbVideoType.SelectedItem = DefaultVideoTypeOptions.GetOption(selectedValue); - cbVideoType.SelectionChanged += (e, args) => - { - SettingService.SetValue(SettingConstants.Player.DEFAULT_VIDEO_TYPE, (int)cbVideoType.SelectedValue); - }; - //视频倍速 - cbVideoSpeed.SelectedIndex = SettingConstants.Player.VideoSpeed.IndexOf(SettingService.GetValue(SettingConstants.Player.DEFAULT_VIDEO_SPEED, 1.0d)); - cbVideoSpeed.Loaded += new RoutedEventHandler((sender, e) => - { - cbVideoSpeed.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.DEFAULT_VIDEO_SPEED, SettingConstants.Player.VideoSpeed[cbVideoSpeed.SelectedIndex]); - }); - }); - - //硬解视频 - swHardwareDecode.IsOn = SettingService.GetValue(SettingConstants.Player.HARDWARE_DECODING, true); - swHardwareDecode.Loaded += new RoutedEventHandler((sender, e) => - { - swHardwareDecode.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.HARDWARE_DECODING, swHardwareDecode.IsOn); - }); - }); - //自动播放 - swAutoPlay.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_PLAY, false); - swAutoPlay.Loaded += new RoutedEventHandler((sender, e) => - { - swAutoPlay.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.AUTO_PLAY, swAutoPlay.IsOn); - }); - }); - //自动跳转下一P - swAutoNext.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_NEXT, true); - swAutoNext.Loaded += new RoutedEventHandler((sender, e) => - { - swAutoNext.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.AUTO_NEXT, swAutoNext.IsOn); - }); - }); - //使用其他网站 - //swPlayerSettingUseOtherSite.IsOn = SettingService.GetValue(SettingConstants.Player.USE_OTHER_SITEVIDEO, false); - //swPlayerSettingUseOtherSite.Loaded += new RoutedEventHandler((sender, e) => - //{ - // swPlayerSettingUseOtherSite.Toggled += new RoutedEventHandler((obj, args) => - // { - // SettingService.SetValue(SettingConstants.Player.USE_OTHER_SITEVIDEO, swPlayerSettingUseOtherSite.IsOn); - // }); - //}); - - //自动跳转进度 - swPlayerSettingAutoToPosition.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_TO_POSITION, true); - swPlayerSettingAutoToPosition.Loaded += new RoutedEventHandler((sender, e) => - { - swPlayerSettingAutoToPosition.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.AUTO_TO_POSITION, swPlayerSettingAutoToPosition.IsOn); - }); - }); - //自动铺满屏幕 - swPlayerSettingAutoFullWindows.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_FULL_WINDOW, false); - swPlayerSettingAutoFullWindows.Loaded += new RoutedEventHandler((sender, e) => - { - swPlayerSettingAutoFullWindows.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.AUTO_FULL_WINDOW, swPlayerSettingAutoFullWindows.IsOn); - }); - }); - //自动全屏 - swPlayerSettingAutoFullScreen.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_FULL_SCREEN, false); - swPlayerSettingAutoFullScreen.Loaded += new RoutedEventHandler((sender, e) => - { - swPlayerSettingAutoFullScreen.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.AUTO_FULL_SCREEN, swPlayerSettingAutoFullScreen.IsOn); - }); - }); - - - //双击全屏 - swPlayerSettingDoubleClickFullScreen.IsOn = SettingService.GetValue(SettingConstants.Player.DOUBLE_CLICK_FULL_SCREEN, false); - swPlayerSettingDoubleClickFullScreen.Loaded += new RoutedEventHandler((sender, e) => - { - swPlayerSettingDoubleClickFullScreen.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.DOUBLE_CLICK_FULL_SCREEN, swPlayerSettingDoubleClickFullScreen.IsOn); - }); - }); - - // 方向键右键行为 - cbPlayerKeyRightAction.SelectedIndex = SettingService.GetValue(SettingConstants.Player.PLAYER_KEY_RIGHT_ACTION, (int)PlayerKeyRightAction.ControlProgress); - cbPlayerKeyRightAction.Loaded += (sender, e) => - { - cbPlayerKeyRightAction.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.PLAYER_KEY_RIGHT_ACTION, cbPlayerKeyRightAction.SelectedIndex); - }; - }; - - // 按住手势行为 - cbPlayerHoldingGestureAction.SelectedIndex = SettingService.GetValue(SettingConstants.Player.HOLDING_GESTURE_ACTION, (int)PlayerHoldingAction.None); - cbPlayerHoldingGestureAction.Loaded += (sender, e) => - { - cbPlayerHoldingGestureAction.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.HOLDING_GESTURE_ACTION, cbPlayerHoldingGestureAction.SelectedIndex); - }; - }; - - // 按住手势可被其他手势取消 - swPlayerHoldingGestureCanCancel.IsOn = SettingService.GetValue(SettingConstants.Player.HOLDING_GESTURE_CAN_CANCEL, true); - swPlayerHoldingGestureCanCancel.Loaded += (sender, e) => - { - swPlayerHoldingGestureCanCancel.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.HOLDING_GESTURE_CAN_CANCEL, swPlayerHoldingGestureCanCancel.IsOn); - }; - }; - - // 倍速播放速度 - cbRatePlaySpeed.SelectedIndex = SettingConstants.Player.HIGH_RATE_PLAY_SPEED_LIST.IndexOf(SettingService.GetValue(SettingConstants.Player.HIGH_RATE_PLAY_SPEED, 2.0d)); - cbRatePlaySpeed.Loaded += (sender, e) => - { - cbRatePlaySpeed.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.HIGH_RATE_PLAY_SPEED, SettingConstants.Player.HIGH_RATE_PLAY_SPEED_LIST[cbRatePlaySpeed.SelectedIndex]); - }; - }; - - // 音量 - NumBoxVolume.Value = Math.Round((SettingService.GetValue(SettingConstants.Player.PLAYER_VOLUME, - SettingConstants.Player.DEFAULT_PLAYER_VOLUME)) * 100, 2); - NumBoxVolume.Loaded += (sender, e) => - { - NumBoxVolume.ValueChanged += (obj, args) => - { - if (NumBoxVolume.Value > 100) - { - NumBoxVolume.Value = 100; - } - - if (NumBoxVolume.Value < 0) - { - NumBoxVolume.Value = 0; - } - SettingService.SetValue(SettingConstants.Player.PLAYER_VOLUME, NumBoxVolume.Value/100); - }; - }; - - // 锁定播放器音量设置 - SwLockPlayerVolume.IsOn = SettingService.GetValue(SettingConstants.Player.LOCK_PLAYER_VOLUME, SettingConstants.Player.DEFAULT_LOCK_PLAYER_VOLUME); - SwLockPlayerVolume.Loaded += (sender, e) => - { - SwLockPlayerVolume.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.LOCK_PLAYER_VOLUME, SwLockPlayerVolume.IsOn); - }; - }; - - // 亮度 - NumBoxBrightness.Value = Math.Round( - (Math.Abs(SettingService.GetValue( - SettingConstants.Player.PLAYER_BRIGHTNESS, - SettingConstants.Player.DEFAULT_PLAYER_BRIGHTNESS) - 1)) * 100, 2); - NumBoxBrightness.Loaded += (sender, e) => - { - NumBoxBrightness.ValueChanged += (obj, args) => - { - if (NumBoxBrightness.Value > 100) - { - NumBoxBrightness.Value = 100; - } - - if (NumBoxBrightness.Value < 0) - { - NumBoxBrightness.Value = 0; - } - - var brightness = Math.Abs((NumBoxBrightness.Value / 100) - 1); - SettingService.SetValue(SettingConstants.Player.PLAYER_BRIGHTNESS, brightness); - }; - }; - - // 锁定播放器亮度设置 - SwLockPlayerBrightness.IsOn = SettingService.GetValue(SettingConstants.Player.LOCK_PLAYER_BRIGHTNESS, SettingConstants.Player.DEFAULT_LOCK_PLAYER_BRIGHTNESS); - SwLockPlayerBrightness.Loaded += (sender, e) => - { - SwLockPlayerBrightness.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.LOCK_PLAYER_BRIGHTNESS, SwLockPlayerBrightness.IsOn); - }; - }; - - //自动打开AI字幕 - swPlayerSettingAutoOpenAISubtitle.IsOn = SettingService.GetValue(SettingConstants.Player.AUTO_OPEN_AI_SUBTITLE, false); - swPlayerSettingAutoOpenAISubtitle.Loaded += new RoutedEventHandler((sender, e) => - { - swPlayerSettingAutoOpenAISubtitle.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.AUTO_OPEN_AI_SUBTITLE, swPlayerSettingAutoOpenAISubtitle.IsOn); - }); - }); - //上报历史纪录 - SwitchPlayerReportHistory.IsOn = SettingService.GetValue(SettingConstants.Player.REPORT_HISTORY, SettingConstants.Player.DEFAULT_REPORT_HISTORY); - SwitchPlayerReportHistory.Loaded += (sender, e) => - { - SwitchPlayerReportHistory.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.REPORT_HISTORY, SwitchPlayerReportHistory.IsOn); - }; - }; - - //视频结束上报历史纪录0 - SwitchReportHistoryZeroWhenVideoEnd.IsOn = SettingService.GetValue(SettingConstants.Player.REPORT_HISTORY_ZERO_WHEN_VIDEO_END, SettingConstants.Player.DEFAULT_REPORT_HISTORY_ZERO_WHEN_VIDEO_END); - SwitchReportHistoryZeroWhenVideoEnd.Loaded += (sender, e) => - { - SwitchReportHistoryZeroWhenVideoEnd.Toggled += (obj, args) => - { - SettingService.SetValue(SettingConstants.Player.REPORT_HISTORY_ZERO_WHEN_VIDEO_END, SwitchReportHistoryZeroWhenVideoEnd.IsOn); - }; - }; - //替换CDN - cbPlayerReplaceCDN.SelectedIndex = SettingService.GetValue(SettingConstants.Player.REPLACE_CDN, 3); - cbPlayerReplaceCDN.Loaded += new RoutedEventHandler((sender, e) => - { - cbPlayerReplaceCDN.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Player.REPLACE_CDN, cbPlayerReplaceCDN.SelectedIndex); - }); - }); - //CDN服务器 - var cdnServer = SettingService.GetValue(SettingConstants.Player.CDN_SERVER, "upos-sz-mirrorhwo1.bilivideo.com"); - RoamingSettingCDNServer.SelectedIndex = settingVM.CDNServers.FindIndex(x => x.Server == cdnServer); - RoamingSettingCDNServer.Loaded += new RoutedEventHandler((sender, e) => - { - RoamingSettingCDNServer.SelectionChanged += new SelectionChangedEventHandler((obj, args) => - { - var server = settingVM.CDNServers[RoamingSettingCDNServer.SelectedIndex]; - SettingService.SetValue(SettingConstants.Player.CDN_SERVER, server.Server); - - }); - }); - } - private void LoadRoaming() - { - //使用自定义服务器 - RoamingSettingSetDefault.Click += RoamingSettingSetDefault_Click; - RoamingSettingCustomServer.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, ApiHelper.ROMAING_PROXY_URL); - RoamingSettingCustomServer.Loaded += new RoutedEventHandler((sender, e) => - { - RoamingSettingCustomServer.QuerySubmitted += RoamingSettingCustomServer_QuerySubmitted; - }); - - //自定义HK服务器 - RoamingSettingCustomServerHK.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_HK, ""); - RoamingSettingCustomServerHK.Loaded += new RoutedEventHandler((sender, e) => - { - RoamingSettingCustomServerHK.QuerySubmitted += new TypedEventHandler((sender2, args) => - { - var text = sender2.Text; - if (string.IsNullOrEmpty(text)) - { - Notify.ShowMessageToast("已取消自定义香港代理服务器"); - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_HK, ""); - return; - } - if (!text.Contains("http")) - { - text = "https://" + text; - } - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_HK, text); - sender2.Text = text; - Notify.ShowMessageToast("保存成功"); - }); - }); - - //自定义TW服务器 - RoamingSettingCustomServerTW.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_TW, ""); - RoamingSettingCustomServerTW.Loaded += new RoutedEventHandler((sender, e) => - { - RoamingSettingCustomServerTW.QuerySubmitted += new TypedEventHandler((sender2, args) => - { - var text = sender2.Text; - if (string.IsNullOrEmpty(text)) - { - Notify.ShowMessageToast("已取消自定义台湾代理服务器"); - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_TW, ""); - return; - } - if (!text.Contains("http")) - { - text = "https://" + text; - } - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_TW, text); - sender2.Text = text; - Notify.ShowMessageToast("保存成功"); - }); - }); - - //自定义大陆服务器 - RoamingSettingCustomServerCN.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_CN, ""); - RoamingSettingCustomServerCN.Loaded += new RoutedEventHandler((sender, e) => - { - RoamingSettingCustomServerCN.QuerySubmitted += new TypedEventHandler((sender2, args) => - { - var text = sender2.Text; - if (string.IsNullOrEmpty(text)) - { - Notify.ShowMessageToast("已取消自定义大陆代理服务器"); - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_CN, ""); - return; - } - if (!text.Contains("http")) - { - text = "https://" + text; - } - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL_CN, text); - sender2.Text = text; - Notify.ShowMessageToast("保存成功"); - }); - }); - - //Akamai - //RoamingSettingAkamaized.IsOn = SettingService.GetValue(SettingConstants.Roaming.AKAMAI_CDN, false); - //RoamingSettingAkamaized.Loaded += new RoutedEventHandler((sender, e) => - //{ - // RoamingSettingAkamaized.Toggled += new RoutedEventHandler((obj, args) => - // { - // SettingService.SetValue(SettingConstants.Roaming.AKAMAI_CDN, RoamingSettingAkamaized.IsOn); - // }); - //}); - //转简体 - RoamingSettingToSimplified.IsOn = SettingService.GetValue(SettingConstants.Roaming.TO_SIMPLIFIED, true); - RoamingSettingToSimplified.Loaded += new RoutedEventHandler((sender, e) => - { - RoamingSettingToSimplified.Toggled += new RoutedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.Roaming.TO_SIMPLIFIED, RoamingSettingToSimplified.IsOn); - }); - }); - - } - - - - private void RoamingSettingSetDefault_Click(object sender, RoutedEventArgs e) - { - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, ApiHelper.ROMAING_PROXY_URL); - RoamingSettingCustomServer.Text = ApiHelper.ROMAING_PROXY_URL; - Notify.ShowMessageToast("保存成功"); - } - - private void RoamingSettingCustomServer_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) - { - var text = sender.Text; - if (text.Length == 0 || !text.Contains(".")) - { - Notify.ShowMessageToast("输入服务器链接有误"); - sender.Text = SettingService.GetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, ApiHelper.ROMAING_PROXY_URL); - return; - } - if (!text.Contains("http")) - { - text = "https://" + text; - } - SettingService.SetValue(SettingConstants.Roaming.CUSTOM_SERVER_URL, text); - sender.Text = text; - Notify.ShowMessageToast("保存成功"); - } - - private void LoadDanmu() - { - // 弹幕引擎 - cbDanmakuEngine.SelectedValue = SettingService.GetValue(SettingConstants.VideoDanmaku.DANMAKU_ENGINE, (int)SettingConstants.VideoDanmaku.DEFAULT_DANMAKU_ENGINE); - cbDanmakuEngine.Loaded += (sender, e) => - { - cbDanmakuEngine.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.VideoDanmaku.DANMAKU_ENGINE, cbDanmakuEngine.SelectedValue); - }; - }; - //弹幕开关 - var state = SettingService.GetValue(SettingConstants.VideoDanmaku.SHOW, Visibility.Visible) == Visibility.Visible; - DanmuSettingState.IsOn = state; - DanmuSettingState.Toggled += new RoutedEventHandler((e, args) => - { - SettingService.SetValue(SettingConstants.VideoDanmaku.SHOW, DanmuSettingState.IsOn ? Visibility.Visible : Visibility.Collapsed); - }); - //弹幕关键词 - DanmuSettingListWords.ItemsSource = settingVM.ShieldWords; - - //正则关键词 - DanmuSettingListRegulars.ItemsSource = settingVM.ShieldRegulars; - - //用户 - DanmuSettingListUsers.ItemsSource = settingVM.ShieldUsers; - - //弹幕顶部距离 - numDanmakuTopMargin.Value = SettingService.GetValue(SettingConstants.VideoDanmaku.TOP_MARGIN, 0); - numDanmakuTopMargin.Loaded += new RoutedEventHandler((sender, e) => - { - numDanmakuTopMargin.ValueChanged += new TypedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.VideoDanmaku.TOP_MARGIN, args.NewValue); - }); - }); - //弹幕最大数量 - numDanmakuMaxNum.Value = SettingService.GetValue(SettingConstants.VideoDanmaku.MAX_NUM, 0); - numDanmakuMaxNum.Loaded += new RoutedEventHandler((sender, e) => - { - numDanmakuMaxNum.ValueChanged += new TypedEventHandler((obj, args) => - { - SettingService.SetValue(SettingConstants.VideoDanmaku.MAX_NUM, args.NewValue); - }); - }); - } - private void LoadLiveDanmu() - { - // 弹幕引擎 - cbLiveDanmakuEngine.SelectedValue = SettingService.GetValue(SettingConstants.Live.DANMAKU_ENGINE, (int)SettingConstants.Live.DEFAULT_DANMAKU_ENGINE); - cbLiveDanmakuEngine.Loaded += (sender, e) => - { - cbLiveDanmakuEngine.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.Live.DANMAKU_ENGINE, cbLiveDanmakuEngine.SelectedValue); - }; - }; - //弹幕开关 - var state = SettingService.GetValue(SettingConstants.Live.SHOW, Visibility.Visible) == Visibility.Visible; - LiveDanmuSettingState.IsOn = state; - LiveDanmuSettingState.Toggled += new RoutedEventHandler((e, args) => - { - SettingService.SetValue(SettingConstants.Live.SHOW, LiveDanmuSettingState.IsOn ? Visibility.Visible : Visibility.Collapsed); - }); - //弹幕关键词 - LiveDanmuSettingListWords.ItemsSource = settingVM.LiveShieldWords; - } - private void LoadDownlaod() - { - //下载路径 - txtDownloadPath.Text = SettingService.GetValue(SettingConstants.Download.DOWNLOAD_PATH, SettingConstants.Download.DEFAULT_PATH); - DownloadOpenPath.Click += new RoutedEventHandler(async (e, args) => - { - if (txtDownloadPath.Text == SettingConstants.Download.DEFAULT_PATH) - { - var videosLibrary = Windows.Storage.KnownFolders.VideosLibrary; - videosLibrary = await videosLibrary.CreateFolderAsync("哔哩哔哩下载", CreationCollisionOption.OpenIfExists); - - await Windows.System.Launcher.LaunchFolderAsync(videosLibrary); - } - else - { - await Windows.System.Launcher.LaunchFolderPathAsync(txtDownloadPath.Text); - } - }); - DownloadChangePath.Click += new RoutedEventHandler(async (e, args) => - { - FolderPicker folderPicker = new FolderPicker(); - folderPicker.FileTypeFilter.Add("*"); - folderPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary; - var folder = await folderPicker.PickSingleFolderAsync(); - if (folder != null) - { - SettingService.SetValue(SettingConstants.Download.DOWNLOAD_PATH, folder.Path); - txtDownloadPath.Text = folder.Path; - Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(folder); - m_downloadPageViewModel.RefreshDownloaded(); - } - }); - //旧版下载目录 - txtDownloadOldPath.Text = SettingService.GetValue(SettingConstants.Download.OLD_DOWNLOAD_PATH, SettingConstants.Download.DEFAULT_OLD_PATH); - DownloadOpenOldPath.Click += new RoutedEventHandler(async (e, args) => - { - if (txtDownloadOldPath.Text == SettingConstants.Download.DEFAULT_OLD_PATH) - { - var videosLibrary = Windows.Storage.KnownFolders.VideosLibrary; - videosLibrary = await videosLibrary.CreateFolderAsync("BiliBiliDownload", CreationCollisionOption.OpenIfExists); - await Windows.System.Launcher.LaunchFolderAsync(videosLibrary); - } - else - { - await Windows.System.Launcher.LaunchFolderPathAsync(txtDownloadOldPath.Text); - } - }); - DownloadChangeOldPath.Click += new RoutedEventHandler(async (e, args) => - { - FolderPicker folderPicker = new FolderPicker(); - folderPicker.FileTypeFilter.Add("*"); - folderPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary; - var folder = await folderPicker.PickSingleFolderAsync(); - if (folder != null) - { - SettingService.SetValue(SettingConstants.Download.OLD_DOWNLOAD_PATH, folder.Path); - txtDownloadOldPath.Text = folder.Path; - Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(folder); - } - }); - //并行下载 - swDownloadParallelDownload.IsOn = SettingService.GetValue(SettingConstants.Download.PARALLEL_DOWNLOAD, true); - swDownloadParallelDownload.Toggled += new RoutedEventHandler((e, args) => - { - SettingService.SetValue(SettingConstants.Download.PARALLEL_DOWNLOAD, swDownloadParallelDownload.IsOn); - m_downloadPageViewModel.UpdateSetting(); - }); - //付费网络下载 - swDownloadAllowCostNetwork.IsOn = SettingService.GetValue(SettingConstants.Download.ALLOW_COST_NETWORK, false); - swDownloadAllowCostNetwork.Toggled += new RoutedEventHandler((e, args) => - { - SettingService.SetValue(SettingConstants.Download.ALLOW_COST_NETWORK, swDownloadAllowCostNetwork.IsOn); - m_downloadPageViewModel.UpdateSetting(); - }); - //下载完成发送通知 - swDownloadSendToast.IsOn = SettingService.GetValue(SettingConstants.Download.SEND_TOAST, false); - swDownloadSendToast.Toggled += new RoutedEventHandler((e, args) => - { - SettingService.SetValue(SettingConstants.Download.SEND_TOAST, swDownloadSendToast.IsOn); - }); - //下载类型 - var selectedValue = (PlayUrlCodecMode)SettingService.GetValue(SettingConstants.Download.DEFAULT_VIDEO_TYPE, (int)DefaultVideoTypeOptions.DEFAULT_VIDEO_TYPE); - cbDownloadVideoType.SelectedItem = DefaultVideoTypeOptions.GetOption(selectedValue); - cbDownloadVideoType.Loaded += (sender, e) => - { - cbDownloadVideoType.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.Download.DEFAULT_VIDEO_TYPE, (int)cbDownloadVideoType.SelectedValue); - }; - }; - //加载旧版本下载的视频 - swDownloadLoadOld.IsOn = SettingService.GetValue(SettingConstants.Download.LOAD_OLD_DOWNLOAD, false); - swDownloadLoadOld.Toggled += new RoutedEventHandler((e, args) => - { - SettingService.SetValue(SettingConstants.Download.LOAD_OLD_DOWNLOAD, swDownloadLoadOld.IsOn); - }); - } - - private void LoadOther() - { - //自动清理日志文件 - swAutoClearLogFile.IsOn = SettingService.GetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE, true); - swAutoClearLogFile.Toggled += new RoutedEventHandler((e, args) => - { - SettingService.SetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE, swAutoClearLogFile.IsOn); - }); - //自动清理多少天前的日志文件 - numAutoClearLogDay.Value = SettingService.GetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE_DAY, 7); - numAutoClearLogDay.ValueChanged += ((e, args) => - { - SettingService.SetValue(SettingConstants.Other.AUTO_CLEAR_LOG_FILE_DAY, numAutoClearLogDay.Value); - }); - //保护日志敏感信息 - swProtectLogInfo.IsOn = SettingService.GetValue(SettingConstants.Other.PROTECT_LOG_INFO, true); - swProtectLogInfo.Toggled += ((e, args) => - { - SettingService.SetValue(SettingConstants.Other.PROTECT_LOG_INFO, swProtectLogInfo.IsOn); - }); - // 日志级别 - cbLogLevel.SelectedIndex = SettingService.GetValue(SettingConstants.Other.LOG_LEVEL, 2); - cbLogLevel.Loaded += (sender, e) => - { - cbLogLevel.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.Other.LOG_LEVEL, cbLogLevel.SelectedIndex); - }; - }; - - // 优先使用Grpc请求动态 - swFirstGrpcRequestDynamic.IsOn = SettingService.GetValue(SettingConstants.Other.FIRST_GRPC_REQUEST_DYNAMIC, true); - swFirstGrpcRequestDynamic.Toggled += ((e, args) => - { - SettingService.SetValue(SettingConstants.Other.FIRST_GRPC_REQUEST_DYNAMIC, swFirstGrpcRequestDynamic.IsOn); - }); - - RequestBuildTextBox.Text = SettingService.GetValue(SettingConstants.Other.REQUEST_BUILD, - SettingConstants.Other.DEFAULT_REQUEST_BUILD); - - // BiliLiteWebApi - BiliLiteWebApiTextBox.Text = SettingService.GetValue(SettingConstants.Other.BILI_LITE_WEB_API_BASE_URL, ApiConstants.BILI_LITE_WEB_API_DEFAULT_BASE_URL); - BiliLiteWebApiTextBox.Loaded += (sender, e) => - { - BiliLiteWebApiTextBox.QuerySubmitted += (sender2, args) => - { - var text = sender2.Text; - if (string.IsNullOrEmpty(text)) - { - Notify.ShowMessageToast("已取消自定义BiliLiteWebApi服务器"); - SettingService.SetValue(SettingConstants.Other.BILI_LITE_WEB_API_BASE_URL, ""); - return; - } - if (!text.EndsWith("/")) text += "/"; - if(!Uri.IsWellFormedUriString(text, UriKind.Absolute)) - { - Notify.ShowMessageToast("地址格式错误"); - return; - } - SettingService.SetValue(SettingConstants.Other.BILI_LITE_WEB_API_BASE_URL, text); - sender2.Text = text; - Notify.ShowMessageToast("保存成功"); - }; - }; - - // 更新json来源 - var selectedValue = SettingService.GetValue(SettingConstants.Other.UPDATE_JSON_ADDRESS, UpdateJsonAddressOptions.DEFAULT_UPDATE_JSON_ADDRESS); - selectedValue = selectedValue.Replace("\"", ""); // 解决取出的值有奇怪的转义符 - updateJsonAddress.SelectedItem = UpdateJsonAddressOptions.GetOption(selectedValue); - mirrorComboboxSelectAction(selectedValue); - updateJsonAddress.Loaded += (sender, e) => - { - updateJsonAddress.SelectionChanged += (obj, args) => - { - SettingService.SetValue(SettingConstants.Other.UPDATE_JSON_ADDRESS, updateJsonAddress.SelectedValue); - mirrorComboboxSelectAction(updateJsonAddress.SelectedValue); - }; - }; - } - - private void ExceptHomeNavItems() - { - var defaultNavItems = DefaultHomeNavItems.GetDefaultHomeNavItems(); - var hideNavItems = DefaultHomeNavItems.GetDefaultHideHomeNavItems(); - var customNavItem = gridHomeCustom.ItemsSource as ObservableCollection; - - var customDontHideNavItems = hideNavItems.Where(hideNavItem => - customNavItem.Any(x => x.Title == hideNavItem.Title)).ToList(); - - foreach (var customDontHideNavItem in customDontHideNavItems) - { - hideNavItems.Remove(customDontHideNavItem); - } - - foreach (var navItem in defaultNavItems) - { - if (!customNavItem.Any(x => x.Title == navItem.Title)) - { - hideNavItems.Add(navItem); - } - } - - gridHomeNavItem.ItemsSource = hideNavItems; - } - private void gridHomeCustom_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args) - { - if (!(gridHomeCustom.ItemsSource is ObservableCollection navItems)) return; - SettingService.SetValue(SettingConstants.UI.HOEM_ORDER, navItems.ToList()); - Notify.ShowMessageToast("更改成功,重启生效"); - } - - private void gridHomeNavItem_ItemClick(object sender, ItemClickEventArgs e) - { - var item = e.ClickedItem as HomeNavItem; - if (!(gridHomeCustom.ItemsSource is ObservableCollection navItems)) return; - navItems.Add(item); - SettingService.SetValue(SettingConstants.UI.HOEM_ORDER, navItems.ToList()); - ExceptHomeNavItems(); - Notify.ShowMessageToast("更改成功,重启生效"); - } - - private void menuRemoveHomeItem_Click(object sender, RoutedEventArgs e) - { - var item = (sender as MenuFlyoutItem).DataContext as HomeNavItem; - if (gridHomeCustom.Items.Count == 1) - { - Notify.ShowMessageToast("至少要留一个页面"); - return; - } - (gridHomeCustom.ItemsSource as ObservableCollection).Remove(item); - SettingService.SetValue(SettingConstants.UI.HOEM_ORDER, gridHomeCustom.ItemsSource as ObservableCollection); - ExceptHomeNavItems(); - Notify.ShowMessageToast("更改成功,重启生效"); - } protected async override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); try { - version.Text = $"版本 {SystemInformation.ApplicationVersion.Major}.{SystemInformation.ApplicationVersion.Minor}.{SystemInformation.ApplicationVersion.Build}.{SystemInformation.ApplicationVersion.Revision}"; txtHelp.Text = await FileIO.ReadTextAsync(await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Text/help.md"))); } catch (Exception) @@ -1008,88 +29,8 @@ protected async override void OnNavigatedTo(NavigationEventArgs e) throw; } - - } - - private async void DanmuSettingAddWord_Click(object sender, RoutedEventArgs e) - { - if (string.IsNullOrEmpty(DanmuSettingTxtWord.Text)) - { - Notify.ShowMessageToast("关键词不能为空"); - return; - } - settingVM.ShieldWords.Add(DanmuSettingTxtWord.Text); - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, settingVM.ShieldWords); - var result = await settingVM.AddDanmuFilterItem(DanmuSettingTxtWord.Text, 0); - DanmuSettingTxtWord.Text = ""; - if (!result) - { - Notify.ShowMessageToast("已经添加到本地,但远程同步失败"); - } - } - - private async void DanmuSettingSyncWords_Click(object sender, RoutedEventArgs e) - { - await settingVM.SyncDanmuFilter(); - } - - private void RemoveDanmuWord_Click(object sender, RoutedEventArgs e) - { - var word = (sender as AppBarButton).DataContext as string; - settingVM.ShieldWords.Remove(word); - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, settingVM.ShieldWords); - } - - private void RemoveDanmuRegular_Click(object sender, RoutedEventArgs e) - { - var word = (sender as AppBarButton).DataContext as string; - settingVM.ShieldRegulars.Remove(word); - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_REGULAR, settingVM.ShieldRegulars); - } - - private void RemoveDanmuUser_Click(object sender, RoutedEventArgs e) - { - var word = (sender as AppBarButton).DataContext as string; - settingVM.ShieldUsers.Remove(word); - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_USER, settingVM.ShieldUsers); - } - - private async void DanmuSettingAddRegex_Click(object sender, RoutedEventArgs e) - { - if (string.IsNullOrEmpty(DanmuSettingTxtRegex.Text)) - { - Notify.ShowMessageToast("正则表达式不能为空"); - return; - } - var txt = DanmuSettingTxtRegex.Text.Trim('/'); - settingVM.ShieldRegulars.Add(txt); - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_REGULAR, settingVM.ShieldRegulars); - var result = await settingVM.AddDanmuFilterItem(txt, 1); - DanmuSettingTxtRegex.Text = ""; - if (!result) - { - Notify.ShowMessageToast("已经添加到本地,但远程同步失败"); - } } - private async void DanmuSettingAddUser_Click(object sender, RoutedEventArgs e) - { - if (string.IsNullOrEmpty(DanmuSettingTxtUser.Text)) - { - Notify.ShowMessageToast("用户ID不能为空"); - return; - } - settingVM.ShieldUsers.Add(DanmuSettingTxtUser.Text); - SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, settingVM.ShieldUsers); - var result = await settingVM.AddDanmuFilterItem(DanmuSettingTxtUser.Text, 2); - DanmuSettingTxtUser.Text = ""; - if (!result) - { - Notify.ShowMessageToast("已经添加到本地,但远程同步失败"); - } - } - - private async void txtHelp_LinkClicked(object sender, Microsoft.Toolkit.Uwp.UI.Controls.LinkClickedEventArgs e) { if (e.Link == "OpenLog") @@ -1101,141 +42,6 @@ private async void txtHelp_LinkClicked(object sender, Microsoft.Toolkit.Uwp.UI.C { await Windows.System.Launcher.LaunchUriAsync(new Uri(e.Link)); } - - } - - private void LiveDanmuSettingAddWord_Click(object sender, RoutedEventArgs e) - { - if (string.IsNullOrEmpty(LiveDanmuSettingTxtWord.Text)) - { - Notify.ShowMessageToast("关键字不能为空"); - return; - } - if (!settingVM.LiveShieldWords.Contains(LiveDanmuSettingTxtWord.Text)) - { - settingVM.LiveShieldWords.Add(LiveDanmuSettingTxtWord.Text); - SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, settingVM.LiveShieldWords); - } - - DanmuSettingTxtWord.Text = ""; - SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, settingVM.LiveShieldWords); - } - - private void RemoveLiveDanmuWord_Click(object sender, RoutedEventArgs e) - { - var word = (sender as AppBarButton).DataContext as string; - settingVM.LiveShieldWords.Remove(word); - SettingService.SetValue(SettingConstants.Live.SHIELD_WORD, settingVM.LiveShieldWords); - } - - private async void btnCleanImageCache_Click(object sender, RoutedEventArgs e) - { - await ImageCache.Instance.ClearAsync(); - Notify.ShowMessageToast("已清除图片缓存"); - } - - private void RoamingSettingTestCDN_Click(object sender, RoutedEventArgs e) - { - settingVM.CDNServerDelayTest(); - } - - private async void btnCheckUpdate_Click(object sender, RoutedEventArgs e) - { - await BiliExtensions.CheckVersion(); - } - - private void btnCleanUpdateIgnore_Click(object sender, RoutedEventArgs e) - { - SettingService.SetValue(SettingConstants.Other.IGNORE_VERSION, ""); - } - - private void mirrorComboboxSelectAction(object selectedValue) - { - switch (selectedValue) - { - case ApiHelper.GHPROXY_GIT_RAW_URL: - { - mirrorDonateText.Visibility = Visibility.Visible; - mirrorDonateUrl.NavigateUri = new Uri("https://mirror.ghproxy.com/donate"); - break; - } - case ApiHelper.KGITHUB_GIT_RAW_URL: - { - mirrorDonateText.Visibility = Visibility.Visible; - mirrorDonateUrl.NavigateUri = new Uri("https://help.kkgithub.com/donate"); - break; - } - case ApiHelper.GIT_RAW_URL: - { - mirrorDonateText.Visibility = Visibility.Collapsed; break; - } - default: - { - mirrorDonateText.Visibility = Visibility.Collapsed; break; - } - } - } - - private void RequestBuildSaveBtn_OnClick(object sender, RoutedEventArgs e) - { - var build = RequestBuildTextBox.Text; - if (string.IsNullOrWhiteSpace(build)) - { - Notify.ShowMessageToast("请输入正确的build值"); - return; - } - - SettingService.SetValue(SettingConstants.Other.REQUEST_BUILD, build); - Notify.ShowMessageToast("已保存"); - } - - private void RequestBuildDefaultBtn_OnClick(object sender, RoutedEventArgs e) - { - var build = SettingConstants.Other.DEFAULT_REQUEST_BUILD; - SettingService.SetValue(SettingConstants.Other.REQUEST_BUILD, build); - RequestBuildTextBox.Text = build; - Notify.ShowMessageToast("已恢复默认"); - } - - private async void BtnExportSettings_OnClick(object sender, RoutedEventArgs e) - { - var exportService = App.ServiceProvider.GetRequiredService(); - await exportService.ExportSettings(); - } - - private async void BtnImportSettings_OnClick(object sender, RoutedEventArgs e) - { - var importService = App.ServiceProvider.GetRequiredService(); - if (!await importService.ImportSettings()) - { - return; - } - Notify.ShowMessageToast("导入成功,正在重启应用"); - // 等用户看提示 - await Task.Delay(3000); - var result = await CoreApplication.RequestRestartAsync(""); - - if (result == AppRestartFailureReason.NotInForeground || result == AppRestartFailureReason.Other) - { - Notify.ShowMessageToast("重启失败,请手动重启应用"); - } - } - - private async void BtnExportSettingsWithAccount_OnClick(object sender, RoutedEventArgs e) - { - var exportService = App.ServiceProvider.GetRequiredService(); - await exportService.ExportSettingsWithAccount(); - } - - private async void DanmuSettingFilterImport_OnClick(object sender, RoutedEventArgs e) - { - await settingVM.ImportDanmuFilter(); - } - - private async void BtnEditPlaySpeedMenu_OnClick(object sender, RoutedEventArgs e) - { - var dialog = App.ServiceProvider.GetRequiredService(); - await dialog.ShowAsync(); } } } diff --git a/src/BiliLite.UWP/Services/MessageCenter.cs b/src/BiliLite.UWP/Services/MessageCenter.cs index f18851c6..6e0e951e 100644 --- a/src/BiliLite.UWP/Services/MessageCenter.cs +++ b/src/BiliLite.UWP/Services/MessageCenter.cs @@ -16,6 +16,7 @@ using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using BiliLite.ViewModels.Settings; using Microsoft.Extensions.DependencyInjection; namespace BiliLite.Services @@ -60,7 +61,7 @@ public async static void SendLogined() { LoginedEvent?.Invoke(null, null); //同步弹幕屏蔽信息 - await new Modules.SettingVM().SyncDanmuFilter(); + await App.ServiceProvider.GetRequiredService().SyncDanmuFilter(); } /// /// 发送注销事件 diff --git a/src/BiliLite.UWP/Themes/Dark.xaml b/src/BiliLite.UWP/Themes/Dark.xaml index 9e085fc8..67d4b91d 100644 --- a/src/BiliLite.UWP/Themes/Dark.xaml +++ b/src/BiliLite.UWP/Themes/Dark.xaml @@ -14,7 +14,8 @@ #CC000000 #ec407a #008ac5 - Gray + #989898 + Gray #805C5C5C diff --git a/src/BiliLite.UWP/Themes/Light.xaml b/src/BiliLite.UWP/Themes/Light.xaml index 1e655668..81b634f7 100644 --- a/src/BiliLite.UWP/Themes/Light.xaml +++ b/src/BiliLite.UWP/Themes/Light.xaml @@ -14,7 +14,8 @@ #CC000000 #ec407a #008ac5 - Gray + #989898 + Gray #805C5C5C diff --git a/src/BiliLite.UWP/ViewModels/Settings/CDNServerItemViewModel.cs b/src/BiliLite.UWP/ViewModels/Settings/CDNServerItemViewModel.cs new file mode 100644 index 00000000..47780d43 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Settings/CDNServerItemViewModel.cs @@ -0,0 +1,25 @@ +using BiliLite.ViewModels.Common; +using PropertyChanged; + +namespace BiliLite.ViewModels.Settings +{ + public class CDNServerItemViewModel : BaseViewModel + { + public CDNServerItemViewModel(string server, string remark) + { + this.Server = server; + this.Remark = remark; + } + + public string Server { get; set; } + + public string Remark { get; set; } + + public bool ShowDelay => Delay > 0; + + public bool ShowTimeOut => Delay < 0; + + [AlsoNotifyFor(nameof(ShowDelay),nameof(ShowTimeOut))] + public long Delay { get; set; } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/ViewModels/Settings/LiveSettingsControlViewModel.cs b/src/BiliLite.UWP/ViewModels/Settings/LiveSettingsControlViewModel.cs new file mode 100644 index 00000000..bd2c5546 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Settings/LiveSettingsControlViewModel.cs @@ -0,0 +1,22 @@ +using System.Collections.ObjectModel; +using BiliLite.Models.Common; +using BiliLite.Services; +using BiliLite.ViewModels.Common; + +namespace BiliLite.ViewModels.Settings +{ + public class LiveSettingsControlViewModel : BaseViewModel + { + public LiveSettingsControlViewModel() + { + LoadShieldSetting(); + } + + public ObservableCollection LiveShieldWords { get; set; } + + public void LoadShieldSetting() + { + LiveShieldWords = SettingService.GetValue>(SettingConstants.Live.SHIELD_WORD, new ObservableCollection() { }); + } + } +} diff --git a/src/BiliLite.UWP/ViewModels/Settings/PlaySettingsControlViewModel.cs b/src/BiliLite.UWP/ViewModels/Settings/PlaySettingsControlViewModel.cs new file mode 100644 index 00000000..8fd68bd3 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Settings/PlaySettingsControlViewModel.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using BiliLite.ViewModels.Common; +using Flurl.Http; + +namespace BiliLite.ViewModels.Settings +{ + public class PlaySettingsControlViewModel : BaseViewModel + { + public PlaySettingsControlViewModel() + { + CDNServers = new List() + { + new CDNServerItemViewModel("upos-sz-mirrorhwo1.bilivideo.com","华为云"), + new CDNServerItemViewModel("upos-sz-mirrorcos.bilivideo.com","腾讯云"), + new CDNServerItemViewModel("upos-sz-mirrorali.bilivideo.com","阿里云"), + new CDNServerItemViewModel("upos-sz-mirrorhw.bilivideo.com","华为云"), + new CDNServerItemViewModel("upos-sz-mirrorks3.bilivideo.com","金山云"), + new CDNServerItemViewModel("upos-tf-all-js.bilivideo.com","JS"), + new CDNServerItemViewModel("cn-hk-eq-bcache-01.bilivideo.com","香港"), + new CDNServerItemViewModel("cn-hk-eq-bcache-16.bilivideo.com","香港"), + new CDNServerItemViewModel("upos-hz-mirrorakam.akamaized.net","Akamaized"), + }; + } + + public List CDNServers { get; set; } + + /// + /// CDN延迟测试 + /// + public async void CDNServerDelayTest() + { + foreach (var item in CDNServers) + { + var time = await GetDelay(item.Server); + item.Delay = time; + } + } + + private async Task GetDelay(string server) + { + //随便整个链接 + var testUrl = $"https://{server}/upgcxcode/76/62/729206276/729206276_nb2-1-30112.m4s"; + + try + { + Stopwatch sw = Stopwatch.StartNew(); + var res = await testUrl.WithTimeout(2).GetAsync(); + sw.Stop(); + return sw.ElapsedMilliseconds; + } + catch (Exception) + { + return -1; + } + } + + // UWP不支持ping,后续更新WindowsAppSDK再考虑启用 + //private async Task GetPing(string address){} + } +} diff --git a/src/BiliLite.UWP/ViewModels/Settings/VideoDanmakuSettingsControlViewModel.cs b/src/BiliLite.UWP/ViewModels/Settings/VideoDanmakuSettingsControlViewModel.cs new file mode 100644 index 00000000..d06d2b30 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Settings/VideoDanmakuSettingsControlViewModel.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using BiliLite.ViewModels.Common; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Storage.Pickers; +using BiliLite.Extensions; +using BiliLite.Models.Common; +using BiliLite.Models.Common.Danmaku; +using BiliLite.Models.Requests.Api; +using BiliLite.Services; +using Microsoft.Toolkit.Uwp.Helpers; +using Newtonsoft.Json; + +namespace BiliLite.ViewModels.Settings +{ + public class VideoDanmakuSettingsControlViewModel : BaseViewModel + { + private static readonly ILogger _logger = GlobalLogger.FromCurrentType(); + private readonly PlayerAPI m_playerAPI; + + public VideoDanmakuSettingsControlViewModel() + { + m_playerAPI = new PlayerAPI(); + LoadShieldSetting(); + } + + /// + /// 弹幕屏蔽关键词列表 + /// + public ObservableCollection ShieldWords { get; set; } + public ObservableCollection ShieldUsers { get; set; } + public ObservableCollection ShieldRegulars { get; set; } + + public void LoadShieldSetting() + { + ShieldWords = SettingService.GetValue>(SettingConstants.VideoDanmaku.SHIELD_WORD, new ObservableCollection() { }); + + //正则关键词 + ShieldRegulars = SettingService.GetValue>(SettingConstants.VideoDanmaku.SHIELD_REGULAR, new ObservableCollection() { }); + + //用户 + ShieldUsers = SettingService.GetValue>(SettingConstants.VideoDanmaku.SHIELD_USER, new ObservableCollection() { }); + } + public async Task ImportDanmuFilter() + { + var filePicker = new FileOpenPicker(); + filePicker.FileTypeFilter.Add(".json"); + var file = await filePicker.PickSingleFileAsync(); + if (file == null) return; + using var stream = await file.OpenReadAsync(); + var text = await stream.ReadTextAsync(Encoding.UTF8); + var filterList = JsonConvert.DeserializeObject>(text); + + ImportDanmakuFilterCore(filterList); + } + + public async Task SyncDanmuFilter() + { + try + { + var result = await m_playerAPI.GetDanmuFilterWords().Request(); + if (!result.status) + { + Notify.ShowMessageToast(result.message); + return; + } + var obj = result.GetJObject(); + if (obj["code"].ToInt32() == 0) + { + var items = JsonConvert.DeserializeObject>(obj["data"]["rule"].ToString()); + + ImportDanmakuFilterCore(items); + } + else + { + Notify.ShowMessageToast(obj["message"].ToString()); + } + } + catch (Exception ex) + { + _logger.Log("读取弹幕屏蔽词失败", LogType.Error, ex); + } + } + + public async Task AddDanmuFilterItem(string word, int type) + { + try + { + var result = await m_playerAPI.AddDanmuFilterWord(word: word, type: type).Request(); + if (!result.status) + { + return false; + } + var obj = result.GetJObject(); + return obj["code"].ToInt32() == 0; + } + catch (Exception ex) + { + _logger.Log("添加弹幕屏蔽词失败", LogType.Error, ex); + return false; + } + } + + private void ImportDanmakuFilterCore(List filterList) + { + { + var words = filterList.Where(x => x.Type == 0).Select(x => x.Filter).ToList(); + var ls = ShieldWords.Union(words); + ShieldWords.Clear(); + foreach (var item in ls) + { + ShieldWords.Add(item); + } + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_WORD, ShieldWords); + } + { + var users = filterList.Where(x => x.Type == 1).Select(x => x.Filter).ToList(); + var ls = ShieldRegulars.Union(users); + ShieldRegulars.Clear(); + foreach (var item in ls) + { + if (!item.IsValidRegex()) + { + _logger.Warn("非法正则表达式: " + item); + continue; + } + ShieldRegulars.Add(item); + } + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_REGULAR, ShieldRegulars); + } + { + var users = filterList.Where(x => x.Type == 2).Select(x => x.Filter).ToList(); + var ls = ShieldUsers.Union(users); + ShieldUsers.Clear(); + foreach (var item in ls) + { + ShieldUsers.Add(item); + } + SettingService.SetValue(SettingConstants.VideoDanmaku.SHIELD_USER, ShieldUsers); + } + } + } +} From 23e143eda39bdb02d200112d676e3785ed66b784 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Tue, 16 Jul 2024 20:16:20 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E8=AF=A6=E6=83=85=E5=92=8C=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/Models/Common/Enumerates.cs | 1 + .../Models/Common/Settings/FilterRuleTypes.cs | 1 + src/BiliLite.UWP/Modules/SearchVM.cs | 1 + .../Services/ContentFilterService.cs | 18 +++++ .../Settings/FilterRuleViewModel.cs | 6 +- .../UserDynamic/DynamicV2ItemViewModel.cs | 79 +++++++++++++++++++ 6 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/BiliLite.UWP/Models/Common/Enumerates.cs b/src/BiliLite.UWP/Models/Common/Enumerates.cs index 1106d71c..ffc92e0a 100644 --- a/src/BiliLite.UWP/Models/Common/Enumerates.cs +++ b/src/BiliLite.UWP/Models/Common/Enumerates.cs @@ -514,5 +514,6 @@ public enum FilterContentType { Title, User, + Desc, } } \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs b/src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs index e713190b..893c3b13 100644 --- a/src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs +++ b/src/BiliLite.UWP/Models/Common/Settings/FilterRuleTypes.cs @@ -13,6 +13,7 @@ public class FilterRuleTypes { new FilterTargetOption(FilterContentType.Title, "标题"), new FilterTargetOption(FilterContentType.User, "用户"), + new FilterTargetOption(FilterContentType.Desc, "详情"), }; } diff --git a/src/BiliLite.UWP/Modules/SearchVM.cs b/src/BiliLite.UWP/Modules/SearchVM.cs index 08dc5303..085e58a3 100644 --- a/src/BiliLite.UWP/Modules/SearchVM.cs +++ b/src/BiliLite.UWP/Modules/SearchVM.cs @@ -852,6 +852,7 @@ public string pic set { _pic = "https:" + value; } } + public string Description { get; set; } } public class SearchAnimeItem { diff --git a/src/BiliLite.UWP/Services/ContentFilterService.cs b/src/BiliLite.UWP/Services/ContentFilterService.cs index 79b312ed..3449c8e0 100644 --- a/src/BiliLite.UWP/Services/ContentFilterService.cs +++ b/src/BiliLite.UWP/Services/ContentFilterService.cs @@ -168,6 +168,12 @@ public List FilterSearchItems(List searchItems FilterType.Regular => current.Where(x => !new Regex(rule.Rule).IsMatch(x.author)), _ => current }, + FilterContentType.Desc => rule.FilterType switch + { + FilterType.Word => current.Where(x => !x.Description.Contains(rule.Rule)), + FilterType.Regular => current.Where(x => !new Regex(rule.Rule).IsMatch(x.Description)), + _ => current + }, _ => current }); @@ -198,6 +204,18 @@ public List FilterDynamicItems(List current.Where(x => !(x.Author != null && new Regex(rule.Rule).IsMatch(x.Author.Author.Name))), _ => current }, + FilterContentType.Desc => rule.FilterType switch + { + FilterType.Word => current.Where(x => !(x.ContentStr != null && x.ContentStr.Contains(rule.Rule))), + FilterType.Regular => current.Where(x => !(x.ContentStr != null && new Regex(rule.Rule).IsMatch(x.ContentStr))), + _ => current + }, + FilterContentType.Title => rule.FilterType switch + { + FilterType.Word => current.Where(x => !(x.ManuscriptTitle.Contains(rule.Rule))), + FilterType.Regular => current.Where(x => !(new Regex(rule.Rule).IsMatch(x.ManuscriptTitle))), + _ => current + }, _ => current }); diff --git a/src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs b/src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs index ee20292f..508891ca 100644 --- a/src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs +++ b/src/BiliLite.UWP/ViewModels/Settings/FilterRuleViewModel.cs @@ -43,7 +43,11 @@ public string FilterContentTypeDesc var desc = "选择过滤目标对象属性"; if (FilterRuleType == FilterRuleType.Dynamic) { - return desc + "(动态不支持过滤标题)"; + return desc + "(动态项过滤标题指过滤投稿标题)"; + } + if (FilterRuleType == FilterRuleType.Recommend) + { + return desc + "(推荐项不支持过滤详情)"; } return desc; diff --git a/src/BiliLite.UWP/ViewModels/UserDynamic/DynamicV2ItemViewModel.cs b/src/BiliLite.UWP/ViewModels/UserDynamic/DynamicV2ItemViewModel.cs index c23e95f1..8a0d45ee 100644 --- a/src/BiliLite.UWP/ViewModels/UserDynamic/DynamicV2ItemViewModel.cs +++ b/src/BiliLite.UWP/ViewModels/UserDynamic/DynamicV2ItemViewModel.cs @@ -25,6 +25,46 @@ public DynamicV2ItemViewModel() m_mapper = App.ServiceProvider.GetRequiredService(); } + [DoNotNotify] + public string ManuscriptTitle + { + get + { + // Dynamic.DynArchive.Title + if (Dynamic is { DynArchive: { }}) + { + return Dynamic.DynArchive.Title; + } + // Extend.OrigDesc[0].Text + if (Extend is { OrigDesc: { } } && Extend.OrigDesc.Count > 0) + { + return Extend.OrigDesc[0].Text; + } + // LiveInfo.PlayInfo.Title + if (LiveInfo is { PlayInfo: { } }) + { + return LiveInfo.PlayInfo.Title; + } + // Dynamic.DynCourBatchUp.Title + if (Dynamic is { DynCourBatchUp: { } }) + { + return Dynamic.DynCourBatchUp.Title; + } + // Season.Title + if (Season is { }) + { + return Season.Title; + } + // CustomArticle.Title + if (CustomArticle is { }) + { + return CustomArticle.Title; + } + + return ""; + } + } + public IUserDynamicCommands Parent { get; set; } public string CardType { get; set; } @@ -133,6 +173,45 @@ public ModuleStat Stat [DependsOn(nameof(Content))] public bool ShowContent => Desc != null || OpusSummary != null; + [DoNotNotify] + public string ContentStr + { + get + { + if (Extend.OpusSummary != null && Extend.OpusSummary.Summary.Text != null) + { + var text = ""; + if (Extend.OpusSummary.Title != null) + { + var title = Extend.OpusSummary.Title.Text.Nodes + .Aggregate("", (current, textNode) => current + textNode.RawText); + text = title + "\n"; + } + + text += Extend.OpusSummary.Summary.Text.Nodes + .Aggregate("", (current, textNode) => current + textNode.RawText); + + return text; + } + + if (Desc != null) + { + return + Desc.Text; + } + + if (OpusSummary != null) + { + var text = OpusSummary.Summary.Text.Nodes.Aggregate("", (current, textNode) => current + textNode.RawText); + + return + text; + } + + return ""; + } + } + [DependsOn(nameof(Desc),nameof(OpusSummary))] public RichTextBlock Content { From 44e55375cb984a3417922435e81ccf94702ab678 Mon Sep 17 00:00:00 2001 From: ywmoyue Date: Thu, 18 Jul 2024 19:37:38 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E8=A7=86=E9=A2=91=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E9=A1=B5=E6=92=AD=E6=94=BE=E5=88=97=E8=A1=A8Tab=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=BB=9A=E5=8A=A8=E5=88=B0=E9=A1=B6=E9=83=A8=E3=80=81?= =?UTF-8?q?=E5=BA=95=E9=83=A8=E5=92=8C=E5=BD=93=E5=89=8D=E8=A7=86=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BiliLite.UWP/BiliLite.UWP.csproj | 8 + .../Controls/Common/PieControl.xaml | 152 ++++++++++++++++ .../Controls/Common/PieControl.xaml.cs | 162 ++++++++++++++++++ src/BiliLite.UWP/Controls/VideoListView.xaml | 96 +++++++---- .../Controls/VideoListView.xaml.cs | 59 ++++++- .../Extensions/ControlsExtensions.cs | 43 +++++ src/BiliLite.UWP/Themes/Dark.xaml | 2 + src/BiliLite.UWP/Themes/Light.xaml | 2 + .../ViewModels/Common/PieControlViewModel.cs | 20 +++ 9 files changed, 505 insertions(+), 39 deletions(-) create mode 100644 src/BiliLite.UWP/Controls/Common/PieControl.xaml create mode 100644 src/BiliLite.UWP/Controls/Common/PieControl.xaml.cs create mode 100644 src/BiliLite.UWP/ViewModels/Common/PieControlViewModel.cs diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index 0cd55a56..bb1b9081 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -139,6 +139,9 @@ AttentionButton.xaml + + PieControl.xaml + DynamicItemV2Control.xaml @@ -226,6 +229,7 @@ + @@ -1046,6 +1050,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/src/BiliLite.UWP/Controls/Common/PieControl.xaml b/src/BiliLite.UWP/Controls/Common/PieControl.xaml new file mode 100644 index 00000000..559f7444 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Common/PieControl.xaml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/Common/PieControl.xaml.cs b/src/BiliLite.UWP/Controls/Common/PieControl.xaml.cs new file mode 100644 index 00000000..45c21e90 --- /dev/null +++ b/src/BiliLite.UWP/Controls/Common/PieControl.xaml.cs @@ -0,0 +1,162 @@ +using System; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media.Animation; +using BiliLite.ViewModels.Common; + +//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 + +namespace BiliLite.Controls.Common +{ + public sealed partial class PieControl : UserControl + { + private readonly PieControlViewModel m_viewModel; + + public PieControl() + { + m_viewModel = new PieControlViewModel(); + this.InitializeComponent(); + } + + public event EventHandler FirstBtnTapped; + + public event EventHandler SecondBtnTapped; + + public event EventHandler ThirdBtnTapped; + + public IconElement FirstBtnIcon + { + get => (IconElement)GetValue(FirstBtnIconProperty); + set => SetValue(FirstBtnIconProperty, value); + } + + public static readonly DependencyProperty FirstBtnIconProperty = + DependencyProperty.Register(nameof(IconElement), + typeof(FrameworkElement), + typeof(PieControl), + new PropertyMetadata(null)); + + public IconElement SecondBtnIcon + { + get => (IconElement)GetValue(SecondBtnIconProperty); + set => SetValue(SecondBtnIconProperty, value); + } + + public static readonly DependencyProperty SecondBtnIconProperty = + DependencyProperty.Register(nameof(IconElement), + typeof(FrameworkElement), + typeof(PieControl), + new PropertyMetadata(null)); + + public IconElement ThirdBtnIcon + { + get => (IconElement)GetValue(ThirdBtnIconProperty); + set => SetValue(ThirdBtnIconProperty, value); + } + + public static readonly DependencyProperty ThirdBtnIconProperty = + DependencyProperty.Register(nameof(IconElement), + typeof(FrameworkElement), + typeof(PieControl), + new PropertyMetadata(null)); + + public string FirstBtnToolTip + { + get => (string)GetValue(FirstBtnToolTipProperty); + set => SetValue(FirstBtnToolTipProperty, value); + } + + public static readonly DependencyProperty FirstBtnToolTipProperty = + DependencyProperty.Register(nameof(FirstBtnToolTip), + typeof(string), + typeof(PieControl), + new PropertyMetadata(null)); + + public string SecondBtnToolTip + { + get => (string)GetValue(SecondBtnToolTipProperty); + set => SetValue(SecondBtnToolTipProperty, value); + } + + public static readonly DependencyProperty SecondBtnToolTipProperty = + DependencyProperty.Register(nameof(SecondBtnToolTip), + typeof(string), + typeof(PieControl), + new PropertyMetadata(null)); + + public string ThirdBtnToolTip + { + get => (string)GetValue(ThirdBtnToolTipProperty); + set => SetValue(ThirdBtnToolTipProperty, value); + } + + public static readonly DependencyProperty ThirdBtnToolTipProperty = + DependencyProperty.Register(nameof(ThirdBtnToolTip), + typeof(string), + typeof(PieControl), + new PropertyMetadata(null)); + + private async void BtnClosePie_Click(object sender, RoutedEventArgs args) + { + await ClosePie(); + } + + private async void BtnExtentPie_OnTapped(object sender, TappedRoutedEventArgs e) + { + await ExtentPie(); + } + + private async Task ClosePie() + { + m_viewModel.ExtendVisibility = true; + var storyboard = (Storyboard)this.Resources["ClosePieStory"]; + //storyboard.Begin(); + var tcs = new TaskCompletionSource(); + + EventHandler completeAction = (s, e) => + { + tcs.SetResult(true); + }; + storyboard.Completed += completeAction; + storyboard.Begin(); + await tcs.Task; + m_viewModel.ExtendVisibility = false; + storyboard.Completed -= completeAction; + } + + private async Task ExtentPie() + { + m_viewModel.ExtendVisibility = true; + var storyboard = (Storyboard)this.Resources["ExtentPieStory"]; + //storyboard.Begin(); + var tcs = new TaskCompletionSource(); + + EventHandler completeAction = (s, e) => + { + tcs.SetResult(true); + }; + + storyboard.Completed += completeAction; + storyboard.Begin(); + await tcs.Task; + storyboard.Completed -= completeAction; + } + + private void ThirdBtn_OnTapped(object sender, TappedRoutedEventArgs e) + { + ThirdBtnTapped?.Invoke(this, e); + } + + private void FirstBtn_OnTapped(object sender, TappedRoutedEventArgs e) + { + FirstBtnTapped?.Invoke(this, e); + } + + private void SecondBtn_OnTapped(object sender, TappedRoutedEventArgs e) + { + SecondBtnTapped?.Invoke(this, e); + } + } +} diff --git a/src/BiliLite.UWP/Controls/VideoListView.xaml b/src/BiliLite.UWP/Controls/VideoListView.xaml index 5c2b20d8..e7012f07 100644 --- a/src/BiliLite.UWP/Controls/VideoListView.xaml +++ b/src/BiliLite.UWP/Controls/VideoListView.xaml @@ -8,6 +8,8 @@ xmlns:muxc="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:video="using:BiliLite.ViewModels.Video" xmlns:video1="using:BiliLite.Models.Common.Video" + xmlns:common="using:BiliLite.Controls.Common" + xmlns:font="using:FontAwesome5" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> @@ -24,61 +26,81 @@ - + - - - + + - - - - - + + + + - - - + + - - - - - - + + + + + - + - - - - - - - - - + + + + + + + + - 加载更多 - - - - - - - - + 加载更多 + + + + + + + + + + + + + + + + + + + + diff --git a/src/BiliLite.UWP/Controls/VideoListView.xaml.cs b/src/BiliLite.UWP/Controls/VideoListView.xaml.cs index fad70cff..30f01a31 100644 --- a/src/BiliLite.UWP/Controls/VideoListView.xaml.cs +++ b/src/BiliLite.UWP/Controls/VideoListView.xaml.cs @@ -11,6 +11,7 @@ using BiliLite.Models.Common.Video; using BiliLite.Services.Biz; using BiliLite.ViewModels.Video; +using Microsoft.Toolkit.Uwp.UI.Controls; //https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板 @@ -100,8 +101,47 @@ private void ListView_OnSelectionChanged(object sender, SelectionChangedEventArg private void ScrollToItem(VideoListItem item) { - //TODO: 实现滚动到指定item - //SectionListView.ScrollIntoView(); + var offset = GetItemOffsetHeight(item); + VideoListScrollViewer.ScrollToVerticalOffset(offset); + } + + private double GetItemOffsetHeight(VideoListItem item) + { + var offset = 0d; + var expanders = this.FindChildrenByType().ToList(); + if (!expanders.Any()) return 0; + var expanderHeaderHeight = (expanders.First().Header as FrameworkElement).ActualHeight; + var videoListItemGridHeight = 87; + foreach (var section in m_viewModel.Sections) + { + if (section.SelectedItem != item && !section.Selected) + { + offset += expanderHeaderHeight; + } + else if (section.SelectedItem != item && section.Selected) + { + offset += expanderHeaderHeight; + + offset += (section.Items.Count * videoListItemGridHeight); + } + else if (section.SelectedItem == item) + { + section.Selected = true; + var expander = expanders.FirstOrDefault(x => x.DataContext == section); + expander.IsExpanded = true; + + foreach (var videoItem in section.Items) + { + offset += videoListItemGridHeight; + if (videoItem == item) + { + return offset; + } + } + } + } + + return offset; } private void UIElement_OnContextRequested(UIElement sender, ContextRequestedEventArgs args) @@ -128,5 +168,20 @@ private async void BtnLoadMore_OnTapped(object sender, TappedRoutedEventArgs e) if (!(btnLoadMore.DataContext is VideoListSectionViewModel section)) return; await m_mediaListService.LoadMoreMediaList(section); } + + private void OnScrollToCurrentBtnTapped(object sender, TappedRoutedEventArgs e) + { + ScrollToItem(CurrentItem()); + } + + private void OnUpToTopBtnTapped(object sender, TappedRoutedEventArgs e) + { + VideoListScrollViewer.ScrollToVerticalOffset(0); + } + + private void OnDownToBottomBtnTapped(object sender, TappedRoutedEventArgs e) + { + VideoListScrollViewer.ScrollToVerticalOffset(SectionListView.ActualHeight); + } } } diff --git a/src/BiliLite.UWP/Extensions/ControlsExtensions.cs b/src/BiliLite.UWP/Extensions/ControlsExtensions.cs index 34f7629d..34f294a5 100644 --- a/src/BiliLite.UWP/Extensions/ControlsExtensions.cs +++ b/src/BiliLite.UWP/Extensions/ControlsExtensions.cs @@ -1,6 +1,9 @@ using BiliLite.Controls; using BiliLite.Dialogs; using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml; namespace BiliLite.Extensions { @@ -15,5 +18,45 @@ public static IServiceCollection AddControls(this IServiceCollection services) services.AddTransient(); return services; } + + public static T FindFirstChildByType(this DependencyObject parent) where T : DependencyObject + { + if (parent == null) return null; + + var childrenCount = VisualTreeHelper.GetChildrenCount(parent); + for (var i = 0; i < childrenCount; i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + if (child is T typedChild) + { + return typedChild; + } + + var subChild = FindFirstChildByType(child); + if (subChild != null) return subChild; + } + + return null; + } + + public static IEnumerable FindChildrenByType(this DependencyObject parent) where T : DependencyObject + { + if (parent == null) yield break; + + var childrenCount = VisualTreeHelper.GetChildrenCount(parent); + for (var i = 0; i < childrenCount; i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + if (child is T typedChild) + { + yield return typedChild; + } + + foreach (var descendant in FindChildrenByType(child)) + { + yield return descendant; + } + } + } } } diff --git a/src/BiliLite.UWP/Themes/Dark.xaml b/src/BiliLite.UWP/Themes/Dark.xaml index 67d4b91d..efc17163 100644 --- a/src/BiliLite.UWP/Themes/Dark.xaml +++ b/src/BiliLite.UWP/Themes/Dark.xaml @@ -17,6 +17,8 @@ #989898 Gray #805C5C5C + #2d2d2d + #FF808080 #FF282828 diff --git a/src/BiliLite.UWP/Themes/Light.xaml b/src/BiliLite.UWP/Themes/Light.xaml index 81b634f7..6886ece8 100644 --- a/src/BiliLite.UWP/Themes/Light.xaml +++ b/src/BiliLite.UWP/Themes/Light.xaml @@ -17,6 +17,8 @@ #989898 Gray #805C5C5C + #f8f8f8 + #FF808080 #FFF9F9F9 diff --git a/src/BiliLite.UWP/ViewModels/Common/PieControlViewModel.cs b/src/BiliLite.UWP/ViewModels/Common/PieControlViewModel.cs new file mode 100644 index 00000000..81066a73 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Common/PieControlViewModel.cs @@ -0,0 +1,20 @@ +namespace BiliLite.ViewModels.Common +{ + + public class PieControlViewModel : BaseViewModel + { + public double LittleBtnWidth => 50; + + public double LittleBtnHeight => 50; + + public double PieExtendGridLittleWidth = 25; + + public double PieExtendGridLittleHeight = 50; + + public double PieExtendGridExtendWidth = 80; + + public double PieExtendGridExtendHeight = 160; + + public bool ExtendVisibility { get; set; } = false; + } +}