From 34a8d5f434acff23f7f4a51ba786e16aa6a6335f Mon Sep 17 00:00:00 2001
From: Tsanie Lily <tsorgy@gmail.com>
Date: Wed, 20 May 2020 01:17:11 +0800
Subject: [PATCH] feature: favorites type filter

---
 Pixiview/Illust/FavoritesPage.xaml      | 46 +++++++++++++
 Pixiview/Illust/FavoritesPage.xaml.cs   | 90 +++++++++++++++++++++++--
 Pixiview/Illust/IllustCollectionPage.cs | 18 ++++-
 Pixiview/Illust/RankingPage.xaml.cs     | 12 ----
 Pixiview/Resources/Languages/zh-CN.xml  |  3 +
 Pixiview/Utils/Stores.cs                |  3 +-
 6 files changed, 152 insertions(+), 20 deletions(-)

diff --git a/Pixiview/Illust/FavoritesPage.xaml b/Pixiview/Illust/FavoritesPage.xaml
index edf288b..13240e2 100644
--- a/Pixiview/Illust/FavoritesPage.xaml
+++ b/Pixiview/Illust/FavoritesPage.xaml
@@ -7,6 +7,32 @@
                                 x:Class="Pixiview.Illust.FavoritesPage"
                                 BackgroundColor="{DynamicResource WindowColor}"
                                 Title="{r:Text Favorites}">
+    <Shell.TitleView>
+        <Grid VerticalOptions="Fill" ColumnSpacing="6"
+               HorizontalOptions="{x:OnPlatform Android=Start, iOS=Fill}">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="{OnPlatform Android=Auto}"/>
+                <ColumnDefinition Width="Auto"/>
+                <ColumnDefinition/>
+            </Grid.ColumnDefinitions>
+            <StackLayout Grid.Column="1" Orientation="Horizontal" Spacing="6">
+                <StackLayout.GestureRecognizers>
+                    <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
+                </StackLayout.GestureRecognizers>
+                <Label Text="{Binding Title}"
+                       TextColor="{DynamicResource TextColor}"
+                       FontSize="{OnPlatform Android=18}"
+                       LineBreakMode="HeadTruncation"
+                       VerticalTextAlignment="Center" FontAttributes="Bold"/>
+                <Label x:Name="labelCaret"
+                       Text="{DynamicResource IconCaretDown}"
+                       TextColor="{DynamicResource TextColor}"
+                       FontFamily="{DynamicResource IconSolidFontFamily}"
+                       FontSize="Small"
+                       VerticalTextAlignment="Center"/>
+            </StackLayout>
+        </Grid>
+    </Shell.TitleView>
     <ContentPage.ToolbarItems>
         <ToolbarItem Order="Primary" Clicked="Refresh_Clicked"
                      IconImageSource="{DynamicResource FontIconCloudDownload}"/>
@@ -30,5 +56,25 @@
                                    IsVisible="{Binding IsBottomLoading}"/>
             </StackLayout>
         </ScrollView>
+
+        <u:BlurryPanel x:Name="panelFilter" VerticalOptions="Start" Opacity="0"
+                       Margin="{Binding PanelTopMargin}"
+                       BackgroundColor="{DynamicResource WindowColor}"
+                       HeightRequest="{Binding Height, Source={x:Reference gridFilter}}"/>
+        <Grid x:Name="gridFilter" VerticalOptions="Start" Opacity="0"
+              Margin="{Binding PageTopMargin}" Padding="10">
+            <Grid RowSpacing="0" HorizontalOptions="Center">
+                <u:SegmentedControl Margin="6, 6, 6, 3" VerticalOptions="Center"
+                                    SelectedSegmentIndex="{Binding SegmentType, Mode=TwoWay}"
+                                    SelectedTextColor="{DynamicResource TextColor}"
+                                    TintColor="{DynamicResource CardBackgroundColor}">
+                    <u:SegmentedControl.Children>
+                        <u:SegmentedControlOption Text="{r:Text All}"/>
+                        <u:SegmentedControlOption Text="{r:Text Animation}"/>
+                        <u:SegmentedControlOption Text="{r:Text Online}"/>
+                    </u:SegmentedControl.Children>
+                </u:SegmentedControl>
+            </Grid>
+        </Grid>
     </Grid>
 </i:FavoriteIllustCollectionPage>
