diff --git a/Pixiview/Illust/RecommendsPage.xaml b/Pixiview/Illust/RecommendsPage.xaml index f11fa82..ecf6382 100644 --- a/Pixiview/Illust/RecommendsPage.xaml +++ b/Pixiview/Illust/RecommendsPage.xaml @@ -13,25 +13,17 @@ </ContentPage.ToolbarItems> <Grid> <ScrollView HorizontalOptions="Fill" HorizontalScrollBarVisibility="Never"> - - <u:FlowLayout ItemsSource="{Binding Illusts}" - HorizontalOptions="Fill" Column="{Binding Columns}" - Margin="16" RowSpacing="16" ColumnSpacing="16" - ItemTemplate="{StaticResource cardView}"/> + <StackLayout> + <u:FlowLayout ItemsSource="{Binding Users}" + HorizontalOptions="Fill" Column="{Binding UserColumns}" + Margin="16" RowSpacing="16" + ItemTemplate="{StaticResource userCardView}"/> + <u:FlowLayout ItemsSource="{Binding Illusts}" + HorizontalOptions="Fill" Column="{Binding Columns}" + Margin="16" RowSpacing="16" ColumnSpacing="16" + ItemTemplate="{StaticResource cardView}"/> + </StackLayout> </ScrollView> - <!--<Grid Margin="0, -40, 0, 0" VerticalOptions="Start" HeightRequest="40"> - <u:SegmentedControl VerticalOptions="Center" HorizontalOptions="Center" - HeightRequest="30" - BackgroundColor="{DynamicResource WindowColor}" - TintColor="{DynamicResource SubTextColor}" - SelectedTextColor="{DynamicResource TextColor}" - SelectedSegmentIndex="{Binding SegmentIndex, Mode=TwoWay}"> - <u:SegmentedControl.Children> - <u:SegmentedControlOption Text="{r:Text Recommends}"/> - <u:SegmentedControlOption Text="{r:Text ByUser}"/> - </u:SegmentedControl.Children> - </u:SegmentedControl> - </Grid>--> <Frame HasShadow="False" Margin="0" Padding="20" CornerRadius="8" IsVisible="{Binding IsLoading}" HorizontalOptions="Center" VerticalOptions="Center" diff --git a/Pixiview/Illust/RecommendsPage.xaml.cs b/Pixiview/Illust/RecommendsPage.xaml.cs index f87c1a5..71abb67 100644 --- a/Pixiview/Illust/RecommendsPage.xaml.cs +++ b/Pixiview/Illust/RecommendsPage.xaml.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using System.Windows.Input; +using Pixiview.UI; +using Pixiview.UI.Theme; using Pixiview.Utils; using Xamarin.Forms; @@ -10,64 +11,274 @@ namespace Pixiview.Illust { public partial class RecommendsPage : IllustDataCollectionPage { - public static readonly BindableProperty SegmentIndexProperty = BindableProperty.Create( - nameof(SegmentIndex), typeof(int), typeof(RecommendsPage), propertyChanged: OnSegmentIndexPropertyChanged); + public static readonly BindableProperty UsersProperty = BindableProperty.Create( + nameof(Users), typeof(List<IllustUserItem>), typeof(RecommendsPage)); + public static readonly BindableProperty UserColumnsProperty = BindableProperty.Create( + nameof(UserColumns), typeof(int), typeof(RecommendsPage), 1); - private static void OnSegmentIndexPropertyChanged(BindableObject obj, object oldValue, object newValue) + public List<IllustUserItem> Users { - var page = (RecommendsPage)obj; - Task.Run(() => page.DoLoadIllusts()); + get => (List<IllustUserItem>)GetValue(UsersProperty); + set => SetValue(UsersProperty, value); + } + public int UserColumns + { + get => (int)GetValue(UserColumnsProperty); + set => SetValue(UserColumnsProperty, value); } - public int SegmentIndex - { - get => (int)GetValue(SegmentIndexProperty); - set => SetValue(SegmentIndexProperty, value); - } + private readonly Command<IllustUserItem> commandUserTapped; public RecommendsPage() { Resources.Add("cardView", GetCardViewTemplate()); + Resources.Add("userCardView", GetUserCardViewTemplate()); InitializeComponent(); + + commandUserTapped = new Command<IllustUserItem>(OnIllustUserItemTapped); } - protected override IEnumerable<IllustItem> DoGetIllustList(IllustData data, ICommand command) + private void OnIllustUserItemTapped(IllustUserItem item) { - if (SegmentIndex == 1) + Start(async () => { - // by user - return data.body.page.recommendUser.SelectMany(i => i.illustIds) - .Select(id => - { - var item = data.body.thumbnails.illust.FirstOrDefault(l => l.illustId == id)?.ConvertToItem(); - if (item != null) - { - item.IllustTapped = command; - } - return item; - }); + var page = new UserIllustPage(item); + await Navigation.PushAsync(page); + }); + } + + private Image GetUserCardViewImage(int column, CornerMask masks, string source, string parameter) + { + Image image; + if (masks == CornerMask.None) + { + image = new Image(); } else { - // recommends - return data.body.page.recommend.Select(id => + image = new RoundImage { - var item = data.body.thumbnails.illust.FirstOrDefault(l => l.illustId == id)?.ConvertToItem(); - if (item != null) - { - item.IllustTapped = command; - } - return item; - }); + CornerRadius = 10, + CornerMasks = masks + }; } + image.HorizontalOptions = LayoutOptions.Fill; + image.Aspect = Aspect.AspectFill; + image.GestureRecognizers.Add(new TapGestureRecognizer + { + Command = commandIllustImageTapped + } + .Binding(TapGestureRecognizer.CommandParameterProperty, parameter)); + image.SetBinding(Image.SourceProperty, source); + if (column > 0) + { + Grid.SetColumn(image, column); + } + Grid.SetRow(image, 1); + return image; + } + + private DataTemplate GetUserCardViewTemplate() + { + return new DataTemplate(() => + { + return new Grid + { + RowSpacing = 0, + RowDefinitions = + { + new RowDefinition { Height = 40 }, + new RowDefinition { Height = 120 } + }, + ColumnDefinitions = + { + new ColumnDefinition(), + new ColumnDefinition(), + new ColumnDefinition() + }, + Children = + { + // stacklayout: user + new Grid + { + ColumnDefinitions = + { + new ColumnDefinition { Width = 30 }, + new ColumnDefinition() + }, + Padding = new Thickness(8, 0, 8, 8), + Children = + { + // user icon + new CircleImage + { + WidthRequest = 30, + HeightRequest = 30, + Aspect = Aspect.AspectFill + } + .Binding(Image.SourceProperty, nameof(IllustUserItem.ProfileImage)), + + // user name + new Label + { + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.Center, + LineBreakMode = LineBreakMode.TailTruncation, + FontSize = StyleDefinition.FontSizeSmall + } + .Binding(Label.TextProperty, nameof(IllustUserItem.UserName)) + .DynamicResource(Label.TextColorProperty, ThemeBase.SubTextColor) + .GridColumn(1), + }, + GestureRecognizers = + { + new TapGestureRecognizer + { + Command = commandUserTapped + } + .Binding(TapGestureRecognizer.CommandParameterProperty, ".") + } + } + .GridColumnSpan(3), + + GetUserCardViewImage(0, CornerMask.Left, + $"{nameof(IllustUserItem.Image1Item)}.{nameof(IllustItem.Image)}", + nameof(IllustUserItem.Image1Item)), + + GetUserCardViewImage(1, CornerMask.None, + $"{nameof(IllustUserItem.Image2Item)}.{nameof(IllustItem.Image)}", + nameof(IllustUserItem.Image2Item)), + + GetUserCardViewImage(2, CornerMask.Right, + $"{nameof(IllustUserItem.Image3Item)}.{nameof(IllustItem.Image)}", + nameof(IllustUserItem.Image3Item)) + } + }; + }); + } + + protected override void OnSizeAllocated(double width, double height) + { + base.OnSizeAllocated(width, height); + int columns; + if (width > height) + { + columns = isPhone ? 2 : 3; + } + else + { + columns = isPhone ? 1 : 2; + } + if (UserColumns != columns) + { + UserColumns = columns; + App.DebugPrint($"change user columns to {columns}"); + } + } + + protected override void DoIllustsLoaded(IllustCollection collection) + { + IllustCollection = collection; + } + + protected override IEnumerable<IllustItem> DoGetIllustList(IllustData data) + { + return data.body.page.recommend.Select(id => + data.body.thumbnails.illust.FirstOrDefault(l => l.illustId == id)?.ConvertToItem()); } protected override IllustData DoLoadIllustData(bool force) { var illustData = Stores.LoadIllustData(force); + Task.Run(() => DoLoadUserRecommendsData(illustData)); return illustData; } + private void DoLoadUserRecommendsData(IllustData data) + { + var defaultImage = StyleDefinition.DownloadBackground; + var users = data.body.page.recommendUser.Select(u => + { + var usrId = u.id.ToString(); + var usr = data.body.users.FirstOrDefault(r => r.userId == usrId); + if (usr == null) + { + return null; + } + IllustItem item1 = null, item2 = null, item3 = null; + if (u.illustIds != null) + { + var length = u.illustIds.Length; + if (length > 0) + { + var id = u.illustIds[0]; + item1 = data.body.thumbnails.illust.FirstOrDefault(l => l.illustId == id)?.ConvertToItem(defaultImage); + } + if (length > 1) + { + var id = u.illustIds[1]; + item2 = data.body.thumbnails.illust.FirstOrDefault(l => l.illustId == id)?.ConvertToItem(defaultImage); + } + if (length > 2) + { + var id = u.illustIds[2]; + item3 = data.body.thumbnails.illust.FirstOrDefault(l => l.illustId == id)?.ConvertToItem(defaultImage); + } + } + return new IllustUserItem + { + UserId = usrId, + UserName = usr.name, + ProfileUrl = usr.image, + Image1Item = item1, + Image2Item = item2, + Image3Item = item3 + }; + }); + + var list = new List<IllustUserItem>(users); + Users = list; + Illusts = IllustCollection; + + DoLoadUserRecommendsImages(list); + } + + private void DoLoadUserRecommendsImages(List<IllustUserItem> users) + { + foreach (var user in users) + { + if (user.ProfileUrl != null) + { + var userImage = Stores.LoadUserProfileImage(user.ProfileUrl); + if (userImage != null) + { + user.ProfileImage = userImage; + } + } + Task.WaitAll( + Task.Run(() => DoLoadUserRecommendsImage(user.Image1Item)), + Task.Run(() => DoLoadUserRecommendsImage(user.Image2Item)), + Task.Run(() => DoLoadUserRecommendsImage(user.Image3Item))); + } + } + + private void DoLoadUserRecommendsImage(IllustItem illust) + { + if (illust.ImageUrl != null) + { + var url = Configs.GetThumbnailUrl(illust.ImageUrl); + var image = Stores.LoadPreviewImage(url, false); + if (image == null) + { + image = Stores.LoadThumbnailImage(url); + } + if (image != null) + { + illust.Image = image; + } + } + } + private void Refresh_Clicked(object sender, EventArgs e) { if (IsLoading) @@ -77,4 +288,30 @@ namespace Pixiview.Illust StartLoad(true); } } + + public class IllustUserItem : BindableObject, IIllustUser + { + //public static readonly BindableProperty Image1Property = BindableProperty.Create( + // nameof(Image1), typeof(ImageSource), typeof(IllustUserItem)); + public static readonly BindableProperty ProfileImageProperty = BindableProperty.Create( + nameof(ProfileImage), typeof(ImageSource), typeof(IllustUserItem)); + + //public ImageSource Image1 + //{ + // get => (ImageSource)GetValue(Image1Property); + // set => SetValue(Image1Property, value); + //} + public ImageSource ProfileImage + { + get => (ImageSource)GetValue(ProfileImageProperty); + set => SetValue(ProfileImageProperty, value); + } + + public string UserId { get; set; } + public string UserName { get; set; } + public IllustItem Image1Item { get; set; } + public IllustItem Image2Item { get; set; } + public IllustItem Image3Item { get; set; } + public string ProfileUrl { get; set; } + } }