diff --git a/Pixiview.iOS/Renderers/AppShellRenderer.cs b/Pixiview.iOS/Renderers/AppShellRenderer.cs index 6575d51..786c4d7 100644 --- a/Pixiview.iOS/Renderers/AppShellRenderer.cs +++ b/Pixiview.iOS/Renderers/AppShellRenderer.cs @@ -51,6 +51,11 @@ namespace Pixiview.iOS.Renderers { return new AppShellTabBarAppearanceTracker(); } + + protected override void UpdateBackgroundColor() + { + NativeView.BackgroundColor = Color.Transparent.ToUIColor(); + } } public class AppShellItemTransition : IShellItemTransition diff --git a/Pixiview/AppShell.xaml b/Pixiview/AppShell.xaml index 1f8cfc5..84c31f8 100644 --- a/Pixiview/AppShell.xaml +++ b/Pixiview/AppShell.xaml @@ -10,7 +10,8 @@ BackgroundColor="{DynamicResource NavColor}" ForegroundColor="{DynamicResource TintColor}" TitleColor="{DynamicResource TextColor}" - UnselectedColor="{DynamicResource SubTextColor}"> + UnselectedColor="{DynamicResource SubTextColor}" + FlyoutBackgroundColor="{DynamicResource WindowColor}"> @@ -35,7 +36,12 @@ - + + + + + - + - + + + + + + + + + + + + + + + + + + diff --git a/Pixiview/Illust/UserIllustPage.xaml.cs b/Pixiview/Illust/UserIllustPage.xaml.cs new file mode 100644 index 0000000..7e33591 --- /dev/null +++ b/Pixiview/Illust/UserIllustPage.xaml.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Input; +using Pixiview.Utils; +using Xamarin.Forms; + +namespace Pixiview.Illust +{ + public partial class UserIllustPage : IllustUserDataCollectionPage + { + public static readonly BindableProperty UserIconProperty = BindableProperty.Create( + nameof(UserIcon), typeof(ImageSource), typeof(UserIllustPage)); + + public ImageSource UserIcon + { + get => (ImageSource)GetValue(UserIconProperty); + set => SetValue(UserIconProperty, value); + } + + public IllustItem IllustItem { get; } + + public UserIllustPage(IllustItem illust) + { + IllustItem = illust; + UserIcon = illust.ProfileImage; + + Resources.Add("cardView", GetCardViewTemplate(true)); + InitializeComponent(); + } + + protected override IEnumerable DoGetIllustList(IllustUserData data, ICommand command) + { + return data.body.works.Select(i => + { + var item = i.Value?.ConvertToItem(); + if (item != null) + { + item.IllustTapped = command; + } + return item; + }); + } + + protected override IllustUserData DoLoadIllustData(bool force) + { + return Stores.LoadIllustUserData(IllustItem.UserId, force); + } + + private void Refresh_Clicked(object sender, EventArgs e) + { + if (IsLoading) + { + return; + } + StartLoad(true); + } + } +} diff --git a/Pixiview/Illust/ViewIllustPage.xaml.cs b/Pixiview/Illust/ViewIllustPage.xaml.cs index ae2e794..ee75910 100644 --- a/Pixiview/Illust/ViewIllustPage.xaml.cs +++ b/Pixiview/Illust/ViewIllustPage.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; @@ -69,12 +70,9 @@ namespace Pixiview.Illust fontIconLove = (ImageSource)Application.Current.Resources[ThemeBase.FontIconLove]; fontIconNotLove = (ImageSource)Application.Current.Resources[ThemeBase.FontIconNotLove]; var favorites = Stores.Favorites; - if (favorites != null) - { - FavoriteIcon = favorites.Any(i => i.Id == illust.Id) - ? fontIconLove - : fontIconNotLove; - } + FavoriteIcon = favorites.Any(i => i.Id == illust.Id) + ? fontIconLove + : fontIconNotLove; InitializeComponent(); @@ -143,10 +141,11 @@ namespace Pixiview.Illust private void DoLoadImages() { - var pages = Stores.LoadIllustPageData(IllustItem.Id); + var illustItem = IllustItem; + var pages = Stores.LoadIllustPageData(illustItem.Id); if (pages == null) { - App.DebugError("illustPage.load", $"failed to load illust page data, id: {IllustItem.Id}"); + App.DebugError("illustPage.load", $"failed to load illust page data, id: {illustItem.Id}"); return; } var items = Illusts; @@ -174,6 +173,11 @@ namespace Pixiview.Illust } DoLoadImage(0, true); + var image = items[0].Image; + if (image != null) + { + illustItem.Image = image; + } if (items.Length > 1) { DoLoadImage(1); @@ -233,10 +237,6 @@ namespace Pixiview.Illust private void Favorite_Clicked(object sender, EventArgs e) { var favorites = Stores.Favorites; - if (favorites == null) - { - return; - } var illust = IllustItem; var index = favorites.FindIndex(i => i.Id == illust.Id); if (index < 0) @@ -255,23 +255,23 @@ namespace Pixiview.Illust private async void Illust_LongPressed(IllustDetailItem item) { + List extras = new List(); var share = ResourceHelper.Share; - string[] extras; var preview = Stores.GetPreviewImagePath(item.PreviewUrl); - if (string.IsNullOrEmpty(preview)) + if (preview != null) { - extras = new string[0]; - } - else - { - extras = new[] { share }; + extras.Add(share); } var saveOriginal = ResourceHelper.SaveOriginal; + var userDetail = ResourceHelper.UserDetail; + extras.Add(userDetail); + + var illustItem = IllustItem; var result = await DisplayActionSheet( - IllustItem.Title, + illustItem.Title, ResourceHelper.Cancel, saveOriginal, - extras); + extras.ToArray()); if (result == saveOriginal) { SaveOriginalImage(item); @@ -280,10 +280,15 @@ namespace Pixiview.Illust { await Share.RequestAsync(new ShareFileRequest { - Title = IllustItem.Title, + Title = illustItem.Title, File = new ShareFile(preview) }); } + else if (result == userDetail) + { + var page = new UserIllustPage(illustItem); + await Navigation.PushAsync(page); + } } private async void SaveOriginalImage(IllustDetailItem item) diff --git a/Pixiview/Resources/Languages/zh-CN.xml b/Pixiview/Resources/Languages/zh-CN.xml index 5b2bb75..5bf800d 100644 --- a/Pixiview/Resources/Languages/zh-CN.xml +++ b/Pixiview/Resources/Languages/zh-CN.xml @@ -17,6 +17,7 @@ 操作 保存原图 分享 + 浏览用户 成功保存图片到照片库。 原图已保存,是否继续? \ No newline at end of file diff --git a/Pixiview/Resources/ResourceHelper.cs b/Pixiview/Resources/ResourceHelper.cs index f51db73..28b0b1f 100644 --- a/Pixiview/Resources/ResourceHelper.cs +++ b/Pixiview/Resources/ResourceHelper.cs @@ -19,6 +19,7 @@ namespace Pixiview.Resources public static string Operation => GetResource(nameof(Operation)); public static string SaveOriginal => GetResource(nameof(SaveOriginal)); public static string Share => GetResource(nameof(Share)); + public static string UserDetail => GetResource(nameof(UserDetail)); public static string SaveSuccess => GetResource(nameof(SaveSuccess)); public static string AlreadySavedQuestion => GetResource(nameof(AlreadySavedQuestion)); diff --git a/Pixiview/UI/Theme/LightTheme.cs b/Pixiview/UI/Theme/LightTheme.cs index cc67833..54ada22 100644 --- a/Pixiview/UI/Theme/LightTheme.cs +++ b/Pixiview/UI/Theme/LightTheme.cs @@ -32,7 +32,7 @@ namespace Pixiview.UI.Theme Add(TintColor, Color.FromRgb(0x00, 0x96, 0xfa)); // 0x7f, 0x99, 0xc6 Add(TextColor, Color.Black); Add(SubTextColor, Color.DimGray); - Add(CardBackgroundColor, Color.FromRgb(0xfa, 0xfa, 0xf0)); + Add(CardBackgroundColor, Color.FromRgb(0xf0, 0xf3, 0xf3)); Add(MaskColor, Color.FromRgba(0, 0, 0, 0x50)); Add(NavColor, Color.FromRgb(0xf0, 0xf0, 0xf0)); Add(NavSelectedColor, Color.LightGray); diff --git a/Pixiview/UI/Theme/ThemeBase.cs b/Pixiview/UI/Theme/ThemeBase.cs index 3c8a634..56f757a 100644 --- a/Pixiview/UI/Theme/ThemeBase.cs +++ b/Pixiview/UI/Theme/ThemeBase.cs @@ -2,7 +2,7 @@ namespace Pixiview.UI.Theme { - public class ThemeBase : ResourceDictionary + public abstract class ThemeBase : ResourceDictionary { public const string FontIconUser = nameof(FontIconUser); public const string FontIconSparkles = nameof(FontIconSparkles); @@ -55,22 +55,21 @@ namespace Pixiview.UI.Theme } } - var tintColor = (Color)this[TextColor]; var regularFontFamily = (string)this[IconRegularFontFamily]; var solidFontFamily = (string)this[IconSolidFontFamily]; - Add(FontIconUser, GetSolidIcon(StyleDefinition.IconUser, solidFontFamily, tintColor)); - Add(FontIconSparkles, GetSolidIcon(StyleDefinition.IconSparkles, solidFontFamily, tintColor)); - Add(FontIconOrder, GetSolidIcon(StyleDefinition.IconOrder, solidFontFamily, tintColor)); - Add(FontIconRefresh, GetSolidIcon(StyleDefinition.IconRefresh, solidFontFamily, tintColor)); Add(FontIconLove, GetSolidIcon(StyleDefinition.IconLove, solidFontFamily, StyleDefinition.ColorRedBackground)); - Add(FontIconNotLove, GetSolidIcon(StyleDefinition.IconLove, regularFontFamily, tintColor)); - Add(FontIconOption, GetSolidIcon(StyleDefinition.IconOption, solidFontFamily, tintColor)); - Add(FontIconDownload, GetSolidIcon(StyleDefinition.IconDownload, solidFontFamily, tintColor)); - Add(FontIconFavorite, GetSolidIcon(StyleDefinition.IconFavorite, solidFontFamily, tintColor)); + Add(FontIconUser, GetSolidIcon(StyleDefinition.IconUser, solidFontFamily)); + Add(FontIconSparkles, GetSolidIcon(StyleDefinition.IconSparkles, solidFontFamily)); + Add(FontIconOrder, GetSolidIcon(StyleDefinition.IconOrder, solidFontFamily)); + Add(FontIconRefresh, GetSolidIcon(StyleDefinition.IconRefresh, solidFontFamily)); + Add(FontIconNotLove, GetSolidIcon(StyleDefinition.IconLove, regularFontFamily)); + Add(FontIconOption, GetSolidIcon(StyleDefinition.IconOption, solidFontFamily)); + Add(FontIconDownload, GetSolidIcon(StyleDefinition.IconDownload, solidFontFamily)); + Add(FontIconFavorite, GetSolidIcon(StyleDefinition.IconFavorite, solidFontFamily)); } - private FontImageSource GetSolidIcon(string icon, string family, Color color) + private FontImageSource GetSolidIcon(string icon, string family, Color color = default) { return new FontImageSource { diff --git a/Pixiview/Utils/IllustData.cs b/Pixiview/Utils/IllustData.cs index 8195602..0be7284 100644 --- a/Pixiview/Utils/IllustData.cs +++ b/Pixiview/Utils/IllustData.cs @@ -1,148 +1,156 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; using Pixiview.Illust; namespace Pixiview.Utils { - public class IllustData + public class IllustResponse { public bool error; public string message; - public Body body; + public T body; + } - public class Body + public class Illust + { + public string illustId; + public string illustTitle; + public string id; + public string title; + public string url; + public string description; + public string[] tags; + public string userId; + public string userName; + public int width; + public int height; + public int pageCount; + public string alt; + public IllustUrls urls; + public string seriesId; + public string seriesTitle; + public string profileImageUrl; + public int xRestrict; + + public class IllustUrls { - public Page page; - public Thumbnail thumbnails; - public User[] users; + [JsonProperty("250x250")] + public string x250; + [JsonProperty("360x360")] + public string x360; + [JsonProperty("540x540")] + public string x540; + } - public class Page + public IllustItem ConvertToItem() + { + return new IllustItem { - public int[] follow; - public string[] recommend; - public RecommendByTag[] recommendByTags; - public Ranking ranking; - public RecommendUser[] recommendUser; - public EditorRecommend[] editorRecommend; - public string[] newPost; - - public class RecommendByTag - { - public string tag; - public string[] ids; - } - - public class Ranking - { - public RankingItem[] items; - public string date; - - public class RankingItem - { - public string rank; - public string id; - } - } - - public class RecommendUser - { - public int id; - public string[] illustIds; - } - - public class EditorRecommend - { - public string illustId; - public string comment; - } - } - - public class Thumbnail - { - public Illust[] illust; - - public class Illust - { - public string illustId; - public string illustTitle; - public string id; - public string title; - public string url; - public string description; - public string[] tags; - public string userId; - public string userName; - public int width; - public int height; - public int pageCount; - public string alt; - public IllustUrls urls; - public string seriesId; - public string seriesTitle; - public string profileImageUrl; - public int xRestrict; - - public class IllustUrls - { - [JsonProperty("250x250")] - public string x250; - [JsonProperty("360x360")] - public string x360; - [JsonProperty("540x540")] - public string x540; - } - - public IllustItem ConvertToItem() - { - return new IllustItem - { - Id = illustId, - ImageUrl = urls.x360 ?? url, - Title = illustTitle, - IsRestrict = xRestrict == 1, - ProfileUrl = profileImageUrl, - UserId = userId, - UserName = userName, - Width = width, - Height = height, - PageCount = pageCount - }; - } - } - } - - public class User - { - public string userId; - public string name; - public string image; - public string imageBig; - public bool premium; - public bool isFollowed; - public string background; - public int partial; - } + Id = illustId, + ImageUrl = urls?.x360 ?? url, + Title = illustTitle, + IsRestrict = xRestrict == 1, + ProfileUrl = profileImageUrl, + UserId = userId, + UserName = userName, + Width = width, + Height = height, + PageCount = pageCount + }; } } - public class IllustPageData + public class IllustData : IllustResponse { } + public class IllustBody { - public bool error; - public string message; - public Body[] body; + public Page page; + public Thumbnail thumbnails; + public User[] users; - public class Body + public class Page { - public Urls urls; - public int width; - public int height; + public int[] follow; + public string[] recommend; + public RecommendByTag[] recommendByTags; + public Ranking ranking; + public RecommendUser[] recommendUser; + public EditorRecommend[] editorRecommend; + public string[] newPost; - public class Urls + public class RecommendByTag { - public string thumb_mini; - public string small; - public string regular; - public string original; + public string tag; + public string[] ids; + } + + public class Ranking + { + public RankingItem[] items; + public string date; + + public class RankingItem + { + public string rank; + public string id; + } + } + + public class RecommendUser + { + public int id; + public string[] illustIds; + } + + public class EditorRecommend + { + public string illustId; + public string comment; } } + + public class Thumbnail + { + public Illust[] illust; + } + + public class User + { + public string userId; + public string name; + public string image; + public string imageBig; + public bool premium; + public bool isFollowed; + public string background; + public int partial; + } + } + + public class IllustPageData : IllustResponse { } + public class IllustPageBody + { + public Urls urls; + public int width; + public int height; + + public class Urls + { + public string thumb_mini; + public string small; + public string regular; + public string original; + } + } + + public class IllustUserListData : IllustResponse { } + public class IllustUserListBody + { + public Dictionary illusts; + } + + public class IllustUserData : IllustResponse { } + public class IllustUserBody + { + public Dictionary works; } } diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs index 30e7ec6..a7d4c61 100644 --- a/Pixiview/Utils/Stores.cs +++ b/Pixiview/Utils/Stores.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -58,6 +59,13 @@ namespace Pixiview.Utils { favoriteObject = favorites; } + else + { + favoriteObject = new IllustFavorite + { + Illusts = new List() + }; + } } return favoriteObject; } @@ -89,7 +97,7 @@ namespace Pixiview.Utils private static T LoadObject(string file, string url, string referer = null, bool force = false) { string content = null; - if (!force && File.Exists(file)) + if (!force && file != null && File.Exists(file)) { try { @@ -117,18 +125,21 @@ namespace Pixiview.Utils using (response) { content = response.Content.ReadAsStringAsync().Result; - try + if (file != null) { - var folder = Path.GetDirectoryName(file); - if (!Directory.Exists(folder)) + try { - Directory.CreateDirectory(folder); + var folder = Path.GetDirectoryName(file); + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + File.WriteAllText(file, content, Encoding.UTF8); + } + catch (Exception ex) + { + App.DebugError("save", $"failed to save illust JSON object, error: {ex.Message}"); } - File.WriteAllText(file, content, Encoding.UTF8); - } - catch (Exception ex) - { - App.DebugError("save", $"failed to save illust JSON object, error: {ex.Message}"); } } } @@ -222,14 +233,32 @@ namespace Pixiview.Utils return result; } + public static IllustUserData LoadIllustUserData(string userId, bool force = false) + { + var list = LoadObject( + null, + string.Format(Configs.UrlIllustUserAll, userId), + string.Format(Configs.UrlIllustUser, userId), + force: force); + + var ids = string.Join("&ids%5B%5D=", list.body.illusts.Keys.Take(20)); + + var result = LoadObject( + null, + string.Format(Configs.UrlIllustUserArtworks, userId, ids, 1), + string.Format(Configs.UrlIllustUser, userId), + force: force); + return result; + } + public static ImageSource LoadIllustImage(string url) { return LoadImage(url, PersonalFolder, imageFolder); } - public static ImageSource LoadPreviewImage(string url) + public static ImageSource LoadPreviewImage(string url, bool downloading = true) { - return LoadImage(url, PersonalFolder, previewFolder); + return LoadImage(url, PersonalFolder, previewFolder, downloading); } public static ImageSource LoadThumbnailImage(string url) @@ -258,7 +287,7 @@ namespace Pixiview.Utils return null; } - private static ImageSource LoadImage(string url, string working, string folder) + private static ImageSource LoadImage(string url, string working, string folder, bool downloading = true) { var file = Path.Combine(working, folder, Path.GetFileName(url)); ImageSource image; @@ -278,7 +307,7 @@ namespace Pixiview.Utils { image = null; } - if (image == null) + if (downloading && image == null) { file = DownloadImage(url, working, folder); if (file != null) @@ -386,6 +415,9 @@ namespace Pixiview.Utils public const int MaxThreads = 3; public const string UrlIllustList = "https://www.pixiv.net/ajax/top/illust?mode=all&lang=zh"; public const string UrlIllust = "https://www.pixiv.net/artworks/{0}"; + public const string UrlIllustUserAll = "https://www.pixiv.net/ajax/user/{0}/profile/all?lang=zh"; + public const string UrlIllustUserArtworks = "https://www.pixiv.net/ajax/user/{0}/profile/illusts?ids%5B%5D={1}&work_category=illustManga&is_first_page={2}&lang=zh"; + public const string UrlIllustUser = "https://www.pixiv.net/users/{0}/artworks"; public const string UrlIllustPage = "https://www.pixiv.net/ajax/illust/{0}/pages?lang=zh"; public const string UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; public const string AcceptImage = "image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5";