diff --git a/Pixiview/Illust/FavoritesPage.xaml.cs b/Pixiview/Illust/FavoritesPage.xaml.cs
index 875dfa2..ae82d34 100644
--- a/Pixiview/Illust/FavoritesPage.xaml.cs
+++ b/Pixiview/Illust/FavoritesPage.xaml.cs
@@ -14,6 +14,22 @@ namespace Pixiview.Illust
     {
         private const int STEP = 20;
 
+        public static readonly BindableProperty SegmentTypeProperty = BindableProperty.Create(
+            nameof(SegmentType), typeof(int), typeof(FavoritesPage), propertyChanged: OnSegmentTypePropertyChanged);
+
+        private static void OnSegmentTypePropertyChanged(BindableObject obj, object old, object @new)
+        {
+            var page = (FavoritesPage)obj;
+            MainThread.BeginInvokeOnMainThread(page.ChangeFilter);
+        }
+
+        public int SegmentType
+        {
+            get => (int)GetValue(SegmentTypeProperty);
+            set => SetValue(SegmentTypeProperty, value);
+        }
+
+        private bool isFilterVisible;
         private int startIndex;
         private int nextIndex;
         private bool flag = false;
@@ -22,6 +38,8 @@ namespace Pixiview.Illust
         {
             Resources.Add("cardView", GetCardViewTemplate());
             InitializeComponent();
+            gridFilter.TranslationY = -60;
+            panelFilter.TranslationY = -60;
 
             startIndex = -1;
             nextIndex = 0;
@@ -35,7 +53,6 @@ namespace Pixiview.Illust
             if (lastUpdated != LastUpdated)
             {
                 startIndex = -1;
-                nextIndex = 0;
                 StartLoad();
             }
             else
@@ -45,7 +62,6 @@ namespace Pixiview.Illust
                 {
                     lastUpdated = default;
                     startIndex = -1;
-                    nextIndex = 0;
                     StartLoad();
                 }
             }
@@ -58,7 +74,7 @@ namespace Pixiview.Illust
 
         protected override IllustItem[] DoLoadIllustData(bool force)
         {
-            FavoriteList favs;
+            IEnumerable<IllustItem> favs;
             if (startIndex < 0)
             {
                 var favorites = Stores.GetFavoriteObject(flag);
@@ -67,14 +83,22 @@ namespace Pixiview.Illust
                 {
                     return null;
                 }
-                favs = favorites.Illusts;
-                favs.Reload();
+                favs = favorites.Illusts.Reload();
                 startIndex = 0;
             }
             else
             {
                 favs = Stores.Favorites;
             }
+            switch (SegmentType)
+            {
+                case 1: // animation
+                    favs = favs.Where(f => f.IllustType == IllustType.Anime);
+                    break;
+                case 2: // online
+                    favs = favs.Where(f => f.BookmarkId != null);
+                    break;
+            }
             var illusts = favs.Skip(startIndex).Take(STEP).ToArray();
             nextIndex = startIndex + STEP;
             if (illusts.Length == 0 || nextIndex >= Stores.Favorites.Count)
@@ -85,6 +109,53 @@ namespace Pixiview.Illust
             return illusts;
         }
 
+        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, -60, easing: Easing.CubicIn),
+                    gridFilter.FadeTo(0, easing: Easing.CubicIn),
+                    panelFilter.TranslateTo(0, -60, easing: Easing.CubicIn),
+                    panelFilter.FadeTo(0, easing: Easing.CubicIn)
+                    );
+            }
+        }
+
+        private async void ChangeFilter()
+        {
+            ToggleFilterPanel(false);
+            await ScrollToTopAsync(scrollView);
+            startIndex = 0;
+            lastUpdated = default;
+            StartLoad();
+        }
+
+        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);
@@ -103,6 +174,14 @@ namespace Pixiview.Illust
         private void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
         {
             var y = e.ScrollY;
+            if (IsScrollingDown(y))
+            {
+                // down
+                if (isFilterVisible)
+                {
+                    ToggleFilterPanel(false);
+                }
+            }
             OnScrolled(y);
         }
 
