using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Gallery.UI; using Gallery.UI.Theme; using Gallery.Utils; using Xamarin.Forms; namespace Gallery.Illust { public partial class RecommendsPage : IllustDataCollectionPage { public static readonly BindableProperty UsersProperty = BindableProperty.Create( nameof(Users), typeof(List), typeof(RecommendsPage)); public static readonly BindableProperty UserColumnsProperty = BindableProperty.Create( nameof(UserColumns), typeof(int), typeof(RecommendsPage), 1); public static readonly BindableProperty UserRecommendsVisibleProperty = BindableProperty.Create( nameof(UserRecommendsVisible), typeof(bool), typeof(RecommendsPage)); public List Users { get => (List)GetValue(UsersProperty); set => SetValue(UsersProperty, value); } public int UserColumns { get => (int)GetValue(UserColumnsProperty); set => SetValue(UserColumnsProperty, value); } public bool UserRecommendsVisible { get => (bool)GetValue(UserRecommendsVisibleProperty); set => SetValue(UserRecommendsVisibleProperty, value); } private IllustData illustData; public RecommendsPage() { Resources.Add("cardView", GetCardViewTemplate()); Resources.Add("userCardView", GetUserCardViewTemplate()); InitializeComponent(); } protected override bool NeedCookie => true; protected override ActivityIndicator LoadingIndicator => activityLoading; public override void OnUnload() { base.OnUnload(); Users = null; } private Image GetUserCardViewImage(int column, CornerMask masks, string source, string parameter) { Image image; if (masks == CornerMask.None) { image = new Image(); } else { image = new RoundImage { 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, ColumnSpacing = 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; #if DEBUG App.DebugPrint($"change user columns to {columns}"); #endif } } protected override void DoIllustsLoaded(IllustCollection collection, bool bottom) { //IsLoading = false; if (illustData != null) { IllustCollection = collection; Task.Run(() => DoLoadUserRecommendsData(illustData)); } else { base.DoIllustsLoaded(collection, bottom); } } protected override IEnumerable DoGetIllustList(IllustData data, out int tag) { tag = 0; if (data.body == null) { return null; } return data.body.page.recommend.ids.Select(id => data.body.thumbnails.illust.FirstOrDefault(l => (l.illustId ?? l.id) == id)?.ConvertToItem()); } protected override IllustData DoLoadIllustData(bool force) { illustData = Stores.LoadIllustData(force); return illustData; } private void DoLoadUserRecommendsData(IllustData data) { var r18 = Configs.IsOnR18; 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 ?? l.id) == id)?.ConvertToItem(defaultImage); } if (length > 1) { var id = u.illustIds[1]; item2 = data.body.thumbnails.illust.FirstOrDefault(l => (l.illustId ?? l.id) == id)?.ConvertToItem(defaultImage); } if (length > 2) { var id = u.illustIds[2]; item3 = data.body.thumbnails.illust.FirstOrDefault(l => (l.illustId ?? l.id) == id)?.ConvertToItem(defaultImage); } } if (!r18) { if (item1?.IsRestrict == true || item2?.IsRestrict == true || item3?.IsRestrict == true) { return null; } } return new IllustUserItem { UserId = usrId, UserName = usr.name, ProfileUrl = usr.image, Image1Item = item1, Image2Item = item2, Image3Item = item3 }; }).Where(u => u != null); var list = new List(users); activityLoading.Animate("margin", top => { activityLoading.Margin = new Thickness(0, top, 0, 0); }, 16, -40, easing: Easing.CubicIn, finished: (v, r) => { IsLoading = false; UserRecommendsVisible = list.Count > 0; #if __IOS__ Device.StartTimer(TimeSpan.FromMilliseconds(48), () => #else Device.StartTimer(TimeSpan.FromMilliseconds(150), () => #endif { Users = list; Illusts = IllustCollection; return false; }); }); DoLoadUserRecommendsImages(list); } private void DoLoadUserRecommendsImages(List users) { foreach (var user in users) { if (user.ProfileUrl != null) { var userImage = Stores.LoadUserProfileImage(user.ProfileUrl, true); 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, true); } if (image != null) { illust.Image = image; } } } private async void Refresh_Clicked(object sender, EventArgs e) { if (IsLoading) { return; } await ScrollToTopAsync(scrollView); StartLoad(true); } } public class IllustUserItem : BindableObject, IIllustItem { //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; } public bool IsFavorite { get; } public string BookmarkId { get; } } }