From 32058fe2109153ec0d8c510df5d7ddcaffc8e9de Mon Sep 17 00:00:00 2001 From: Tsanie Lily Date: Tue, 19 May 2020 11:40:17 +0800 Subject: [PATCH] feature: sync favorites feature: remote bookmark icon fix: sometimes blank title --- Pixiview/Illust/FavoritesPage.xaml.cs | 31 +++++++++- Pixiview/Illust/IllustCollectionPage.cs | 41 ++++++++------ Pixiview/Illust/RecommendsPage.xaml.cs | 5 +- Pixiview/Illust/UserIllustPage.xaml.cs | 4 +- Pixiview/Illust/ViewIllustPage.xaml.cs | 10 ++-- Pixiview/UI/CardView.cs | 4 +- Pixiview/UI/FlowLayout.cs | 2 +- Pixiview/UI/StyleDefinition.cs | 1 + Pixiview/Utils/Converters.cs | 50 ++++++++++------- Pixiview/Utils/Extensions.cs | 5 +- Pixiview/Utils/IllustData.cs | 2 - Pixiview/Utils/IllustLegacy.cs | 2 +- Pixiview/Utils/Stores.cs | 6 ++ Pixiview/Utils/Ugoira.cs | 75 +++++++++++++++---------- 14 files changed, 154 insertions(+), 84 deletions(-) diff --git a/Pixiview/Illust/FavoritesPage.xaml.cs b/Pixiview/Illust/FavoritesPage.xaml.cs index 698facb..c8338e5 100644 --- a/Pixiview/Illust/FavoritesPage.xaml.cs +++ b/Pixiview/Illust/FavoritesPage.xaml.cs @@ -176,12 +176,37 @@ namespace Pixiview.Illust else if (result == combine) { // combine - var favNow = Stores.GetFavoriteObject(); - var nows = favNow.Illusts; + var nows = Stores.GetFavoriteObject().Illusts; + // sync bookmarks from remote + for (var i = nows.Count - 1; i >= 0; i--) + { + var b = nows[i]; + var bookmarkId = b.BookmarkId; + if (!string.IsNullOrEmpty(bookmarkId)) + { + var bookmark = list.FirstOrDefault(f => f.Id == b.Id); + if (bookmark == null) + { + // not exists in remote any more + App.DebugPrint($"remove bookmark ({bookmarkId}) - {b.Id}: {b.Title}"); + nows.RemoveAt(i); + } + else if (bookmarkId != bookmark.BookmarkId) + { + // update bookmark id + App.DebugPrint($"change bookmark ({bookmarkId}) to ({bookmark.BookmarkId}) - {b.Id}: {b.Title}"); + b.BookmarkId = bookmark.BookmarkId; + } + } + } + // add bookmarks that exists in remote only list = list.Where(f => !nows.Any(i => i.Id == f.Id)).ToArray(); + for (var i = 0; i < list.Length; i++) { - list[i].Image = StyleDefinition.DownloadBackground; + var item = list[i]; + App.DebugPrint($"add bookmark ({item.BookmarkId}) - {item.Id}: {item.Title}"); + item.Image = StyleDefinition.DownloadBackground; } nows.InsertRange(0, list); } diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs index f4e17a7..1ebac54 100644 --- a/Pixiview/Illust/IllustCollectionPage.cs +++ b/Pixiview/Illust/IllustCollectionPage.cs @@ -174,7 +174,7 @@ namespace Pixiview.Illust protected abstract IEnumerable DoGetIllustList(T data); protected virtual void OnIllustImageTapped(IllustItem illust) { - var page = new ViewIllustPage(illust, IsFavoriteVisible); + var page = new ViewIllustPage(illust, true); Navigation.PushAsync(page); } protected virtual IllustCollection GetIllustsLoadedCollection(IllustCollection collection, bool bottom) @@ -388,9 +388,10 @@ namespace Pixiview.Illust VerticalOptions = LayoutOptions.Center, FontSize = StyleDefinition.FontSizeSmall, TextColor = StyleDefinition.ColorRedBackground, - Text = StyleDefinition.IconLove + IsVisible = false } - .Binding(IsVisibleProperty, IsFavoriteVisible ? nameof(IllustItem.IsFavorite) : null) + .Binding(Label.TextProperty, ".", converter: new FavoriteIconConverter(IsFavoriteVisible)) + .Binding(IsVisibleProperty, ".", converter: new FavoriteVisibleConverter()) .DynamicResource(Label.FontFamilyProperty, ThemeBase.IconSolidFontFamily); #endregion @@ -488,7 +489,7 @@ namespace Pixiview.Illust HeightRequest = 30, Aspect = Aspect.AspectFill } - .Binding(Image.SourceProperty, nameof(IllustItem.ProfileImage)), + .Binding(Image.SourceProperty, nameof(IIllustItem.ProfileImage)), // user name new Label @@ -498,7 +499,7 @@ namespace Pixiview.Illust LineBreakMode = LineBreakMode.TailTruncation, FontSize = StyleDefinition.FontSizeMicro } - .Binding(Label.TextProperty, nameof(IllustItem.UserName)) + .Binding(Label.TextProperty, nameof(IIllustItem.UserName)) .DynamicResource(Label.TextColorProperty, ThemeBase.SubTextColor) .GridColumn(1), @@ -558,17 +559,14 @@ namespace Pixiview.Illust var data = DoGetIllustList(illustData).Where(i => i != null && (r18 || !i.IsRestrict)); var collection = new IllustCollection(data); - if (IsFavoriteVisible) + var favorites = Stores.Favorites; + foreach (var item in collection) { - var favorites = Stores.Favorites; - foreach (var item in collection) + if (item.Image == null) { - if (item.Image == null) - { - item.Image = StyleDefinition.DownloadBackground; - } - item.IsFavorite = favorites.Any(i => i.Id == item.Id); + item.Image = StyleDefinition.DownloadBackground; } + item.IsFavorite = IsFavoriteVisible && favorites.Any(i => i.Id == item.Id); } DoIllustsLoaded(collection, bottom); @@ -767,15 +765,17 @@ namespace Pixiview.Illust Anime = 2 } - public interface IIllustUser + public interface IIllustItem { string UserId { get; } string UserName { get; } ImageSource ProfileImage { get; } + bool IsFavorite { get; } + string BookmarkId { get; } } [JsonObject(MemberSerialization.OptIn)] - public class IllustItem : BindableObject, IIllustUser + public class IllustItem : BindableObject, IIllustItem { private static IllustItem empty; public static IllustItem Empty @@ -798,10 +798,13 @@ namespace Pixiview.Illust nameof(ImageHeight), typeof(GridLength), typeof(IllustItem), GridLength.Auto); public static readonly BindableProperty IsFavoriteProperty = BindableProperty.Create( nameof(IsFavorite), typeof(bool), typeof(IllustItem)); + public static readonly BindableProperty BookmarkIdProperty = BindableProperty.Create( + nameof(BookmarkId), typeof(string), typeof(IllustItem)); [JsonProperty] public string Title { get; set; } - public string RankTitle { get; set; } + public int Rank { get; set; } + public string RankTitle => Rank > 0 ? $"#{Rank} {Title}" : Title; public ImageSource Image { get => (ImageSource)GetValue(ImageProperty); @@ -827,7 +830,11 @@ namespace Pixiview.Illust [JsonProperty] public string Id { get; set; } [JsonProperty] - public string BookmarkId { get; set; } + public string BookmarkId + { + get => (string)GetValue(BookmarkIdProperty); + set => SetValue(BookmarkIdProperty, value); + } [JsonProperty] public DateTime FavoriteDateUtc { get; set; } [JsonProperty] diff --git a/Pixiview/Illust/RecommendsPage.xaml.cs b/Pixiview/Illust/RecommendsPage.xaml.cs index aeba33c..4e4221d 100644 --- a/Pixiview/Illust/RecommendsPage.xaml.cs +++ b/Pixiview/Illust/RecommendsPage.xaml.cs @@ -347,7 +347,7 @@ namespace Pixiview.Illust } } - public class IllustUserItem : BindableObject, IIllustUser + public class IllustUserItem : BindableObject, IIllustItem { //public static readonly BindableProperty Image1Property = BindableProperty.Create( // nameof(Image1), typeof(ImageSource), typeof(IllustUserItem)); @@ -371,5 +371,8 @@ namespace Pixiview.Illust public IllustItem Image2Item { get; set; } public IllustItem Image3Item { get; set; } public string ProfileUrl { get; set; } + + public bool IsFavorite { get; } + public string BookmarkId { get; } } } diff --git a/Pixiview/Illust/UserIllustPage.xaml.cs b/Pixiview/Illust/UserIllustPage.xaml.cs index e1b3f53..84f4d51 100644 --- a/Pixiview/Illust/UserIllustPage.xaml.cs +++ b/Pixiview/Illust/UserIllustPage.xaml.cs @@ -20,13 +20,13 @@ namespace Pixiview.Illust set => SetValue(UserIconProperty, value); } - public IIllustUser UserItem { get; } + public IIllustItem UserItem { get; } private int startIndex; private int nextIndex; private string[] illustIds; - public UserIllustPage(IIllustUser item) + public UserIllustPage(IIllustItem item) { UserItem = item; UserIcon = item.ProfileImage; diff --git a/Pixiview/Illust/ViewIllustPage.xaml.cs b/Pixiview/Illust/ViewIllustPage.xaml.cs index cc3e16f..fee41f4 100644 --- a/Pixiview/Illust/ViewIllustPage.xaml.cs +++ b/Pixiview/Illust/ViewIllustPage.xaml.cs @@ -528,6 +528,10 @@ namespace Pixiview.Illust { return; } + if (!add && string.IsNullOrEmpty(illust.BookmarkId)) + { + return; + } if (Configs.SyncFavType == SyncType.Prompt) { var ok = await DisplayAlert( @@ -551,11 +555,7 @@ namespace Pixiview.Illust } else { - var bookmarkId = illust.BookmarkId; - if (!string.IsNullOrEmpty(bookmarkId)) - { - _ = Task.Run(() => Stores.DeleteBookmark(bookmarkId)); - } + _ = Task.Run(() => Stores.DeleteBookmark(illust.BookmarkId)); } } diff --git a/Pixiview/UI/CardView.cs b/Pixiview/UI/CardView.cs index 1730b2f..5882178 100644 --- a/Pixiview/UI/CardView.cs +++ b/Pixiview/UI/CardView.cs @@ -44,7 +44,9 @@ namespace Pixiview.UI protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) { - if (BindingContext is IllustItem illust) + if (BindingContext is IllustItem illust && + illust.Width > 0 && + illust.ImageHeight.IsAuto) { illust.ImageHeight = widthConstraint * illust.Height / illust.Width; } diff --git a/Pixiview/UI/FlowLayout.cs b/Pixiview/UI/FlowLayout.cs index 164fd38..b70a4aa 100644 --- a/Pixiview/UI/FlowLayout.cs +++ b/Pixiview/UI/FlowLayout.cs @@ -245,7 +245,7 @@ namespace Pixiview.UI } freezed = false; UpdateChildrenLayout(); - InvalidateLayout(); + //InvalidateLayout(); } } diff --git a/Pixiview/UI/StyleDefinition.cs b/Pixiview/UI/StyleDefinition.cs index 9da44b2..9f155fc 100644 --- a/Pixiview/UI/StyleDefinition.cs +++ b/Pixiview/UI/StyleDefinition.cs @@ -40,6 +40,7 @@ namespace Pixiview.UI public const string IconLayer = "\uf302"; public const string IconRefresh = "\uf2f9"; public const string IconLove = "\uf004"; + public const string IconCircleLove = "\uf4c7"; public const string IconOption = "\uf013"; public const string IconFavorite = "\uf02e"; public const string IconShare = "\uf1e0"; diff --git a/Pixiview/Utils/Converters.cs b/Pixiview/Utils/Converters.cs index 079df06..58ea905 100644 --- a/Pixiview/Utils/Converters.cs +++ b/Pixiview/Utils/Converters.cs @@ -1,33 +1,18 @@ using System; using System.Globalization; +using Pixiview.Illust; using Pixiview.UI; using Xamarin.Forms; namespace Pixiview.Utils { - public class PageConverter : IValueConverter + public class FavoriteVisibleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return StyleDefinition.IconLayer + value; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } - - public class OffsetConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is Thickness thickness && parameter != null) + if (value is IIllustItem item) { - if (double.TryParse(parameter.ToString(), out var offset)) - { - return new Thickness(thickness.Left, thickness.Top + offset, thickness.Right, thickness.Bottom); - } + return item.IsFavorite || !string.IsNullOrEmpty(item.BookmarkId); } return value; } @@ -37,4 +22,31 @@ namespace Pixiview.Utils throw new NotImplementedException(); } } + + public class FavoriteIconConverter : IValueConverter + { + private readonly bool isFavorite; + + public FavoriteIconConverter(bool favorite) + { + isFavorite = favorite; + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is IIllustItem item) + { + var love = isFavorite ? StyleDefinition.IconLove : string.Empty; + return !string.IsNullOrEmpty(item.BookmarkId) ? + StyleDefinition.IconCircleLove : + love; + } + return string.Empty; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } } diff --git a/Pixiview/Utils/Extensions.cs b/Pixiview/Utils/Extensions.cs index fb982e2..4092843 100644 --- a/Pixiview/Utils/Extensions.cs +++ b/Pixiview/Utils/Extensions.cs @@ -7,7 +7,8 @@ namespace Pixiview.Utils { public static class Extensions { - public static T Binding(this T view, BindableProperty property, string name, BindingMode mode = BindingMode.Default) where T : BindableObject + public static T Binding(this T view, BindableProperty property, string name, + BindingMode mode = BindingMode.Default, IValueConverter converter = null) where T : BindableObject { if (name == null) { @@ -15,7 +16,7 @@ namespace Pixiview.Utils } else { - view.SetBinding(property, name, mode); + view.SetBinding(property, name, mode, converter); } return view; } diff --git a/Pixiview/Utils/IllustData.cs b/Pixiview/Utils/IllustData.cs index 6334658..da6a3f9 100644 --- a/Pixiview/Utils/IllustData.cs +++ b/Pixiview/Utils/IllustData.cs @@ -67,7 +67,6 @@ namespace Pixiview.Utils Id = illustId, BookmarkId = bookmarkData?.id, Title = illustTitle, - RankTitle = illustTitle, IllustType = (IllustType)illustType, Image = image, ImageUrl = urls?.x360 ?? url, @@ -188,7 +187,6 @@ namespace Pixiview.Utils { item.BookmarkId = bookmarkData?.id; item.Title = illustTitle; - item.RankTitle = illustTitle; item.IllustType = (IllustType)illustType; item.ImageUrl = urls?.regular; item.IsRestrict = xRestrict == 1; diff --git a/Pixiview/Utils/IllustLegacy.cs b/Pixiview/Utils/IllustLegacy.cs index 88f2ced..811afa8 100644 --- a/Pixiview/Utils/IllustLegacy.cs +++ b/Pixiview/Utils/IllustLegacy.cs @@ -98,7 +98,7 @@ namespace Pixiview.Utils Id = illust_id.ToString(), BookmarkId = bookmark_id, Title = title, - RankTitle = $"#{rank} {title}", + Rank = rank, IllustType = (IllustType)type, ImageUrl = url, IsRestrict = restrict, diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs index a735062..93db6e4 100644 --- a/Pixiview/Utils/Stores.cs +++ b/Pixiview/Utils/Stores.cs @@ -659,6 +659,12 @@ namespace Pixiview.Utils Changed = true; } + public new void InsertRange(int index, IEnumerable collection) + { + base.InsertRange(index, collection); + Changed = true; + } + public new void RemoveAt(int index) { base.RemoveAt(index); diff --git a/Pixiview/Utils/Ugoira.cs b/Pixiview/Utils/Ugoira.cs index e18c056..6b2c32b 100644 --- a/Pixiview/Utils/Ugoira.cs +++ b/Pixiview/Utils/Ugoira.cs @@ -41,45 +41,46 @@ namespace Pixiview.Utils detailItem = item; frames = new ImageSource[ugoira.frames.Length]; FrameCount = frames.Length; - timer = new Timer(OnTimerCallback, null, Timeout.Infinite, Timeout.Infinite); Task.Run(LoadFrames); } public void Dispose() + { + if (IsPlaying) + { + TogglePlay(false); + } + ClearTimer(); + } + + private void ClearTimer() { lock (sync) { - if (IsPlaying) + if (timer != null) { - TogglePlay(false); + timer.Dispose(); + timer = null; } } - if (timer != null) - { - timer.Dispose(); - timer = null; - } } public void TogglePlay(bool flag) { - lock (sync) + if (IsPlaying == flag) { - if (timer == null || IsPlaying == flag) - { - return; - } - if (flag) - { - IsPlaying = true; - timer.Change(0, Timeout.Infinite); - } - else - { - IsPlaying = false; - timer.Change(Timeout.Infinite, Timeout.Infinite); - } + return; + } + ClearTimer(); + if (flag) + { + timer = new Timer(OnTimerCallback, null, 0, Timeout.Infinite); + IsPlaying = true; + } + else + { + IsPlaying = false; } } @@ -122,6 +123,13 @@ namespace Pixiview.Utils var info = ugoira.frames[i]; while ((frame = frames[i]) == null) { + lock (sync) + { + if (timer == null) + { + return; + } + } // not downloaded yet, waiting... Thread.Sleep(DELAY); } @@ -137,12 +145,9 @@ namespace Pixiview.Utils i = 0; } index = i; - lock (sync) + if (timer != null && IsPlaying) { - if (timer != null && IsPlaying) - { - timer.Change(info.delay, Timeout.Infinite); - } + timer.Change(info.delay, Timeout.Infinite); } } @@ -297,9 +302,12 @@ namespace Pixiview.Utils var last = frame.Last; while (segs.AnyFor(first, last, s => !s.Done)) { - if (timer == null) + lock (sync) { - return; + if (timer == null) + { + return; + } } Thread.Sleep(DELAY); } @@ -456,6 +464,13 @@ namespace Pixiview.Utils var cgImage = images[i].CGImage; var width = cgImage.Width; var height = cgImage.Height; + //var scan = cgImage.BytesPerRow; + //var mod = scan % 16; + //if (mod > 0) + //{ + // App.DebugPrint($"add more {mod} bytes to align line from {scan} to {scan + mod}."); + // scan += mod; + //} using (CGBitmapContext bitmapContext = new CGBitmapContext( pxdata, width, height, cgImage.BitsPerComponent,