diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index 3e49bb439..35f307fe7 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -262,16 +262,35 @@ + + + + + + + + MarkdownViewerPage.xaml + + + + + + + + + + + @@ -785,7 +804,7 @@ - + @@ -940,7 +959,7 @@ - + diff --git a/src/BiliLite.UWP/Controls/DataTemplateSelectors/SearchDataTemplateSelector.cs b/src/BiliLite.UWP/Controls/DataTemplateSelectors/SearchDataTemplateSelector.cs new file mode 100644 index 000000000..0c5f4a49f --- /dev/null +++ b/src/BiliLite.UWP/Controls/DataTemplateSelectors/SearchDataTemplateSelector.cs @@ -0,0 +1,44 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using BiliLite.Models.Common; +using BiliLite.ViewModels.Search; + +namespace BiliLite.Controls.DataTemplateSelectors +{ + public class SearchDataTemplateSelector : DataTemplateSelector + { + public DataTemplate VideoTemplate { get; set; } + public DataTemplate AnimeTemplate { get; set; } + public DataTemplate TestTemplate { get; set; } + public DataTemplate LiveRoomTemplate { get; set; } + public DataTemplate UserTemplate { get; set; } + public DataTemplate ArticTemplate { get; set; } + public DataTemplate TopicTemplate { get; set; } + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + var data = item as ISearchPivotViewModel; + switch (data.SearchType) + { + case SearchType.Video: + return VideoTemplate; + case SearchType.Anime: + case SearchType.Movie: + return AnimeTemplate; + case SearchType.User: + return UserTemplate; + case SearchType.Live: + return LiveRoomTemplate; + case SearchType.Article: + return ArticTemplate; + case SearchType.Topic: + return TopicTemplate; + case SearchType.Anchor: + return TestTemplate; + default: + return TestTemplate; + } + + + } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs b/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs index 13af63e53..1fd07da4e 100644 --- a/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs +++ b/src/BiliLite.UWP/Extensions/StringHttpExtensions.cs @@ -102,7 +102,7 @@ public static async Task GetHttpResultsWithWebCookie(this string ur { foreach (var kvp in extraCookies.ToList()) { - cookies.Add(kvp.Key, kvp.Value); + cookies[kvp.Key] = kvp.Value; } } diff --git a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs index 8cd58aa53..9447e40cf 100644 --- a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs +++ b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs @@ -5,6 +5,7 @@ using BiliLite.ViewModels.Home; using BiliLite.ViewModels.Live; using BiliLite.ViewModels.Rank; +using BiliLite.ViewModels.Search; using BiliLite.ViewModels.Settings; using BiliLite.ViewModels.User; using BiliLite.ViewModels.User.SendDynamic; @@ -53,6 +54,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 5619ef65e..3030c7f0c 100644 --- a/src/BiliLite.UWP/Models/Common/Enumerates.cs +++ b/src/BiliLite.UWP/Models/Common/Enumerates.cs @@ -525,4 +525,40 @@ public enum FilterContentType User, Desc, } + + public enum SearchType + { + /// + /// 视频 + /// + Video = 0, + /// + /// 番剧 + /// + Anime = 1, + /// + /// 直播 + /// + Live = 2, + /// + /// 主播 + /// + Anchor = 3, + /// + /// 用户 + /// + User = 4, + /// + /// 影视 + /// + Movie = 5, + /// + /// 专栏 + /// + Article = 6, + /// + /// 话题 + /// + Topic = 7 + } } \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchAnimeItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchAnimeItem.cs new file mode 100644 index 000000000..7cb11725a --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchAnimeItem.cs @@ -0,0 +1,42 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchAnimeItem + { + public string type { get; set; } + public string season_id { get; set; } + public string media_id { get; set; } + private string _title; + + public string title + { + get { return _title; } + set + { + + _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); + } + } + public string areas { get; set; } + public string cv { get; set; } + public string styles { get; set; } + public string desc { get; set; } + public long pubtime { get; set; } + public string season_type_name { get; set; } + + private string _pic; + public string cover + { + get { return _pic; } + set { _pic = value; } + } + + public string angle_title { get; set; } + public bool showBadge + { + get + { + return !string.IsNullOrEmpty(angle_title); + } + } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchArea.cs b/src/BiliLite.UWP/Models/Common/Search/SearchArea.cs new file mode 100644 index 000000000..346ce3f45 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchArea.cs @@ -0,0 +1,13 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchArea + { + public SearchArea(string name, string area) + { + this.name = name; + this.area = area; + } + public string name { get; set; } + public string area { get; set; } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchArticleItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchArticleItem.cs new file mode 100644 index 000000000..572c081d4 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchArticleItem.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; + +namespace BiliLite.Models.Common.Search +{ + public class SearchArticleItem + { + + public string mid { get; set; } + + private string _title; + + public string title + { + get { return _title; } + set + { + _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); + } + } + public string category_name { get; set; } + public string type { get; set; } + public string desc { get; set; } + public long like { get; set; } + public long view { get; set; } + public long reply { get; set; } + public string id { get; set; } + public List image_urls { get; set; } + public string cover + { + get + { + if (image_urls != null && image_urls.Count != 0) + { + return "https:" + image_urls[0]; + } + return null; + } + } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchFilterItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchFilterItem.cs new file mode 100644 index 000000000..fca676d54 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchFilterItem.cs @@ -0,0 +1,13 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchFilterItem + { + public SearchFilterItem(string name, string value) + { + this.name = name; + this.value = value; + } + public string name { get; set; } + public string value { get; set; } + } +} diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchLiveRoomItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchLiveRoomItem.cs new file mode 100644 index 000000000..cbb55f4ef --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchLiveRoomItem.cs @@ -0,0 +1,45 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchLiveRoomItem + { + + public string roomid { get; set; } + + private string _title; + + public string title + { + get { return _title; } + set + { + + _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); + } + } + public string uname { get; set; } + public string tags { get; set; } + public string cate_name { get; set; } + public int online { get; set; } + + + private string _user_cover; + public string user_cover + { + get { return _user_cover; } + set { _user_cover = "https:" + value; } + } + private string _uface; + public string uface + { + get { return _uface; } + set { _uface = "https:" + value; } + } + private string _cover; + public string cover + { + get { return _cover; } + set { _cover = "https:" + value; } + } + + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchParameter.cs b/src/BiliLite.UWP/Models/Common/Search/SearchParameter.cs new file mode 100644 index 000000000..ddc6eff21 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchParameter.cs @@ -0,0 +1,9 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchParameter + { + public string Keyword { get; set; } + + public SearchType SearchType { get; set; } = SearchType.Video; + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchTopicItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchTopicItem.cs new file mode 100644 index 000000000..65ced9217 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchTopicItem.cs @@ -0,0 +1,42 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchTopicItem + { + public string arcurl { get; set; } + + private string _title; + + public string title + { + get { return _title; } + set + { + _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); + } + } + + private string _description; + + public string description + { + get { return _description; } + set + { + _description = value.Replace("", "").Replace("", ""); + } + } + + + public long pubdate { get; set; } + + + private string _pic; + public string cover + { + get { return _pic; } + set { _pic = "https:" + value; } + } + + + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchUserItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchUserItem.cs new file mode 100644 index 000000000..7149e4662 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchUserItem.cs @@ -0,0 +1,58 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchUserItem + { + public string mid { get; set; } + public string uname { get; set; } + private string _pic; + public string upic + { + get { return _pic; } + set { _pic = "https:" + value; } + } + + public int level { get; set; } + public int videos { get; set; } + public int fans { get; set; } + public int is_upuser { get; set; } + public string lv + { + get + { + return $"ms-appx:///Assets/Icon/lv{level}.png"; + } + } + public SearchUserOfficialVerifyItem official_verify { get; set; } + public string Verify + { + get + { + if (official_verify == null) + { + return ""; + } + switch (official_verify.type) + { + case 0: + return Constants.App.VERIFY_PERSONAL_IMAGE; + case 1: + return Constants.App.VERIFY_OGANIZATION_IMAGE; + default: + return Constants.App.TRANSPARENT_IMAGE; + } + } + } + public string usign { get; set; } + public string sign + { + get + { + if (official_verify != null && !string.IsNullOrEmpty(official_verify.desc)) + { + return official_verify.desc; + } + return usign; + } + } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchUserOfficialVerifyItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchUserOfficialVerifyItem.cs new file mode 100644 index 000000000..01887fb76 --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchUserOfficialVerifyItem.cs @@ -0,0 +1,8 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchUserOfficialVerifyItem + { + public string desc { get; set; } + public int type { get; set; } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Models/Common/Search/SearchVideoItem.cs b/src/BiliLite.UWP/Models/Common/Search/SearchVideoItem.cs new file mode 100644 index 000000000..366f8431b --- /dev/null +++ b/src/BiliLite.UWP/Models/Common/Search/SearchVideoItem.cs @@ -0,0 +1,36 @@ +namespace BiliLite.Models.Common.Search +{ + public class SearchVideoItem + { + public string type { get; set; } + public string typename { get; set; } + public string author { get; set; } + public string id { get; set; } + public string aid { get; set; } + private string _title; + + public string title + { + get { return _title; } + set + { + + _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); + } + } + public string tag { get; set; } + public int play { get; set; } + public int video_review { get; set; } + public int review { get; set; } + public int favorites { get; set; } + public string duration { get; set; } + private string _pic; + public string pic + { + get { return _pic; } + set { _pic = "https:" + value; } + } + + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/src/BiliLite.UWP/Modules/SearchVM.cs b/src/BiliLite.UWP/Modules/SearchVM.cs deleted file mode 100644 index 085e58a35..000000000 --- a/src/BiliLite.UWP/Modules/SearchVM.cs +++ /dev/null @@ -1,1073 +0,0 @@ -using BiliLite.Models; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading.Tasks; -using System.Windows.Input; -using BiliLite.Extensions; -using BiliLite.Models.Common; -using BiliLite.Models.Exceptions; -using Newtonsoft.Json; -using BiliLite.Pages; -using BiliLite.Models.Requests.Api; -using BiliLite.Services; -using Microsoft.Extensions.DependencyInjection; - -namespace BiliLite.Modules -{ - public class ISearchVM : IModules - { - public SearchType SearchType { get; set; } - public SearchAPI searchAPI; - public ISearchVM() - { - searchAPI = new SearchAPI(); - RefreshCommand = new RelayCommand(Refresh); - LoadMoreCommand = new RelayCommand(LoadMore); - } - public string Title { get; set; } - - private string _keyword; - public string Keyword - { - get { return _keyword; } - set { _keyword = value; } - } - public ICommand LoadMoreCommand { get; private set; } - public ICommand RefreshCommand { get; private set; } - - public string Area { get; set; } = ""; - - public int Page { get; set; } = 1; - private bool _loading = false; - - public bool Loading - { - get { return _loading; } - set { _loading = value; DoPropertyChanged("Loading"); } - } - private bool _Nothing = false; - public bool Nothing - { - get { return _Nothing; } - set { _Nothing = value; DoPropertyChanged("Nothing"); } - } - - private bool _ShowLoadMore = false; - public bool ShowLoadMore - { - get { return _ShowLoadMore; } - set { _ShowLoadMore = value; DoPropertyChanged("ShowLoadMore"); } - } - - public async virtual void Refresh() - { - HasData = false; - Page = 1; - await LoadData(); - } - public async virtual void LoadMore() - { - await LoadData(); - } - public bool HasData { get; set; } = false; - - public virtual Task LoadData() - { - throw new NotImplementedException(); - } - } - - public class SearchVM : IModules - { - /// - /// 搜索请求需要cookie - /// - public static string cookie = ""; - public SearchVM() - { - Area = Areas[0]; - SearchItems = new ObservableCollection() { - new SearchVideoVM() - { - Title="视频", - SearchType= SearchType.Video, - Area= Area.area - }, - new SearchAnimeVM() - { - Title="番剧", - SearchType= SearchType.Anime, - Area= Area.area - }, - new SearchLiveRoomVM() - { - Title="直播", - SearchType= SearchType.Live, - Area= Area.area - }, - //new SearchLiveRoomVM() - //{ - // Title="主播", - // SearchType= SearchType.Anchor - //}, - new SearchUserVM() - { - Title="用户", - SearchType= SearchType.User, - Area= Area.area - }, - new SearchAnimeVM() - { - Title="影视", - SearchType= SearchType.Movie, - Area= Area.area - }, - new SearchArticleVM() - { - Title="专栏", - SearchType= SearchType.Article, - Area= Area.area - }, - new SearchTopicVM() - { - Title="话题", - SearchType= SearchType.Topic, - Area= Area.area - } - }; - SelectItem = SearchItems[0]; - - } - private ObservableCollection _items; - public ObservableCollection SearchItems - { - get { return _items; } - set { _items = value; DoPropertyChanged("SearchItems"); } - } - - public List Areas { get; set; } = new List() - { - new SearchArea("默认地区",""), - new SearchArea("大陆地区","cn"), - new SearchArea("香港地区","hk"), - new SearchArea("台湾地区","tw"), - }; - public SearchArea Area { get; set; } - - private ISearchVM _SelectItem; - public ISearchVM SelectItem - { - get { return _SelectItem; } - set { _SelectItem = value; } - } - - private ObservableCollection m_suggestSearchContents; - - public ObservableCollection SuggestSearchContents - { - get => m_suggestSearchContents; - set - { - m_suggestSearchContents = value; - DoPropertyChanged("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"), - new SearchFilterItem("最新发布","pubdate"), - new SearchFilterItem("最多弹幕","dm"), - new SearchFilterItem("最多收藏","stow") - }; - SelectOrder = OrderFilters[0]; - DurationFilters = new List() { - new SearchFilterItem("全部时长",""), - new SearchFilterItem("10分钟以下","1"), - new SearchFilterItem("10-30分钟","2"), - new SearchFilterItem("30-60分钟","3"), - new SearchFilterItem("60分钟以上","4") - }; - SelectDuration = DurationFilters[0]; - RegionFilters = new List() { - new SearchFilterItem("全部分区","0"), - }; - foreach (var item in AppHelper.Regions.Where(x => x.children != null && x.children.Count != 0)) - { - RegionFilters.Add(new SearchFilterItem(item.name, item.tid.ToString())); - } - SelectRegion = RegionFilters[0]; - } - public List OrderFilters { get; set; } - - private SearchFilterItem _SelectOrder; - public SearchFilterItem SelectOrder - { - get { return _SelectOrder; } - set { _SelectOrder = value; } - } - - public List DurationFilters { get; set; } - - private SearchFilterItem _SelectDuration; - public SearchFilterItem SelectDuration - { - get { return _SelectDuration; } - set { _SelectDuration = value; } - } - public List RegionFilters { get; set; } - private SearchFilterItem _SelectRegion; - public SearchFilterItem SelectRegion - { - get { return _SelectRegion; } - set { _SelectRegion = value; } - } - - - private ObservableCollection _videos; - public ObservableCollection Videos - { - get { return _videos; } - set { _videos = value; DoPropertyChanged("Videos"); } - } - - public async override Task LoadData() - { - try - { - if (Loading) - { - return; - } - ShowLoadMore = false; - Loading = true; - Nothing = false; - var results = await searchAPI.WebSearchVideo(Keyword, Page, SelectOrder.value, SelectDuration.value, SelectRegion.value, Area).Request(); - if (!results.status) - { - throw new CustomizedErrorException(results.message); - } - var data = await results.GetJson>(); - if (!data.success) - { - throw new CustomizedErrorException(data.message); - } - 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) - { - Nothing = true; - Videos?.Clear(); - return; - } - Videos = result; - } - else if (data.data != null) - { - foreach (var item in result) - { - Videos.Add(item); - } - } - if (Page < data.data["numPages"].ToInt32()) - { - ShowLoadMore = true; - Page++; - } - HasData = true; - - } - catch (Exception ex) - { - if (ex is CustomizedErrorException customizedErrorException) - { - Notify.ShowMessageToast(ex.Message); - _logger.Error("搜索失败", ex); - } - - var handel = HandelError(ex); - Notify.ShowMessageToast(handel.message); - } - finally - { - Loading = false; - } - } - } - - public class SearchArticleVM : ISearchVM - { - public SearchArticleVM() - { - OrderFilters = new List() { - new SearchFilterItem("默认排序","totalrank"), - new SearchFilterItem("最多阅读","click"), - new SearchFilterItem("最新发布","pubdate"), - new SearchFilterItem("最多喜欢","attention"), - new SearchFilterItem("最多评论","scores") - }; - SelectOrder = OrderFilters[0]; - - RegionFilters = new List() { - new SearchFilterItem("全部分区","0"), - new SearchFilterItem("动画","2"), - new SearchFilterItem("游戏","1"), - new SearchFilterItem("影视","28"), - new SearchFilterItem("生活","3"), - new SearchFilterItem("兴趣","29"), - new SearchFilterItem("轻小说","16"), - new SearchFilterItem("科技","17"), - }; - - SelectRegion = RegionFilters[0]; - } - public List OrderFilters { get; set; } - - private SearchFilterItem _SelectOrder; - public SearchFilterItem SelectOrder - { - get { return _SelectOrder; } - set { _SelectOrder = value; } - } - - public List DurationFilters { get; set; } - - - public List RegionFilters { get; set; } - private SearchFilterItem _SelectRegion; - public SearchFilterItem SelectRegion - { - get { return _SelectRegion; } - set { _SelectRegion = value; } - } - - - private ObservableCollection _Articles; - public ObservableCollection Articles - { - get { return _Articles; } - set { _Articles = value; DoPropertyChanged("Articles"); } - } - - public async override Task LoadData() - { - try - { - if (Loading) - { - return; - } - ShowLoadMore = false; - Loading = true; - Nothing = false; - var results = await searchAPI.WebSearchArticle(Keyword, Page, SelectOrder.value, SelectRegion.value, Area).Request(); - if (results.status) - { - var data = await results.GetJson>(); - if (data.success) - { - var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); - if (Page == 1) - { - if (result == null || result.Count == 0) - { - Nothing = true; - Articles?.Clear(); - return; - } - Articles = result; - } - else - { - if (data.data != null) - { - foreach (var item in result) - { - Articles.Add(item); - } - } - } - if (Page < data.data["numPages"].ToInt32()) - { - ShowLoadMore = true; - Page++; - } - HasData = true; - } - else - { - Notify.ShowMessageToast(data.message); - } - } - else - { - Notify.ShowMessageToast(results.message); - } - } - catch (Exception ex) - { - var handel = HandelError(ex); - Notify.ShowMessageToast(handel.message); - } - finally - { - Loading = false; - } - } - - - } - public class SearchAnimeVM : ISearchVM - { - public SearchAnimeVM() - { - } - - private ObservableCollection _Animes; - public ObservableCollection Animes - { - get { return _Animes; } - set { _Animes = value; DoPropertyChanged("Animes"); } - } - - public async override Task LoadData() - { - try - { - if (Loading) - { - return; - } - ShowLoadMore = false; - Loading = true; - Nothing = false; - var api = searchAPI.WebSearchAnime(Keyword, Page, Area); - if (this.SearchType == SearchType.Movie) - { - api = searchAPI.WebSearchMovie(Keyword, Page, Area); - } - var results = await api.Request(); - if (results.status) - { - var data = await results.GetJson>(); - if (data.success) - { - - var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); - if (Page == 1) - { - if (result == null || result.Count == 0) - { - Nothing = true; - Animes?.Clear(); - return; - } - Animes = result; - } - else - { - if (data.data != null) - { - foreach (var item in result) - { - Animes.Add(item); - } - } - } - if (Page < data.data["numPages"].ToInt32()) - { - ShowLoadMore = true; - Page++; - } - HasData = true; - } - else - { - Notify.ShowMessageToast(data.message); - } - } - else - { - Notify.ShowMessageToast(results.message); - } - } - catch (Exception ex) - { - var handel = HandelError(ex); - Notify.ShowMessageToast(handel.message); - } - finally - { - Loading = false; - } - } - - - } - public class SearchUserVM : ISearchVM - { - public SearchUserVM() - { - OrderFilters = new List() { - new SearchFilterItem("默认排序","&order=&order_sort="), - new SearchFilterItem("粉丝数由高到低","&order=fans&order_sort=0"), - new SearchFilterItem("粉丝数由低到高","&order=fans&order_sort=1"), - new SearchFilterItem("LV等级由高到低","&order=level&order_sort=0"), - new SearchFilterItem("LV等级由低到高","&order=level&order_sort=1"), - }; - SelectOrder = OrderFilters[0]; - TypeFilters = new List() { - new SearchFilterItem("全部用户","&user_type=0"), - new SearchFilterItem("UP主","&user_type=1"), - new SearchFilterItem("普通用户","&user_type=2"), - new SearchFilterItem("认证用户","&user_type=3") - }; - SelectType = TypeFilters[0]; - - } - public List OrderFilters { get; set; } - - private SearchFilterItem _SelectOrder; - public SearchFilterItem SelectOrder - { - get { return _SelectOrder; } - set { _SelectOrder = value; } - } - - public List TypeFilters { get; set; } - - private SearchFilterItem _SelectType; - public SearchFilterItem SelectType - { - get { return _SelectType; } - set { _SelectType = value; } - } - - - private ObservableCollection _users; - public ObservableCollection Users - { - get { return _users; } - set { _users = value; DoPropertyChanged("Users"); } - } - - public async override Task LoadData() - { - try - { - if (Loading) - { - return; - } - ShowLoadMore = false; - Loading = true; - Nothing = false; - var results = await searchAPI.WebSearchUser(Keyword, Page, SelectOrder.value, SelectType.value, Area).Request(); - if (results.status) - { - var data = await results.GetJson>(); - if (data.success) - { - var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); - if (Page == 1) - { - if (result == null || result.Count == 0) - { - Nothing = true; - Users?.Clear(); - return; - } - Users = result; - } - else - { - if (data.data != null) - { - foreach (var item in result) - { - Users.Add(item); - } - } - } - if (Page < data.data["numPages"].ToInt32()) - { - ShowLoadMore = true; - Page++; - } - HasData = true; - } - else - { - Notify.ShowMessageToast(data.message); - } - } - else - { - Notify.ShowMessageToast(results.message); - } - } - catch (Exception ex) - { - var handel = HandelError(ex); - Notify.ShowMessageToast(handel.message); - } - finally - { - Loading = false; - } - } - - - } - public class SearchLiveRoomVM : ISearchVM - { - public SearchLiveRoomVM() - { - } - - private ObservableCollection _Rooms; - public ObservableCollection Rooms - { - get { return _Rooms; } - set { _Rooms = value; DoPropertyChanged("Rooms"); } - } - - public async override Task LoadData() - { - try - { - if (Loading) - { - return; - } - ShowLoadMore = false; - Loading = true; - Nothing = false; - - var results = await searchAPI.WebSearchLive(Keyword, Page, Area).Request(); - if (results.status) - { - var data = await results.GetJson>(); - if (data.success) - { - - var result = JsonConvert.DeserializeObject>(data.data["result"]["live_room"]?.ToString() ?? "[]"); - if (Page == 1) - { - if (result == null || result.Count == 0) - { - Nothing = true; - Rooms?.Clear(); - return; - } - Rooms = result; - } - else - { - if (data.data != null) - { - foreach (var item in result) - { - Rooms.Add(item); - } - } - } - if (Page < data.data["pageinfo"]["live_room"]["numPages"].ToInt32()) - { - ShowLoadMore = true; - Page++; - } - HasData = true; - } - else - { - Notify.ShowMessageToast(data.message); - } - } - else - { - Notify.ShowMessageToast(results.message); - } - } - catch (Exception ex) - { - var handel = HandelError(ex); - Notify.ShowMessageToast(handel.message); - } - finally - { - Loading = false; - } - } - - - } - public class SearchTopicVM : ISearchVM - { - public SearchTopicVM() - { - } - - private ObservableCollection _Topics; - public ObservableCollection Topics - { - get { return _Topics; } - set { _Topics = value; DoPropertyChanged("Topics"); } - } - - public async override Task LoadData() - { - try - { - if (Loading) - { - return; - } - ShowLoadMore = false; - Loading = true; - Nothing = false; - var results = await searchAPI.WebSearchTopic(Keyword, Page, Area).Request(); - if (results.status) - { - var data = await results.GetJson>(); - if (data.success) - { - - var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); - if (Page == 1) - { - if (result == null || result.Count == 0) - { - Nothing = true; - Topics?.Clear(); - return; - } - Topics = result; - } - else - { - if (data.data != null) - { - foreach (var item in result) - { - Topics.Add(item); - } - } - } - if (Page < data.data["numPages"].ToInt32()) - { - ShowLoadMore = true; - Page++; - } - HasData = true; - } - else - { - Notify.ShowMessageToast(data.message); - } - } - else - { - Notify.ShowMessageToast(results.message); - } - } - catch (Exception ex) - { - var handel = HandelError(ex); - Notify.ShowMessageToast(handel.message); - } - finally - { - Loading = false; - } - } - - - } - - public class SearchFilterItem - { - public SearchFilterItem(string name, string value) - { - this.name = name; - this.value = value; - } - public string name { get; set; } - public string value { get; set; } - } - - public class SearchArea - { - public SearchArea(string name, string area) - { - this.name = name; - this.area = area; - } - public string name { get; set; } - public string area { get; set; } - } - public class SearchVideoItem - { - public string type { get; set; } - public string typename { get; set; } - public string author { get; set; } - public string id { get; set; } - public string aid { get; set; } - private string _title; - - public string title - { - get { return _title; } - set - { - - _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); - } - } - public string tag { get; set; } - public int play { get; set; } - public int video_review { get; set; } - public int review { get; set; } - public int favorites { get; set; } - public string duration { get; set; } - private string _pic; - public string pic - { - get { return _pic; } - set { _pic = "https:" + value; } - } - - public string Description { get; set; } - } - public class SearchAnimeItem - { - public string type { get; set; } - public string season_id { get; set; } - public string media_id { get; set; } - private string _title; - - public string title - { - get { return _title; } - set - { - - _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); - } - } - public string areas { get; set; } - public string cv { get; set; } - public string styles { get; set; } - public string desc { get; set; } - public long pubtime { get; set; } - public string season_type_name { get; set; } - - private string _pic; - public string cover - { - get { return _pic; } - set { _pic = value; } - } - - public string angle_title { get; set; } - public bool showBadge - { - get - { - return !string.IsNullOrEmpty(angle_title); - } - } - } - - public class SearchUserItem - { - public string mid { get; set; } - public string uname { get; set; } - private string _pic; - public string upic - { - get { return _pic; } - set { _pic = "https:" + value; } - } - - public int level { get; set; } - public int videos { get; set; } - public int fans { get; set; } - public int is_upuser { get; set; } - public string lv - { - get - { - return $"ms-appx:///Assets/Icon/lv{level}.png"; - } - } - public SearchUserOfficialVerifyItem official_verify { get; set; } - public string Verify - { - get - { - if (official_verify == null) - { - return ""; - } - switch (official_verify.type) - { - case 0: - return Constants.App.VERIFY_PERSONAL_IMAGE; - case 1: - return Constants.App.VERIFY_OGANIZATION_IMAGE; - default: - return Constants.App.TRANSPARENT_IMAGE; - } - } - } - public string usign { get; set; } - public string sign - { - get - { - if (official_verify != null && !string.IsNullOrEmpty(official_verify.desc)) - { - return official_verify.desc; - } - return usign; - } - } - } - public class SearchLiveRoomItem - { - - public string roomid { get; set; } - - private string _title; - - public string title - { - get { return _title; } - set - { - - _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); - } - } - public string uname { get; set; } - public string tags { get; set; } - public string cate_name { get; set; } - public int online { get; set; } - - - private string _user_cover; - public string user_cover - { - get { return _user_cover; } - set { _user_cover = "https:" + value; } - } - private string _uface; - public string uface - { - get { return _uface; } - set { _uface = "https:" + value; } - } - private string _cover; - public string cover - { - get { return _cover; } - set { _cover = "https:" + value; } - } - - } - public class SearchUserOfficialVerifyItem - { - public string desc { get; set; } - public int type { get; set; } - } - public class SearchArticleItem - { - - public string mid { get; set; } - - private string _title; - - public string title - { - get { return _title; } - set - { - _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); - } - } - public string category_name { get; set; } - public string type { get; set; } - public string desc { get; set; } - public long like { get; set; } - public long view { get; set; } - public long reply { get; set; } - public string id { get; set; } - public List image_urls { get; set; } - public string cover - { - get - { - if (image_urls != null && image_urls.Count != 0) - { - return "https:" + image_urls[0]; - } - return null; - } - } - } - public class SearchTopicItem - { - public string arcurl { get; set; } - - private string _title; - - public string title - { - get { return _title; } - set - { - _title = System.Web.HttpUtility.HtmlDecode(value.Replace("", "").Replace("", "")); - } - } - - private string _description; - - public string description - { - get { return _description; } - set - { - _description = value.Replace("", "").Replace("", ""); - } - } - - - public long pubdate { get; set; } - - - private string _pic; - public string cover - { - get { return _pic; } - set { _pic = "https:" + value; } - } - - - } -} diff --git a/src/BiliLite.UWP/Pages/HomePage.xaml.cs b/src/BiliLite.UWP/Pages/HomePage.xaml.cs index 34068a7af..175b54ce9 100644 --- a/src/BiliLite.UWP/Pages/HomePage.xaml.cs +++ b/src/BiliLite.UWP/Pages/HomePage.xaml.cs @@ -8,6 +8,8 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; +using BiliLite.Models.Common.Search; +using BiliLite.Services.Biz; using BiliLite.ViewModels.Download; using BiliLite.ViewModels.Home; using Microsoft.Extensions.DependencyInjection; @@ -24,6 +26,8 @@ public sealed partial class HomePage : BasePage, IRefreshablePage, IScrollRecove private static readonly ILogger logger = GlobalLogger.FromCurrentType(); private readonly DownloadPageViewModel m_downloadPageViewModel; + + private readonly SearchService m_searchService; // private readonly CookieService m_cookieService; private readonly HomeViewModel m_viewModel; readonly Account account; @@ -36,6 +40,7 @@ public HomePage() m_viewModel = new HomeViewModel(); account = new Account(); m_downloadPageViewModel = App.ServiceProvider.GetRequiredService(); + m_searchService = App.ServiceProvider.GetRequiredService(); // m_cookieService = App.ServiceProvider.GetRequiredService(); this.DataContext = m_viewModel; } @@ -188,8 +193,8 @@ private async void SearchBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBo title = "搜索:" + args.QueryText, parameters = new SearchParameter() { - keyword = args.QueryText, - searchType = SearchType.Video + Keyword = args.QueryText, + SearchType = SearchType.Video } }); } @@ -332,7 +337,7 @@ private async void SearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTe var text = sender.Text; text = text.TrimEnd(); if (string.IsNullOrWhiteSpace(text)) return; - var suggestSearchContents = await new SearchService().GetSearchSuggestContents(text); + var suggestSearchContents = await m_searchService.GetSearchSuggestContents(text); if (m_viewModel.SuggestSearchContents == null) { m_viewModel.SuggestSearchContents = new System.Collections.ObjectModel.ObservableCollection(suggestSearchContents); diff --git a/src/BiliLite.UWP/Pages/NewPage.xaml.cs b/src/BiliLite.UWP/Pages/NewPage.xaml.cs index 52ced345d..229ebb3db 100644 --- a/src/BiliLite.UWP/Pages/NewPage.xaml.cs +++ b/src/BiliLite.UWP/Pages/NewPage.xaml.cs @@ -1,7 +1,6 @@ using BiliLite.Pages.Bangumi; using Microsoft.UI.Xaml.Controls; using System; -using System.IO; using Windows.Storage; using Windows.Storage.Pickers; using Windows.UI.Xaml; @@ -11,6 +10,7 @@ using BiliLite.Models.Common; using BiliLite.Services; using BiliLite.Extensions; +using BiliLite.Models.Common.Search; using NavigationView = Microsoft.UI.Xaml.Controls.NavigationView; // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板 @@ -100,8 +100,8 @@ private async void SearchBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBo title = "搜索:" + SearchBox.Text, parameters = new SearchParameter() { - keyword = SearchBox.Text, - searchType = SearchType.Video + Keyword = SearchBox.Text, + SearchType = SearchType.Video } }); } diff --git a/src/BiliLite.UWP/Pages/SearchPage.xaml b/src/BiliLite.UWP/Pages/SearchPage.xaml index 51ee5b10d..3567d82a2 100644 --- a/src/BiliLite.UWP/Pages/SearchPage.xaml +++ b/src/BiliLite.UWP/Pages/SearchPage.xaml @@ -2,114 +2,233 @@ x:Class="BiliLite.Pages.SearchPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:local="using:BiliLite.Pages" + xmlns:control="using:BiliLite.Controls" + xmlns:convert="using:BiliLite.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" xmlns:fa="using:FontAwesome5" - xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls" - xmlns:convert="using:BiliLite.Converters" + xmlns:local="using:BiliLite.Pages" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:modules="using:BiliLite.Modules" - xmlns:control="using:BiliLite.Controls" + xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls" + xmlns:dataTemplateSelectors="using:BiliLite.Controls.DataTemplateSelectors" + xmlns:viewModel="using:BiliLite.ViewModels.Search" + xmlns:model="using:BiliLite.Models.Common.Search" Background="Transparent" - Loaded="SearchPage_Loaded"> + SizeChanged="SearchPage_OnSizeChanged" + mc:Ignorable="d"> - - - - + + + + - + - + - - - + + + - - - + + + - + - + - - + + - - - + + + - - - UP: - 播放: 弹幕: + + + + UP: + + 播放: + 弹幕: - + 加载更多 - + - 什么都没有找到呢~ - - + + 什么都没有找到呢~ + + + - + - + - + - - + + - - - + + + - - - 类型: - 地区: - 风格: - 开播时间: + + + + 类型: + + 地区: + + 风格: + + 开播时间: @@ -117,62 +236,121 @@ - + 加载更多 - + - 什么都没有找到呢~ - - + + 什么都没有找到呢~ + + + - + - + - + - - + + - - + + - + - + - - + + - + - + - + - - - 稿件: 粉丝: - + + + + 稿件: + 粉丝: + @@ -181,250 +359,441 @@ - + 加载更多 - + - 什么都没有找到呢~ - - + + 什么都没有找到呢~ + + + - + - + - + - + - - - + + + - + - + - - + + - + - + - + - + - - + + - - 人气: + + + 人气: - + 加载更多 - + - 什么都没有找到呢~ - - + + 什么都没有找到呢~ + + + - + - + - + - - + + - - + + - + - + - - + + - + - - - 阅读: 评论: 喜欢: - 分区: + + + + 阅读: + 评论: + 喜欢: + + 分区: - + 加载更多 - + - 什么都没有找到呢~ - - + + 什么都没有找到呢~ + + + - + - + - + - + - - + + - + - - - - 时间: + + + + + 时间: - + 加载更多 - + - 什么都没有找到呢~ - - + + 什么都没有找到呢~ + + + 还没写好 - + - - - - - + + + + + + + + + + + - + - + + 默认地区 大陆地区 香港地区 台湾地区 - - - - - - - - - - - - - diff --git a/src/BiliLite.UWP/Pages/SearchPage.xaml.cs b/src/BiliLite.UWP/Pages/SearchPage.xaml.cs index 8a454819f..f78b00b7f 100644 --- a/src/BiliLite.UWP/Pages/SearchPage.xaml.cs +++ b/src/BiliLite.UWP/Pages/SearchPage.xaml.cs @@ -7,66 +7,39 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; +using BiliLite.Models.Common.Search; +using BiliLite.Services.Biz; +using BiliLite.ViewModels.Search; +using Microsoft.Extensions.DependencyInjection; +using System.Linq; +using Windows.UI.Xaml.Controls.Primitives; // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板 namespace BiliLite.Pages { - public enum SearchType - { - /// - /// 视频 - /// - Video = 0, - /// - /// 番剧 - /// - Anime = 1, - /// - /// 直播 - /// - Live = 2, - /// - /// 主播 - /// - Anchor = 3, - /// - /// 用户 - /// - User = 4, - /// - /// 影视 - /// - Movie = 5, - /// - /// 专栏 - /// - Article = 6, - /// - /// 话题 - /// - Topic = 7 - } - public class SearchParameter - { - public string keyword { get; set; } - public SearchType searchType { get; set; } = SearchType.Video; - } /// /// 可用于自身或导航至 Frame 内部的空白页。 /// public sealed partial class SearchPage : BasePage, IRefreshablePage { - SearchVM searchVM; + private readonly SearchService m_searchService; + private readonly SearchPageViewModel m_viewModel; + public SearchPage() { + NavigationCacheMode = NavigationCacheMode.Required; + m_searchService = App.ServiceProvider.GetRequiredService(); + m_viewModel = App.ServiceProvider.GetRequiredService(); + m_viewModel.Init(m_searchService.PivotIndexCache = 0, m_searchService.ComboIndexCache = 0); this.InitializeComponent(); - Title = "搜索"; - searchVM = new SearchVM(); } + protected override void OnNavigatedTo(NavigationEventArgs e) { + CompositionTarget.Rendered += CompositionTarget_Rendered; // 订阅页面加载后事件 base.OnNavigatedTo(e); SearchParameter par = new SearchParameter(); if (e.Parameter is SearchParameter) @@ -75,18 +48,22 @@ protected override void OnNavigatedTo(NavigationEventArgs e) } else { - par.keyword = e.Parameter.ToString(); + par.Keyword = e.Parameter.ToString(); } - par.keyword = par.keyword.TrimStart('@'); - txtKeyword.Text = par.keyword; - foreach (var item in searchVM.SearchItems) + par.Keyword = par.Keyword.TrimStart('@'); + txtKeyword.Text = par.Keyword; + foreach (var item in m_viewModel.SearchItems) { - item.Keyword = par.keyword; - item.Area = searchVM.Area.area; + item.Keyword = par.Keyword; + item.Area = m_viewModel.Area.area; } - pivot.SelectedIndex = (int)par.searchType; } - + private void CompositionTarget_Rendered(object sender, RenderedEventArgs e) + { + txtKeyword.Focus(FocusState.Keyboard); + Title = "搜索"; + CompositionTarget.Rendered -= CompositionTarget_Rendered; + } private async void txtKeyword_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) { var queryText = args.QueryText; @@ -101,14 +78,14 @@ private async void txtKeyword_QuerySubmitted(AutoSuggestBox sender, AutoSuggestB return; } queryText = queryText.TrimStart('@'); - foreach (var item in searchVM.SearchItems) + foreach (var item in m_viewModel.SearchItems) { item.Keyword = queryText; - item.Area = searchVM.Area.area; + item.Area = m_viewModel.Area.area; item.Page = 1; item.HasData = false; } - searchVM.SelectItem.Refresh(); + m_viewModel.SelectItem.Refresh(); ChangeTitle("搜索:" + queryText); } @@ -130,7 +107,8 @@ private async void pivot_SelectionChanged(object sender, SelectionChangedEventAr { if (pivot.SelectedItem != null) { - var item = pivot.SelectedItem as ISearchVM; + m_searchService.PivotIndexCache = pivot.SelectedIndex; + var item = pivot.SelectedItem as ISearchPivotViewModel; if (!item.HasData && !item.Loading) { await item.LoadData(); @@ -141,7 +119,7 @@ private async void pivot_SelectionChanged(object sender, SelectionChangedEventAr private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { - var data = (sender as ComboBox).DataContext as ISearchVM; + var data = (sender as ComboBox).DataContext as ISearchPivotViewModel; if (data.HasData && !data.Loading) { data.Refresh(); @@ -246,13 +224,14 @@ private void cbArea_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (cbArea.SelectedItem != null) { - foreach (var item in searchVM.SearchItems) + m_searchService.ComboIndexCache = cbArea.SelectedIndex; + foreach (var item in m_viewModel.SearchItems) { - item.Area = searchVM.Area.area; + item.Area = m_viewModel.Area.area; item.Page = 1; item.HasData = false; } - searchVM.SelectItem.Refresh(); + m_viewModel.SelectItem.Refresh(); } } @@ -262,62 +241,33 @@ private async void txtKeyword_TextChanged(AutoSuggestBox sender, AutoSuggestBoxT var text = sender.Text; text = text.TrimEnd(); if (string.IsNullOrWhiteSpace(text)) return; - var suggestSearchContents = await new SearchService().GetSearchSuggestContents(text); - if (searchVM.SuggestSearchContents == null) + var suggestSearchContents = await m_searchService.GetSearchSuggestContents(text); + if (m_viewModel.SuggestSearchContents == null) { - searchVM.SuggestSearchContents = new System.Collections.ObjectModel.ObservableCollection(suggestSearchContents); + m_viewModel.SuggestSearchContents = new System.Collections.ObjectModel.ObservableCollection(suggestSearchContents); } else { - searchVM.SuggestSearchContents.ReplaceRange(suggestSearchContents); + m_viewModel.SuggestSearchContents.ReplaceRange(suggestSearchContents); } } public async Task Refresh() { - if (!(pivot.SelectedItem is ISearchVM searchVm)) return; + if (!(pivot.SelectedItem is ISearchPivotViewModel searchVm)) return; searchVm.Refresh(); } - private void SearchPage_Loaded(object sender, RoutedEventArgs e) + private void UpdateSize() { - txtKeyword.Focus(FocusState.Keyboard); + m_viewModel.PageWidth = ActualWidth; + m_viewModel.PivotHeaderWidth = + pivot.FindChildrenByType().Select(x=>x.ActualWidth).Sum(); } - } - public class SearchDataTemplateSelector : DataTemplateSelector - { - public DataTemplate VideoTemplate { get; set; } - public DataTemplate AnimeTemplate { get; set; } - public DataTemplate TestTemplate { get; set; } - public DataTemplate LiveRoomTemplate { get; set; } - public DataTemplate UserTemplate { get; set; } - public DataTemplate ArticTemplate { get; set; } - public DataTemplate TopicTemplate { get; set; } - protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) - { - var data = item as ISearchVM; - switch (data.SearchType) - { - case SearchType.Video: - return VideoTemplate; - case SearchType.Anime: - case SearchType.Movie: - return AnimeTemplate; - case SearchType.User: - return UserTemplate; - case SearchType.Live: - return LiveRoomTemplate; - case SearchType.Article: - return ArticTemplate; - case SearchType.Topic: - return TopicTemplate; - case SearchType.Anchor: - return TestTemplate; - default: - return TestTemplate; - } - + private void SearchPage_OnSizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateSize(); } } } diff --git a/src/BiliLite.UWP/Services/SearchService.cs b/src/BiliLite.UWP/Services/Biz/SearchService.cs similarity index 80% rename from src/BiliLite.UWP/Services/SearchService.cs rename to src/BiliLite.UWP/Services/Biz/SearchService.cs index 67ad099d5..9b3c6d2c5 100644 --- a/src/BiliLite.UWP/Services/SearchService.cs +++ b/src/BiliLite.UWP/Services/Biz/SearchService.cs @@ -1,14 +1,18 @@ -using BiliLite.Extensions; -using BiliLite.Models.Requests.Api; -using BiliLite.Models.Responses; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using BiliLite.Extensions; +using BiliLite.Models.Requests.Api; +using BiliLite.Models.Responses; -namespace BiliLite.Services +namespace BiliLite.Services.Biz { public class SearchService { + public int PivotIndexCache { get; set; } + + public int ComboIndexCache { get; set; } + public async Task> GetSearchSuggestContents(string text) { if (string.IsNullOrWhiteSpace(text)) return null; diff --git a/src/BiliLite.UWP/Services/ContentFilterService.cs b/src/BiliLite.UWP/Services/ContentFilterService.cs index 1d0c009e7..6061e8a4e 100644 --- a/src/BiliLite.UWP/Services/ContentFilterService.cs +++ b/src/BiliLite.UWP/Services/ContentFilterService.cs @@ -3,8 +3,8 @@ using System.Text.RegularExpressions; using BiliLite.Models.Common; using BiliLite.Models.Common.Recommend; +using BiliLite.Models.Common.Search; using BiliLite.Models.Common.Settings; -using BiliLite.Modules; using BiliLite.ViewModels.UserDynamic; namespace BiliLite.Services diff --git a/src/BiliLite.UWP/Startup.cs b/src/BiliLite.UWP/Startup.cs index ce163e64c..1745f0fac 100644 --- a/src/BiliLite.UWP/Startup.cs +++ b/src/BiliLite.UWP/Startup.cs @@ -1,5 +1,6 @@ using BiliLite.Extensions; using BiliLite.Services; +using BiliLite.Services.Biz; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -28,6 +29,7 @@ public void ConfigureServices(HostBuilderContext context, IServiceCollection ser services.AddBizServices(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); } diff --git a/src/BiliLite.UWP/ViewModels/Search/BaseSearchPivotViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/BaseSearchPivotViewModel.cs new file mode 100644 index 000000000..2b37f30f2 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/BaseSearchPivotViewModel.cs @@ -0,0 +1,82 @@ +using System; +using System.Threading.Tasks; +using System.Windows.Input; +using BiliLite.Models.Common; +using BiliLite.Models.Requests.Api; +using BiliLite.Modules; +using BiliLite.ViewModels.Common; +using PropertyChanged; + +namespace BiliLite.ViewModels.Search +{ + public class BaseSearchPivotViewModel : BaseViewModel, ISearchPivotViewModel + { + #region Fields + + protected SearchAPI SearchApi; + + #endregion + + #region Constructors + + public BaseSearchPivotViewModel() + { + SearchApi = new SearchAPI(); + RefreshCommand = new RelayCommand(Refresh); + LoadMoreCommand = new RelayCommand(LoadMore); + } + + #endregion + + #region Properties + + public ICommand LoadMoreCommand { get; private set; } + + public ICommand RefreshCommand { get; private set; } + + [DoNotNotify] + public SearchType SearchType { get; set; } + + [DoNotNotify] + public string Title { get; set; } + + [DoNotNotify] + public string Keyword { get; set; } + + [DoNotNotify] + public string Area { get; set; } = ""; + + [DoNotNotify] + public int Page { get; set; } = 1; + + public bool Loading { get; set; } + + public bool Nothing { get; set; } + + public bool ShowLoadMore { get; set; } + + public bool HasData { get; set; } = false; + + #endregion + + #region Public Methods + + public virtual async void Refresh() + { + HasData = false; + Page = 1; + await LoadData(); + } + public virtual async void LoadMore() + { + await LoadData(); + } + + public virtual Task LoadData() + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/ISearchPivotViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/ISearchPivotViewModel.cs new file mode 100644 index 000000000..6335c2aab --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/ISearchPivotViewModel.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using System.Windows.Input; +using BiliLite.Models.Common; + +namespace BiliLite.ViewModels.Search +{ + public interface ISearchPivotViewModel + { + public ICommand LoadMoreCommand { get; } + + public ICommand RefreshCommand { get; } + + public SearchType SearchType { get; set; } + + public string Title { get; set; } + + public string Keyword { get; set; } + + public string Area { get; set; } + + public int Page { get; set; } + + public bool Loading { get; set; } + + public bool Nothing { get; set; } + + public bool ShowLoadMore { get; set; } + + public bool HasData { get; set; } + + public void Refresh(); + + public Task LoadData(); + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/SearchAnimeViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/SearchAnimeViewModel.cs new file mode 100644 index 000000000..ff278e180 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/SearchAnimeViewModel.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using BiliLite.Extensions; +using BiliLite.Models; +using BiliLite.Models.Common.Search; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace BiliLite.ViewModels.Search +{ + public class SearchAnimeViewModel : BaseSearchPivotViewModel + { + #region Properties + + public ObservableCollection Animes { get; set; } + + #endregion + + #region Public Methods + + public override async Task LoadData() + { + try + { + if (Loading) + { + return; + } + ShowLoadMore = false; + Loading = true; + Nothing = false; + var api = SearchApi.WebSearchAnime(Keyword, Page, Area); + if (this.SearchType == Models.Common.SearchType.Movie) + { + api = SearchApi.WebSearchMovie(Keyword, Page, Area); + } + var results = await api.Request(); + if (results.status) + { + var data = await results.GetJson>(); + if (data.success) + { + + var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); + if (Page == 1) + { + if (result == null || result.Count == 0) + { + Nothing = true; + Animes?.Clear(); + return; + } + Animes = result; + } + else + { + if (data.data != null) + { + foreach (var item in result) + { + Animes.Add(item); + } + } + } + if (Page < data.data["numPages"].ToInt32()) + { + ShowLoadMore = true; + Page++; + } + HasData = true; + } + else + { + Notify.ShowMessageToast(data.message); + } + } + else + { + Notify.ShowMessageToast(results.message); + } + } + catch (Exception ex) + { + var handel = HandelError(ex); + Notify.ShowMessageToast(handel.message); + } + finally + { + Loading = false; + } + } + + #endregion + + + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/SearchArticleViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/SearchArticleViewModel.cs new file mode 100644 index 000000000..0d2049a8e --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/SearchArticleViewModel.cs @@ -0,0 +1,124 @@ +using BiliLite.Models; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using BiliLite.Extensions; +using BiliLite.Models.Common.Search; +using PropertyChanged; + +namespace BiliLite.ViewModels.Search +{ + public class SearchArticleViewModel : BaseSearchPivotViewModel + { + public SearchArticleViewModel() + { + OrderFilters = new List() { + new SearchFilterItem("默认排序","totalrank"), + new SearchFilterItem("最多阅读","click"), + new SearchFilterItem("最新发布","pubdate"), + new SearchFilterItem("最多喜欢","attention"), + new SearchFilterItem("最多评论","scores") + }; + SelectOrder = OrderFilters[0]; + + RegionFilters = new List() { + new SearchFilterItem("全部分区","0"), + new SearchFilterItem("动画","2"), + new SearchFilterItem("游戏","1"), + new SearchFilterItem("影视","28"), + new SearchFilterItem("生活","3"), + new SearchFilterItem("兴趣","29"), + new SearchFilterItem("轻小说","16"), + new SearchFilterItem("科技","17"), + }; + + SelectRegion = RegionFilters[0]; + } + + [DoNotNotify] + public List OrderFilters { get; set; } + + [DoNotNotify] + public SearchFilterItem SelectOrder { get; set; } + + [DoNotNotify] + public List DurationFilters { get; set; } + + [DoNotNotify] + public List RegionFilters { get; set; } + + [DoNotNotify] + public SearchFilterItem SelectRegion { get; set; } + + public ObservableCollection Articles { get; set; } + + public override async Task LoadData() + { + try + { + if (Loading) + { + return; + } + ShowLoadMore = false; + Loading = true; + Nothing = false; + var results = await SearchApi.WebSearchArticle(Keyword, Page, SelectOrder.value, SelectRegion.value, Area).Request(); + if (results.status) + { + var data = await results.GetJson>(); + if (data.success) + { + var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); + if (Page == 1) + { + if (result == null || result.Count == 0) + { + Nothing = true; + Articles?.Clear(); + return; + } + Articles = result; + } + else + { + if (data.data != null) + { + foreach (var item in result) + { + Articles.Add(item); + } + } + } + if (Page < data.data["numPages"].ToInt32()) + { + ShowLoadMore = true; + Page++; + } + HasData = true; + } + else + { + Notify.ShowMessageToast(data.message); + } + } + else + { + Notify.ShowMessageToast(results.message); + } + } + catch (Exception ex) + { + var handel = HandelError(ex); + Notify.ShowMessageToast(handel.message); + } + finally + { + Loading = false; + } + } + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/SearchLiveRoomViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/SearchLiveRoomViewModel.cs new file mode 100644 index 000000000..eacc7f51c --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/SearchLiveRoomViewModel.cs @@ -0,0 +1,92 @@ +using BiliLite.Models; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using BiliLite.Extensions; +using BiliLite.Models.Common.Search; + +namespace BiliLite.ViewModels.Search +{ + public class SearchLiveRoomViewModel : BaseSearchPivotViewModel + { + #region Properties + + public ObservableCollection Rooms { get; set; } + + #endregion + + #region Public Methods + + public override async Task LoadData() + { + try + { + if (Loading) + { + return; + } + ShowLoadMore = false; + Loading = true; + Nothing = false; + + var results = await SearchApi.WebSearchLive(Keyword, Page, Area).Request(); + if (results.status) + { + var data = await results.GetJson>(); + if (data.success) + { + + var result = JsonConvert.DeserializeObject>(data.data["result"]["live_room"]?.ToString() ?? "[]"); + if (Page == 1) + { + if (result == null || result.Count == 0) + { + Nothing = true; + Rooms?.Clear(); + return; + } + Rooms = result; + } + else + { + if (data.data != null) + { + foreach (var item in result) + { + Rooms.Add(item); + } + } + } + if (Page < data.data["pageinfo"]["live_room"]["numPages"].ToInt32()) + { + ShowLoadMore = true; + Page++; + } + HasData = true; + } + else + { + Notify.ShowMessageToast(data.message); + } + } + else + { + Notify.ShowMessageToast(results.message); + } + } + catch (Exception ex) + { + var handel = HandelError(ex); + Notify.ShowMessageToast(handel.message); + } + finally + { + Loading = false; + } + } + + #endregion + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/SearchPageViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/SearchPageViewModel.cs new file mode 100644 index 000000000..59cdcadc6 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/SearchPageViewModel.cs @@ -0,0 +1,125 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Windows.UI.Xaml; +using BiliLite.Models.Common; +using BiliLite.Models.Common.Search; +using BiliLite.ViewModels.Common; +using PropertyChanged; + +namespace BiliLite.ViewModels.Search +{ + public class SearchPageViewModel : BaseViewModel + { + #region Constructors + + public SearchPageViewModel() + { + } + + #endregion + + #region Properties + + public ObservableCollection SearchItems { get; set; } + + [DoNotNotify] + public List Areas { get; set; } = new List() + { + new SearchArea("默认地区",""), + new SearchArea("大陆地区","cn"), + new SearchArea("香港地区","hk"), + new SearchArea("台湾地区","tw"), + }; + + [DoNotNotify] + public SearchArea Area { get; set; } + + [DoNotNotify] + public ISearchPivotViewModel SelectItem { get; set; } + + public ObservableCollection SuggestSearchContents { get; set; } + + public int PivotIndex { get; set; } + + public int ComboIndex { get; set; } + + public double PivotHeaderWidth { get; set; } + + public double PageWidth { get; set; } + + [DoNotNotify] + public double SearchBoxWidth { get; } = 334; + + [DependsOn(nameof(PivotHeaderWidth), nameof(PageWidth))] + public Thickness PivotMargin => PivotHeaderWidth + SearchBoxWidth < PageWidth ? new Thickness(0, 0, 0, 0) : new Thickness(0, 36, 0, 0); + + [DependsOn(nameof(PivotHeaderWidth), nameof(PageWidth))] + public Thickness SearchBoxMargin => PivotHeaderWidth + SearchBoxWidth < PageWidth ? new Thickness(400, 8, 8, 0) : new Thickness(8, 8, 8, 0); + + [DependsOn(nameof(PivotHeaderWidth), nameof(PageWidth))] + public HorizontalAlignment SearchBoxHorizontalAlignment => PivotHeaderWidth + SearchBoxWidth < PageWidth + ? HorizontalAlignment.Right + : HorizontalAlignment.Stretch; + + #endregion + + #region Public Methods + + public void Init(int pivotIndex, int comboIndex) + { + Area = Areas[comboIndex]; + SearchItems = new ObservableCollection() { + new SearchVideoViewModel() + { + Title="视频", + SearchType= SearchType.Video, + Area= Area.area + }, + new SearchAnimeViewModel() + { + Title="番剧", + SearchType= SearchType.Anime, + Area= Area.area + }, + new SearchLiveRoomViewModel() + { + Title="直播", + SearchType= SearchType.Live, + Area= Area.area + }, + //new SearchLiveRoomVM() + //{ + // Title="主播", + // SearchType= SearchType.Anchor + //}, + new SearchUserViewModel() + { + Title="用户", + SearchType= SearchType.User, + Area= Area.area + }, + new SearchAnimeViewModel() + { + Title="影视", + SearchType= SearchType.Movie, + Area= Area.area + }, + new SearchArticleViewModel() + { + Title="专栏", + SearchType= SearchType.Article, + Area= Area.area + }, + new SearchTopicViewModel() + { + Title="话题", + SearchType= SearchType.Topic, + Area= Area.area + } + }; + SelectItem = SearchItems[pivotIndex]; + } + + #endregion + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/SearchTopicViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/SearchTopicViewModel.cs new file mode 100644 index 000000000..782292b81 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/SearchTopicViewModel.cs @@ -0,0 +1,83 @@ +using BiliLite.Models; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using BiliLite.Extensions; +using BiliLite.Models.Common.Search; + +namespace BiliLite.ViewModels.Search +{ + public class SearchTopicViewModel : BaseSearchPivotViewModel + { + public ObservableCollection Topics { get; set; } + + public override async Task LoadData() + { + try + { + if (Loading) + { + return; + } + ShowLoadMore = false; + Loading = true; + Nothing = false; + var results = await SearchApi.WebSearchTopic(Keyword, Page, Area).Request(); + if (results.status) + { + var data = await results.GetJson>(); + if (data.success) + { + + var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); + if (Page == 1) + { + if (result == null || result.Count == 0) + { + Nothing = true; + Topics?.Clear(); + return; + } + Topics = result; + } + else + { + if (data.data != null) + { + foreach (var item in result) + { + Topics.Add(item); + } + } + } + if (Page < data.data["numPages"].ToInt32()) + { + ShowLoadMore = true; + Page++; + } + HasData = true; + } + else + { + Notify.ShowMessageToast(data.message); + } + } + else + { + Notify.ShowMessageToast(results.message); + } + } + catch (Exception ex) + { + var handel = HandelError(ex); + Notify.ShowMessageToast(handel.message); + } + finally + { + Loading = false; + } + } + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/SearchUserViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/SearchUserViewModel.cs new file mode 100644 index 000000000..b1b61e302 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/SearchUserViewModel.cs @@ -0,0 +1,129 @@ +using BiliLite.Models; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using BiliLite.Extensions; +using BiliLite.Models.Common.Search; +using PropertyChanged; + +namespace BiliLite.ViewModels.Search +{ + public class SearchUserViewModel : BaseSearchPivotViewModel + { + #region Constructors + + public SearchUserViewModel() + { + OrderFilters = new List() { + new SearchFilterItem("默认排序","&order=&order_sort="), + new SearchFilterItem("粉丝数由高到低","&order=fans&order_sort=0"), + new SearchFilterItem("粉丝数由低到高","&order=fans&order_sort=1"), + new SearchFilterItem("LV等级由高到低","&order=level&order_sort=0"), + new SearchFilterItem("LV等级由低到高","&order=level&order_sort=1"), + }; + SelectOrder = OrderFilters[0]; + TypeFilters = new List() { + new SearchFilterItem("全部用户","&user_type=0"), + new SearchFilterItem("UP主","&user_type=1"), + new SearchFilterItem("普通用户","&user_type=2"), + new SearchFilterItem("认证用户","&user_type=3") + }; + SelectType = TypeFilters[0]; + + } + + #endregion + + #region Properties + + [DoNotNotify] + public List OrderFilters { get; set; } + + [DoNotNotify] + public SearchFilterItem SelectOrder { get; set; } + + [DoNotNotify] + public List TypeFilters { get; set; } + + [DoNotNotify] + public SearchFilterItem SelectType { get; set; } + + public ObservableCollection Users { get; set; } + + #endregion + + #region Public Methods + + public override async Task LoadData() + { + try + { + if (Loading) + { + return; + } + ShowLoadMore = false; + Loading = true; + Nothing = false; + var results = await SearchApi.WebSearchUser(Keyword, Page, SelectOrder.value, SelectType.value, Area).Request(); + if (results.status) + { + var data = await results.GetJson>(); + if (data.success) + { + var result = JsonConvert.DeserializeObject>(data.data["result"]?.ToString() ?? "[]"); + if (Page == 1) + { + if (result == null || result.Count == 0) + { + Nothing = true; + Users?.Clear(); + return; + } + Users = result; + } + else + { + if (data.data != null) + { + foreach (var item in result) + { + Users.Add(item); + } + } + } + if (Page < data.data["numPages"].ToInt32()) + { + ShowLoadMore = true; + Page++; + } + HasData = true; + } + else + { + Notify.ShowMessageToast(data.message); + } + } + else + { + Notify.ShowMessageToast(results.message); + } + } + catch (Exception ex) + { + var handel = HandelError(ex); + Notify.ShowMessageToast(handel.message); + } + finally + { + Loading = false; + } + } + + #endregion + + } +} diff --git a/src/BiliLite.UWP/ViewModels/Search/SearchVideoViewModel.cs b/src/BiliLite.UWP/ViewModels/Search/SearchVideoViewModel.cs new file mode 100644 index 000000000..b7dfda727 --- /dev/null +++ b/src/BiliLite.UWP/ViewModels/Search/SearchVideoViewModel.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using BiliLite.Extensions; +using BiliLite.Models; +using BiliLite.Models.Common.Search; +using BiliLite.Models.Exceptions; +using BiliLite.Services; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PropertyChanged; + +namespace BiliLite.ViewModels.Search +{ + public class SearchVideoViewModel : BaseSearchPivotViewModel + { + #region Fields + + private static readonly ILogger _logger = GlobalLogger.FromCurrentType(); + private readonly ContentFilterService m_contentFilterService; + + #endregion + + #region Constructors + + public SearchVideoViewModel() + { + m_contentFilterService = App.ServiceProvider.GetRequiredService(); + OrderFilters = new List() { + new SearchFilterItem("综合排序",""), + new SearchFilterItem("最多点击","click"), + new SearchFilterItem("最新发布","pubdate"), + new SearchFilterItem("最多弹幕","dm"), + new SearchFilterItem("最多收藏","stow") + }; + SelectOrder = OrderFilters[0]; + DurationFilters = new List() { + new SearchFilterItem("全部时长",""), + new SearchFilterItem("10分钟以下","1"), + new SearchFilterItem("10-30分钟","2"), + new SearchFilterItem("30-60分钟","3"), + new SearchFilterItem("60分钟以上","4") + }; + SelectDuration = DurationFilters[0]; + RegionFilters = new List() { + new SearchFilterItem("全部分区","0"), + }; + foreach (var item in AppHelper.Regions.Where(x => x.children != null && x.children.Count != 0)) + { + RegionFilters.Add(new SearchFilterItem(item.name, item.tid.ToString())); + } + SelectRegion = RegionFilters[0]; + } + + #endregion + + #region Properties + + + [DoNotNotify] + public List OrderFilters { get; set; } + + [DoNotNotify] + public SearchFilterItem SelectOrder { get; set; } + + [DoNotNotify] + public List DurationFilters { get; set; } + + [DoNotNotify] + public SearchFilterItem SelectDuration { get; set; } + + [DoNotNotify] + public List RegionFilters { get; set; } + + [DoNotNotify] + public SearchFilterItem SelectRegion { get; set; } + + public ObservableCollection Videos { get; set; } + + #endregion + + #region Public Methods + + public override async Task LoadData() + { + try + { + if (Loading) + { + return; + } + ShowLoadMore = false; + Loading = true; + Nothing = false; + var results = await SearchApi.WebSearchVideo(Keyword, Page, SelectOrder.value, SelectDuration.value, SelectRegion.value, Area).Request(); + if (!results.status) + { + throw new CustomizedErrorException(results.message); + } + var data = await results.GetJson>(); + if (!data.success) + { + throw new CustomizedErrorException(data.message); + } + 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) + { + Nothing = true; + Videos?.Clear(); + return; + } + Videos = result; + } + else if (data.data != null) + { + foreach (var item in result) + { + Videos.Add(item); + } + } + if (Page < data.data["numPages"].ToInt32()) + { + ShowLoadMore = true; + Page++; + } + HasData = true; + + } + catch (Exception ex) + { + if (ex is CustomizedErrorException customizedErrorException) + { + Notify.ShowMessageToast(ex.Message); + _logger.Error("搜索失败", ex); + } + + var handel = HandelError(ex); + Notify.ShowMessageToast(handel.message); + } + finally + { + Loading = false; + } + } + + #endregion + } +}