using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Gallery.Resources; using Gallery.UI; using Gallery.Utils; using Xamarin.Essentials; using Xamarin.Forms; namespace Gallery.Illust { public partial class RankingPage : IllustRankingDataCollectionPage { private static readonly string[] segmentDates = { "daily", "weekly", "monthly", "male" }; public static readonly BindableProperty InternalTitleProperty = BindableProperty.Create( nameof(InternalTitle), typeof(string), typeof(RankingPage)); public string InternalTitle { get => (string)GetValue(InternalTitleProperty); set => SetValue(InternalTitleProperty, value); } public static readonly BindableProperty SegmentDateProperty = BindableProperty.Create( nameof(SegmentDate), typeof(int), typeof(RankingPage), propertyChanged: OnSegmentDatePropertyChanged); public static readonly BindableProperty SegmentTypeVisibleProperty = BindableProperty.Create( nameof(SegmentTypeVisible), typeof(bool), typeof(RankingPage)); public static readonly BindableProperty SegmentTypeProperty = BindableProperty.Create( nameof(SegmentType), typeof(int), typeof(RankingPage), propertyChanged: OnSegmentTypePropertyChanged); public static readonly BindableProperty MaximumDateProperty = BindableProperty.Create( nameof(MaximumDate), typeof(DateTime), typeof(RankingPage), DateTime.Today); public static readonly BindableProperty SelectedDateProperty = BindableProperty.Create( nameof(SelectedDate), typeof(DateTime), typeof(RankingPage), DateTime.Today); private static void OnSegmentDatePropertyChanged(BindableObject obj, object old, object @new) { var page = (RankingPage)obj; var index = (int)@new; if (index == 2) { // monthly var typeIndex = page.SegmentType; if (typeIndex == 1) { // r-18 page.SegmentType = 0; } } } private static void OnSegmentTypePropertyChanged(BindableObject obj, object old, object @new) { var page = (RankingPage)obj; var index = (int)@new; if (index == 1) { // r-18 var dateIndex = page.SegmentDate; if (dateIndex == 2) { // monthly page.SegmentDate = 0; } } } public int SegmentDate { get => (int)GetValue(SegmentDateProperty); set => SetValue(SegmentDateProperty, value); } public bool SegmentTypeVisible { get => (bool)GetValue(SegmentTypeVisibleProperty); set => SetValue(SegmentTypeVisibleProperty, value); } public int SegmentType { get => (int)GetValue(SegmentTypeProperty); set => SetValue(SegmentTypeProperty, value); } public DateTime MaximumDate { get => (DateTime)GetValue(MaximumDateProperty); set => SetValue(MaximumDateProperty, value); } public DateTime SelectedDate { get => (DateTime)GetValue(SelectedDateProperty); set => SetValue(SelectedDateProperty, value); } public Command ToolbarCommand { get; private set; } private bool previousEnabled; private bool dateEnabled; private bool nextEnabled; private bool isFilterVisible; private bool isDatePickerVisible; private string lastQueryKey; private string queryDate; private string previousDate; private string nextDate; private int currentPage; private int nextPage; private string QueryKey => segmentDates[SegmentDate] + (SegmentType == 1 ? "_r18" : string.Empty); public RankingPage() { Resources.Add("cardView", GetCardViewTemplate(titleBinding: nameof(IllustItem.RankTitle))); ToolbarCommand = new Command(OnDateTrigger, OnCanDateTrigger); InitializeComponent(); gridFilter.TranslationY = -100; panelFilter.TranslationY = -100; // preferences SegmentDate = Preferences.Get(Configs.QueryModeKey, 0); SegmentType = Preferences.Get(Configs.QueryTypeKey, 0); lastQueryKey = QueryKey; queryDate = Preferences.Get(Configs.QueryDateKey, null); currentPage = 1; datePicker.MinimumDate = new DateTime(2007, 9, 13); MaximumDate = DateTime.Today.AddDays(-1); } protected override ActivityIndicator LoadingIndicator => activityLoading; protected override void OnAppearing() { var r18 = Configs.IsOnR18; if (!r18) { SegmentType = 0; var query = QueryKey; if (lastQueryKey != query) { ReleaseCollection(); lastQueryKey = query; } } SegmentTypeVisible = r18; if (currentPage != 1 && Illusts == null) { currentPage = 1; } base.OnAppearing(); } protected override void OnDisappearing() { base.OnDisappearing(); // saving state Preferences.Set(Configs.QueryModeKey, SegmentDate); Preferences.Set(Configs.QueryTypeKey, SegmentType); if (queryDate != null) { Preferences.Set(Configs.QueryDateKey, queryDate); } } protected override IEnumerable DoGetIllustList(IllustRankingData data, out int tag) { tag = currentPage; if (lastQueryKey != null && lastQueryKey.StartsWith(segmentDates[3])) { return data.contents.Where(i => i.illust_type == "0").Select(i => i.ConvertToItem()); } return data.contents.Select(i => i.ConvertToItem()); } protected override IllustRankingData DoLoadIllustData(bool force) { var data = Stores.LoadIllustRankingData(lastQueryKey, queryDate, currentPage, out lastError, force); if (data != null) { if (int.TryParse(data.next, out int next)) { nextPage = next; } var date = data.date; DateTime now; if (date.Length == 8 && int.TryParse(date, out _)) { queryDate = date; now = new DateTime( int.Parse(date.Substring(0, 4)), int.Parse(date.Substring(4, 2)), int.Parse(date.Substring(6, 2))); SelectedDate = now; //date = now.ToShortDateString(); date = now.ToString("yyyy-MM-dd"); } else { now = default; } date = ResourceHelper.GetResource(data.mode, date); MainThread.BeginInvokeOnMainThread(() => InternalTitle = date); var prev_date = data.prev_date; if (int.TryParse(prev_date, out _)) { previousDate = prev_date; previousEnabled = true; } else { previousDate = null; previousEnabled = false; } var next_date = data.next_date; if (int.TryParse(next_date, out _)) { nextDate = next_date; nextEnabled = true; } else { nextDate = null; nextEnabled = false; if (now != default && force) { MaximumDate = now; } } } dateEnabled = true; MainThread.BeginInvokeOnMainThread(ToolbarCommand.ChangeCanExecute); return data; } private async void ToggleFilterPanel(bool flag) { ViewExtensions.CancelAnimations(gridFilter); ViewExtensions.CancelAnimations(panelFilter); if (flag) { isFilterVisible = true; if (scrollDirection == ScrollDirection.Down) { // stop the scrolling await scrollView.ScrollToAsync(scrollView.ScrollX, scrollView.ScrollY, false); } await Task.WhenAll( labelCaret.RotateTo(180, easing: Easing.CubicOut), gridFilter.TranslateTo(0, 0, easing: Easing.CubicOut), gridFilter.FadeTo(1, easing: Easing.CubicOut), panelFilter.TranslateTo(0, 0, easing: Easing.CubicOut), panelFilter.FadeTo(1, easing: Easing.CubicOut) ); } else { isFilterVisible = false; await Task.WhenAll( labelCaret.RotateTo(0, easing: Easing.CubicIn), gridFilter.TranslateTo(0, -100, easing: Easing.CubicIn), gridFilter.FadeTo(0, easing: Easing.CubicIn), panelFilter.TranslateTo(0, -100, easing: Easing.CubicIn), panelFilter.FadeTo(0, easing: Easing.CubicIn) ); } } private async void OnDateTrigger(string action) { if (IsLoading) { return; } if (action == "select") { // stop the scrolling await scrollView.ScrollToAsync(scrollView.ScrollX, scrollView.ScrollY, false); datePicker.Focus(); } else { var date = action == "prev" ? previousDate : nextDate; if (date == null) { return; } if (isFilterVisible) { ToggleFilterPanel(false); } queryDate = date; PrepareLoad(); } } private bool OnCanDateTrigger(string action) { switch (action) { case "prev": return previousEnabled; case "next": return nextEnabled; default: return dateEnabled; } } private void DatePicker_Focused(object sender, FocusEventArgs e) { isDatePickerVisible = e.IsFocused; } private void DatePicker_DateSelected(object sender, DateChangedEventArgs e) { if (e.OldDate == DateTime.Today || IsLoading) { // first load or loading return; } queryDate = e.NewDate.ToString("yyyyMMdd"); PrepareLoad(); } private void TapGestureRecognizer_Tapped(object sender, EventArgs e) { ToggleFilterPanel(!isFilterVisible); } private void FlowLayout_MaxHeightChanged(object sender, HeightEventArgs e) { SetOffset(e.ContentHeight - scrollView.Bounds.Height - SCROLL_OFFSET); } protected override bool CheckRefresh() { if (nextPage == currentPage + 1) { currentPage = nextPage; #if DEBUG App.DebugPrint($"loading page {nextPage}"); #endif return true; } return false; } private void ScrollView_Scrolled(object sender, ScrolledEventArgs e) { var y = e.ScrollY; if (IsScrollingDown(y)) { // down if (isFilterVisible) { ToggleFilterPanel(false); } } if (isDatePickerVisible) { isDatePickerVisible = false; datePicker.Unfocus(); } OnScrolled(y); } private void Filter_Clicked(object sender, EventArgs e) { var query = QueryKey; ToggleFilterPanel(false); if (IsLoading) { return; } //if (lastQueryKey != query) { // query changed. lastQueryKey = query; #if DEBUG App.DebugPrint($"query changed: {query}"); #endif PrepareLoad(); } } private async void PrepareLoad() { await ScrollToTopAsync(scrollView); // release currentPage = 1; previousEnabled = false; dateEnabled = false; nextEnabled = false; ToolbarCommand.ChangeCanExecute(); StartLoad(true); } private void ReleaseCollection() { currentPage = 1; InvalidateCollection(); } } }