@@ -114,7 +193,6 @@ namespace Pixiview.Illust
                 flag = true;
             }
             startIndex = -1;
-            nextIndex = 0;
             StartLoad(force);
         }
 
diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs
index 38924a4..490a718 100644
--- a/Pixiview/Illust/IllustCollectionPage.cs
+++ b/Pixiview/Illust/IllustCollectionPage.cs
@@ -630,6 +630,7 @@ namespace Pixiview.Illust
     public abstract class IllustScrollableCollectionPage<T> : IllustCollectionPage<T>
     {
         protected const int SCROLL_OFFSET = 33;
+        protected ScrollDirection scrollDirection = ScrollDirection.Stop;
 
         private double lastScrollY = double.MinValue;
         private double lastRefreshY = double.MinValue;
@@ -637,7 +638,22 @@ namespace Pixiview.Illust
 
         protected bool IsScrollingDown(double y)
         {
-            return y > lastScrollY;
+            if (y > lastScrollY)
+            {
+                if (scrollDirection != ScrollDirection.Down)
+                {
+                    scrollDirection = ScrollDirection.Down;
+                }
+                return true;
+            }
+            else
+            {
+                if (scrollDirection != ScrollDirection.Up)
+                {
+                    scrollDirection = ScrollDirection.Up;
+                }
+                return false;
+            }
         }
         protected void SetOffset(double off)
         {
diff --git a/Pixiview/Illust/RankingPage.xaml.cs b/Pixiview/Illust/RankingPage.xaml.cs
index 449e8be..8663e4b 100644
--- a/Pixiview/Illust/RankingPage.xaml.cs
+++ b/Pixiview/Illust/RankingPage.xaml.cs
@@ -86,7 +86,6 @@ namespace Pixiview.Illust
         private bool previousEnabled;
         private bool dateEnabled;
         private bool nextEnabled;
-        private ScrollDirection scrollDirection = ScrollDirection.Stop;
 
         private bool isFilterVisible;
         private string lastQueryKey;
@@ -332,23 +331,12 @@ namespace Pixiview.Illust
             var y = e.ScrollY;
             if (IsScrollingDown(y))
             {
-                if (scrollDirection != ScrollDirection.Down)
-                {
-                    scrollDirection = ScrollDirection.Down;
-                }
                 // down
                 if (isFilterVisible)
                 {
                     ToggleFilterPanel(false);
                 }
             }
-            else
-            {
-                if (scrollDirection != ScrollDirection.Up)
-                {
-                    scrollDirection = ScrollDirection.Up;
-                }
-            }
             OnScrolled(y);
         }
 
diff --git a/Pixiview/Resources/Languages/zh-CN.xml b/Pixiview/Resources/Languages/zh-CN.xml
index 535d187..ca3863a 100644
--- a/Pixiview/Resources/Languages/zh-CN.xml
+++ b/Pixiview/Resources/Languages/zh-CN.xml
@@ -59,4 +59,7 @@
     <FailedResponse>无法获取返回结果。</FailedResponse>
     <ConfirmSyncFavorite>要同步收藏吗?</ConfirmSyncFavorite>
     <ConfirmLogin>当前身份为游客,是否跳转到登录页面?</ConfirmLogin>
+    <All>所有</All>
+    <Animation>动画</Animation>
+    <Online>在线</Online>
 </root>
\ No newline at end of file
diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs
index c9a1420..76caf29 100644
--- a/Pixiview/Utils/Stores.cs
+++ b/Pixiview/Utils/Stores.cs
@@ -675,9 +675,10 @@ namespace Pixiview.Utils
             Changed = true;
         }
 
-        public void Reload()
+        public FavoriteList Reload()
         {
             Changed = false;
+            return this;
         }
     }