diff --git a/PixivFSUWP/Controls/TagsPanel.cs b/PixivFSUWP/Controls/TagsPanel.cs index a016c43..4e443dd 100644 --- a/PixivFSUWP/Controls/TagsPanel.cs +++ b/PixivFSUWP/Controls/TagsPanel.cs @@ -77,7 +77,7 @@ protected override Size MeasureOverride(Size availableSize) else widths[rowCount - 1] = tmpWidth; } - return new Size(widths.Max(), rowCount * ItemHeight + (rowCount - 1) * ItemVerticalMargin); + return new Size(0, rowCount * ItemHeight + (rowCount - 1) * ItemVerticalMargin); } protected override Size ArrangeOverride(Size finalSize) diff --git a/PixivFSUWP/Data/OverAll.cs b/PixivFSUWP/Data/OverAll.cs index 3c32eb9..165439e 100644 --- a/PixivFSUWP/Data/OverAll.cs +++ b/PixivFSUWP/Data/OverAll.cs @@ -36,12 +36,28 @@ public static class OverAll public static UserIllustsCollection UserList { get; private set; } public static MainPage TheMainPage { get; set; } - public struct SearchParam + public struct SearchParam : IEquatable { public string Word; public string SearchTarget; public string Sort; public string Duration; + + public override bool Equals(object obj) => obj is SearchParam param && Equals(param); + public bool Equals(SearchParam other) => Word == other.Word && SearchTarget == other.SearchTarget && Sort == other.Sort && Duration == other.Duration; + + public override int GetHashCode() + { + var hashCode = -582144489; + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Word); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(SearchTarget); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Sort); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Duration); + return hashCode; + } + + public static bool operator ==(SearchParam left, SearchParam right) => left.Equals(right); + public static bool operator !=(SearchParam left, SearchParam right) => !(left == right); } public static void RefreshRecommendList() diff --git a/PixivFSUWP/IllustDetailPage.xaml b/PixivFSUWP/IllustDetailPage.xaml index fcf0441..dcb8410 100644 --- a/PixivFSUWP/IllustDetailPage.xaml +++ b/PixivFSUWP/IllustDetailPage.xaml @@ -135,7 +135,7 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PixivFSUWP/SearchDialog.xaml.cs b/PixivFSUWP/SearchDialog.xaml.cs new file mode 100644 index 0000000..40344d0 --- /dev/null +++ b/PixivFSUWP/SearchDialog.xaml.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; +using PixivCS; // +using Windows.UI.Xaml.Media.Imaging; +using PixivFSUWP.Interfaces; +using static PixivFSUWP.Data.OverAll; +using Windows.Data.Json; +using PixivFSUWP.Data; + +// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板 + +namespace PixivFSUWP +{ + /// + /// 可用于自身或导航至 Frame 内部的空白页。 + /// + public sealed partial class SearchDialog + { + private readonly Frame Frame; + SearchParam last = default; + + public SearchDialog() + { + this.InitializeComponent(); + Title = GetResourceString("SearchPagePlain"); + CloseButtonText = GetResourceString("CancelPlain"); + + _ = loadContents(); + } + public SearchDialog(Frame frame) : this() => Frame = frame; + + async Task> getTrendingTags() + { + try + { + var res = await new PixivAppAPI(Data.OverAll.GlobalBaseAPI).GetTrendingTagsIllustAsync(); + var array = res.TrendTags; + List toret = new List(); + foreach (var i in array) + toret.Add(new ViewModels.TagViewModel() { Tag = i.Tag }); + return toret; + } + catch + { + return null; + } + } + + async Task loadContents() + { + var tags = await getTrendingTags(); + progressRing.Visibility = Visibility.Collapsed; + panelTags.ItemsSource = tags; + } + + private void TxtWord_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) => Search(sender.Text); + + public void Search(string word) + { + if (string.IsNullOrWhiteSpace(word)) + return; + + var param = new SearchParam + { + Word = word.Trim() + }; + switch (cbSearchTarget.SelectedIndex) + { + case 0: + param.SearchTarget = "partial_match_for_tags"; + break; + case 1: + param.SearchTarget = "exact_match_for_tags"; + break; + case 2: + param.SearchTarget = "title_and_caption"; + break; + } + switch (cbSort.SelectedIndex) + { + case 0: + param.Sort = "date_desc"; + break; + case 1: + param.Sort = "date_asc"; + break; + } + switch (cbDuration.SelectedIndex) + { + case 0: + param.Duration = null; + break; + case 1: + param.Duration = "within_last_day"; + break; + case 2: + param.Duration = "within_last_week"; + break; + case 3: + param.Duration = "within_last_month"; + break; + } + Search(param); + } + public void Search(SearchParam param) + { + if (param != last) + { + RefreshSearchResultList(param); + Frame?.Navigate(typeof(WaterfallPage), WaterfallPage.ListContent.SearchResult, App.FromRightTransitionInfo); + } + Hide(); + if (param != last) + last = param; + } + + private void BtnTag_Click(object sender, RoutedEventArgs e) + { + Search(new SearchParam + { + Word = (sender as Button).Tag as string, + SearchTarget = "exact_match_for_tags", + Sort = "date_desc", + Duration = null + }); + } + + private async void btnSauceNAO_Click(object sender, RoutedEventArgs e) + { + const string sauceNAOAPI = null; + const string imgurAPI = null; + string SAUCENAO_API_KEY, IMGUR_API_KEY; + Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; + //读取设置项 + if (localSettings.Values["SauceNAOAPI"] as string == null) + { + Frame.Navigate(typeof(SettingsPage), null, App.FromRightTransitionInfo); + SAUCENAO_API_KEY = sauceNAOAPI; + return; + } + else if ((localSettings.Values["SauceNAOAPI"] as string).Length == 0) + { + Frame.Navigate(typeof(SettingsPage), null, App.FromRightTransitionInfo); + SAUCENAO_API_KEY = sauceNAOAPI; + return; + } + if (localSettings.Values["ImgurAPI"] as string == null) + { + Frame.Navigate(typeof(SettingsPage), null, App.FromRightTransitionInfo); + IMGUR_API_KEY = imgurAPI; + return; + } + else if ((localSettings.Values["ImgurAPI"] as string).Length == 0) + { + Frame.Navigate(typeof(SettingsPage), null, App.FromRightTransitionInfo); + IMGUR_API_KEY = imgurAPI; + return; + } + SAUCENAO_API_KEY = localSettings.Values["SauceNAOAPI"] as string; + IMGUR_API_KEY = localSettings.Values["ImgurAPI"] as string; + // 选择文件 + var picker = new Windows.Storage.Pickers.FileOpenPicker(); + picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail; + picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary; + picker.FileTypeFilter.Add(".jpg"); + picker.FileTypeFilter.Add(".jpeg"); + picker.FileTypeFilter.Add(".png"); + Windows.Storage.StorageFile file = await picker.PickSingleFileAsync(); + // 检测文件 + if (file == null) + { + Frame.GoBack(); + return; + } + // + //ImgurNaoAPI imgurNaoApi = new ImgurNaoAPI(SAUCENAO_API_KEY, IMGUR_API_KEY); + //string image = imgurNaoApi.UpLoad(await StorageFileExt.AsByteArray(file)).GetNamedString("link"); + //int retPid = (int)imgurNaoApi.DownLoad(image).GetNamedNumber("pixiv_id"); + //Frame.Navigate(typeof(IllustDetailPage), retPid); + } + private void GoPixivID_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) + { + if (int.TryParse(sender.Text, out var id)) + { + Frame.Navigate(typeof(IllustDetailPage), id, App.FromRightTransitionInfo); + Hide(); + } + } + + private void style_TextBox_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args) + { + //IME输入不能触发BeforeTextChanging,我估计是个Bug + //只能在此确保绝对没有不是数字的东西混进来 + sender.Text = new string(sender.Text.Where(char.IsDigit).ToArray()); + } + + private void style_TextBox_BeforeTextChanging(TextBox sender, TextBoxBeforeTextChangingEventArgs args) + { + args.Cancel = args.NewText.Any(c => !char.IsDigit(c)); + } + } + + static class StorageFileExt + { + /// + /// 将文件转换为字节数组 + /// + /// + /// + public static async Task AsByteArray(this Windows.Storage.StorageFile file) + { + Windows.Storage.Streams.IRandomAccessStream fileStream = + await file.OpenAsync(Windows.Storage.FileAccessMode.Read); + var reader = new Windows.Storage.Streams.DataReader(fileStream.GetInputStreamAt(0)); + await reader.LoadAsync((uint)fileStream.Size); + byte[] pixels = new byte[fileStream.Size]; + reader.ReadBytes(pixels); + return pixels; + } + } +} diff --git a/PixivFSUWP/SearchPage.xaml b/PixivFSUWP/SearchPage.xaml deleted file mode 100644 index 2a7e2b9..0000000 --- a/PixivFSUWP/SearchPage.xaml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/PixivFSUWP/SearchPage.xaml.cs b/PixivFSUWP/SearchPage.xaml.cs deleted file mode 100644 index cf9b97a..0000000 --- a/PixivFSUWP/SearchPage.xaml.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using System.Threading.Tasks; -using Windows.Foundation; -using Windows.Foundation.Collections; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; -using Windows.UI.Xaml.Data; -using Windows.UI.Xaml.Input; -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Navigation; -using PixivCS; // -using Windows.UI.Xaml.Media.Imaging; -using PixivFSUWP.Interfaces; -using static PixivFSUWP.Data.OverAll; -using Windows.Data.Json; -using PixivFSUWP.Data; - -// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板 - -namespace PixivFSUWP -{ - /// - /// 可用于自身或导航至 Frame 内部的空白页。 - /// - public sealed partial class SearchPage : Page, IGoBackFlag - { - string lastWord = null; - int lastSearchTarget = -1; - int lastSort = -1; - int lastDuration = -1; - - public SearchPage() - { - this.InitializeComponent(); - } - - private bool _backflag { get; set; } = false; - - public void SetBackFlag(bool value) - { - _backflag = value; - } - - protected override void OnNavigatedFrom(NavigationEventArgs e) - { - base.OnNavigatedFrom(e); - if (!_backflag) - { - Data.OverAll.SearchResultList?.PauseLoading(); - if (e.Parameter is ValueTuple tuple) - { - Data.Backstack.Default.Push - (typeof(SearchPage), - new ValueTuple - (WaterfallPage.ListContent.SearchResult, tuple.Item2)); - } - else - Data.Backstack.Default.Push(typeof(SearchPage), WaterfallPage.ListContent.SearchResult); - } - ((Frame.Parent as Grid)?.Parent as MainPage)?.UpdateNavButtonState(); - } - - async Task> getTrendingTags() - { - try - { - var res = await new PixivAppAPI(Data.OverAll.GlobalBaseAPI).GetTrendingTagsIllustAsync(); - var array = res.TrendTags; - List toret = new List(); - foreach (var i in array) - toret.Add(new ViewModels.TagViewModel() { Tag = i.Tag }); - return toret; - } - catch - { - return null; - } - } - - async Task loadContents() - { - stkMain.Visibility = Visibility.Visible; - var tags = await getTrendingTags(); - //progressRing.IsActive = false; - progressRing.Visibility = Visibility.Collapsed; - panelTags.ItemsSource = tags; - } - - protected override void OnNavigatedTo(NavigationEventArgs e) - { - base.OnNavigatedTo(e); - if (e.Parameter is WaterfallPage.ListContent) - { - _ = loadContents(); - SearchResultList?.StopLoading(); - } - else if (e.Parameter is ValueTuple) - { - resultFrame.Navigate(typeof(WaterfallPage), e.Parameter); - grdSearchPanel.Visibility = Visibility.Collapsed; - if (txtWord.Text.Trim() != lastWord || cbSearchTarget.SelectedIndex != lastSearchTarget || - cbSort.SelectedIndex != lastSort || cbDuration.SelectedIndex != lastDuration) - { - lastWord = txtWord.Text.Trim(); - lastSearchTarget = cbSearchTarget.SelectedIndex; - lastSort = cbSort.SelectedIndex; - lastDuration = cbDuration.SelectedIndex; - } - } - ((Frame.Parent as Grid)?.Parent as MainPage)?.SelectNavPlaceholder(GetResourceString("SearchPagePlain")); - } - - public async Task ShowSearch() - { - if (grdSearchPanel.Visibility == Visibility.Collapsed) - { - searchProgressRing.Visibility = Visibility.Collapsed; - searchProgressRing.IsActive = false; - grdSearchPanel.Visibility = Visibility.Visible; - stkMain.Visibility = Visibility.Collapsed; - storyShow.Begin(); - await Task.Delay(200); - } - else stkMain.Visibility = Visibility.Collapsed; - //progressRing.IsActive = true; - progressRing.Visibility = Visibility.Visible; - (panelTags.ItemsSource as List).Clear(); - panelTags.ItemsSource = null; - await loadContents(); - } - - private async void TxtWord_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) - { - if (string.IsNullOrWhiteSpace(txtWord.Text)) return; - if (txtWord.Text.Trim() != lastWord || cbSearchTarget.SelectedIndex != lastSearchTarget || - cbSort.SelectedIndex != lastSort || cbDuration.SelectedIndex != lastDuration) - { - if (resultFrame.Content != null) - (resultFrame.Content as WaterfallPage).ItemsSource.CollectionChanged -= ItemsSource_CollectionChanged; - var param = new OverAll.SearchParam() - { - Word = txtWord.Text.Trim() - }; - switch (cbSearchTarget.SelectedIndex) - { - case 0: - param.SearchTarget = "partial_match_for_tags"; - break; - case 1: - param.SearchTarget = "exact_match_for_tags"; - break; - case 2: - param.SearchTarget = "title_and_caption"; - break; - } - switch (cbSort.SelectedIndex) - { - case 0: - param.Sort = "date_desc"; - break; - case 1: - param.Sort = "date_asc"; - break; - } - switch (cbDuration.SelectedIndex) - { - case 0: - param.Duration = null; - break; - case 1: - param.Duration = "within_last_day"; - break; - case 2: - param.Duration = "within_last_week"; - break; - case 3: - param.Duration = "within_last_month"; - break; - } - OverAll.RefreshSearchResultList(param); - resultFrame.Navigate(typeof(WaterfallPage), WaterfallPage.ListContent.SearchResult, App.FromRightTransitionInfo); - (resultFrame.Content as WaterfallPage).ItemsSource.CollectionChanged += ItemsSource_CollectionChanged; - } - storyFade.Begin(); - await Task.Delay(200); - grdSearchPanel.Visibility = Visibility.Collapsed; - if (txtWord.Text.Trim() != lastWord || cbSearchTarget.SelectedIndex != lastSearchTarget || - cbSort.SelectedIndex != lastSort || cbDuration.SelectedIndex != lastDuration) - { - lastWord = txtWord.Text.Trim(); - lastSearchTarget = cbSearchTarget.SelectedIndex; - lastSort = cbSort.SelectedIndex; - lastDuration = cbDuration.SelectedIndex; - searchProgressRing.IsActive = true; - searchProgressRing.Visibility = Visibility.Visible; - } - } - - private void ItemsSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - searchProgressRing.Visibility = Visibility.Collapsed; - searchProgressRing.IsActive = false; - } - - private void BtnTag_Click(object sender, RoutedEventArgs e) - { - txtWord.Text = (sender as Button).Tag as string; - cbSearchTarget.SelectedIndex = 1; - cbSort.SelectedIndex = 0; - cbDuration.SelectedIndex = 0; - TxtWord_QuerySubmitted(null, null); - } - - private async void btnSauceNAO_Click(object sender, RoutedEventArgs e) - { - const string sauceNAOAPI = null; - const string imgurAPI = null; - string SAUCENAO_API_KEY, IMGUR_API_KEY; - Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; - //读取设置项 - if (localSettings.Values["SauceNAOAPI"] as string == null) - { - Frame.Navigate(typeof(SettingsPage),null, App.FromRightTransitionInfo); - SAUCENAO_API_KEY = sauceNAOAPI; - return; - } - else if ((localSettings.Values["SauceNAOAPI"] as string).Length == 0) - { - Frame.Navigate(typeof(SettingsPage), null, App.FromRightTransitionInfo); - SAUCENAO_API_KEY = sauceNAOAPI; - return; - } - if (localSettings.Values["ImgurAPI"] as string == null) - { - Frame.Navigate(typeof(SettingsPage), null, App.FromRightTransitionInfo); - IMGUR_API_KEY = imgurAPI; - return; - } - else if ((localSettings.Values["ImgurAPI"] as string).Length == 0) - { - Frame.Navigate(typeof(SettingsPage), null, App.FromRightTransitionInfo); - IMGUR_API_KEY = imgurAPI; - return; - } - SAUCENAO_API_KEY = localSettings.Values["SauceNAOAPI"] as string; - IMGUR_API_KEY = localSettings.Values["ImgurAPI"] as string; - // 选择文件 - var picker = new Windows.Storage.Pickers.FileOpenPicker(); - picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail; - picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary; - picker.FileTypeFilter.Add(".jpg"); - picker.FileTypeFilter.Add(".jpeg"); - picker.FileTypeFilter.Add(".png"); - Windows.Storage.StorageFile file = await picker.PickSingleFileAsync(); - // 检测文件 - if (file == null) - { - Frame.GoBack(); - return; - } - // - //ImgurNaoAPI imgurNaoApi = new ImgurNaoAPI(SAUCENAO_API_KEY, IMGUR_API_KEY); - //string image = imgurNaoApi.UpLoad(await StorageFileExt.AsByteArray(file)).GetNamedString("link"); - //int retPid = (int)imgurNaoApi.DownLoad(image).GetNamedNumber("pixiv_id"); - //Frame.Navigate(typeof(IllustDetailPage), retPid); - } - private void GoPixivID_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) - { - try - { - Frame.Navigate(typeof(IllustDetailPage), int.Parse(asbGTPID.Text), App.FromRightTransitionInfo); - } - catch(OverflowException) - { - //吞了异常。一般是由于输入的数字过大,超过了Int32的限制导致 - } - } - - private void style_TextBox_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args) - { - //IME输入不能触发BeforeTextChanging,我估计是个Bug - //只能在此确保绝对没有不是数字的东西混进来 - sender.Text = new string(sender.Text.Where(char.IsDigit).ToArray()); - } - - private void style_TextBox_BeforeTextChanging(TextBox sender, TextBoxBeforeTextChangingEventArgs args) - { - args.Cancel = args.NewText.Any(c => !char.IsDigit(c)); - } - } - - static class StorageFileExt - { - /// - /// 将文件转换为字节数组 - /// - /// - /// - public static async Task AsByteArray(this Windows.Storage.StorageFile file) - { - Windows.Storage.Streams.IRandomAccessStream fileStream = - await file.OpenAsync(Windows.Storage.FileAccessMode.Read); - var reader = new Windows.Storage.Streams.DataReader(fileStream.GetInputStreamAt(0)); - await reader.LoadAsync((uint)fileStream.Size); - byte[] pixels = new byte[fileStream.Size]; - reader.ReadBytes(pixels); - return pixels; - } - } -} diff --git a/PixivFSUWP/WaterfallPage.xaml.cs b/PixivFSUWP/WaterfallPage.xaml.cs index 65ef051..fd880c9 100644 --- a/PixivFSUWP/WaterfallPage.xaml.cs +++ b/PixivFSUWP/WaterfallPage.xaml.cs @@ -61,10 +61,14 @@ public WaterfallPage() protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); - if (e.Parameter is ListContent) listContent = (ListContent)e.Parameter; - else if(e.Parameter is ValueTuple tuple) + switch (e.Parameter) { - (listContent, clicked) = tuple; + case ListContent content: + listContent = content; + break; + case ValueTuple tuple: + (listContent, clicked) = tuple; + break; } switch (listContent) { @@ -85,6 +89,7 @@ protected override void OnNavigatedTo(NavigationEventArgs e) Data.OverAll.RankingList.ResumeLoading(); break; case ListContent.SearchResult: + TheMainPage.SelectNavPlaceholder(GetResourceString("SearchPagePlain")); ItemsSource = Data.OverAll.SearchResultList; Data.OverAll.SearchResultList.ResumeLoading(); WaterfallListView.ItemsSource = ItemsSource;