diff --git a/Pixiview.iOS/AppDelegate.cs b/Pixiview.iOS/AppDelegate.cs
index 47ab490..ce788b0 100644
--- a/Pixiview.iOS/AppDelegate.cs
+++ b/Pixiview.iOS/AppDelegate.cs
@@ -27,7 +27,7 @@ namespace Pixiview.iOS
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
App.DebugPrint($"url: {url}.");
- return App.OpenUrl(url.AbsoluteString);
+ return App.OpenUrl(url);
}
}
}
diff --git a/Pixiview.iOS/Info.plist b/Pixiview.iOS/Info.plist
index 3861c37..770a341 100644
--- a/Pixiview.iOS/Info.plist
+++ b/Pixiview.iOS/Info.plist
@@ -65,5 +65,20 @@
Assets.xcassets/AppIcon.appiconset/Icon58
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeName
+ Favorites Json
+ LSItemContentTypes
+
+ public.text
+
+ CFBundleTypeIconFiles
+
+ Assets.xcassets/AppIcon.appiconset/Icon180
+
+
+
diff --git a/Pixiview/App.cs b/Pixiview/App.cs
index f3f8b33..647835f 100644
--- a/Pixiview/App.cs
+++ b/Pixiview/App.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
+using System.Linq;
using System.Text.RegularExpressions;
using Pixiview.Illust;
using Pixiview.Resources;
@@ -123,24 +125,92 @@ namespace Pixiview
Debug.Fail(string.Format("[{0:HH:mm:ss.ffff}] - {1} - {2}", DateTime.Now, category, message));
}
- public static bool OpenUrl(string url)
+ public static bool OpenUrl(Uri uri)
{
var current = Current.MainPage;
- if (current != null)
+ if (current != null && uri != null)
{
- var m = Regex.Match(url, "/artworks/([0-9]+)", RegexOptions.IgnoreCase);
- if (m.Success)
+ var url = uri.AbsolutePath;
+ if (uri.Scheme == "pixiview://")
{
- var illust = new IllustItem { Id = m.Groups[1].Value };
- var page = new ViewIllustPage(illust, true);
- MainThread.BeginInvokeOnMainThread(() => current.Navigation.PushAsync(page));
+ var m = Regex.Match(url, "/artworks/([0-9]+)", RegexOptions.IgnoreCase);
+ if (m.Success)
+ {
+ var illust = new IllustItem { Id = m.Groups[1].Value };
+ var page = new ViewIllustPage(illust, true);
+ MainThread.BeginInvokeOnMainThread(() => current.Navigation.PushAsync(page));
+ }
+ else
+ {
+ MainThread.BeginInvokeOnMainThread(() => current.DisplayAlert(
+ url,
+ ResourceHelper.InvalidUrl,
+ ResourceHelper.Ok));
+ }
}
- else
+ else if (File.Exists(url))
{
- MainThread.BeginInvokeOnMainThread(() => current.DisplayAlert(
- url,
- ResourceHelper.InvalidUrl,
- ResourceHelper.Ok));
+ IllustFavorite favObj;
+ try
+ {
+ favObj = Stores.LoadFavoritesIllusts(url);
+ }
+ catch (Exception ex)
+ {
+ DebugError("open.file", $"failed to parse file, name: {url}, error: {ex.Message}");
+ return true;
+ }
+ var path = Stores.FavoritesPath;
+ if (File.Exists(path))
+ {
+ MainThread.BeginInvokeOnMainThread(async () =>
+ {
+ var opReplace = ResourceHelper.FavoritesReplace;
+ var opCombine = ResourceHelper.FavoritesCombine;
+ var result = await current.DisplayActionSheet(
+ ResourceHelper.FavoritesOperation,
+ ResourceHelper.Cancel,
+ opCombine,
+ opReplace);
+ if (result == opReplace)
+ {
+ // replace favorite file
+ File.Copy(url, path, true);
+ }
+ else if (result == opCombine)
+ {
+ // combine favorite file
+ var favNow = Stores.GetFavoriteObject();
+ var list = favObj.Illusts;
+ var distinct = favNow.Illusts.Where(f => !list.Any(i => i.Id == f.Id)).ToList();
+ list.AddRange(distinct);
+
+ favNow.Illusts = list;
+ Stores.SaveFavoritesIllusts();
+ }
+
+ if (Shell.Current.CurrentState.Location.OriginalString.EndsWith(Routes.Favorites))
+ {
+ var sc = (IShellSectionController)Shell.Current.CurrentItem.CurrentItem;
+ if (sc.PresentedPage is FavoritesPage fav)
+ {
+ fav.Reload(true);
+ }
+ }
+ });
+ }
+ else
+ {
+ File.Copy(url, path);
+ if (Shell.Current.CurrentState.Location.OriginalString.EndsWith(Routes.Favorites))
+ {
+ var sc = (IShellSectionController)Shell.Current.CurrentItem.CurrentItem;
+ if (sc.PresentedPage is FavoritesPage fav)
+ {
+ fav.Reload(true);
+ }
+ }
+ }
}
}
return true;
diff --git a/Pixiview/Illust/FavoritesPage.xaml b/Pixiview/Illust/FavoritesPage.xaml
index 878a84e..8bfd2c1 100644
--- a/Pixiview/Illust/FavoritesPage.xaml
+++ b/Pixiview/Illust/FavoritesPage.xaml
@@ -7,8 +7,12 @@
x:Class="Pixiview.Illust.FavoritesPage"
BackgroundColor="{DynamicResource WindowColor}"
Title="{r:Text Favorites}">
+
+
+
-
+
DoGetIllustList(IllustItem[] data, ICommand command)
@@ -37,12 +39,28 @@ namespace Pixiview.Illust
protected override IllustItem[] DoLoadIllustData(bool force)
{
- var favorites = Stores.FavoriteObject;
+ var favorites = Stores.GetFavoriteObject(force);
if (favorites == null)
{
return null;
}
return favorites.Illusts.ToArray();
}
+
+ public void Reload(bool force = false)
+ {
+ loaded = false;
+ StartLoad(force);
+ }
+
+ private async void ShareFavorites_Clicked(object sender, EventArgs e)
+ {
+ var file = Stores.FavoritesPath;
+ await Share.RequestAsync(new ShareFileRequest
+ {
+ Title = ResourceHelper.Favorites,
+ File = new ShareFile(file)
+ });
+ }
}
}
diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs
index 43ba8f5..f8e9237 100644
--- a/Pixiview/Illust/IllustCollectionPage.cs
+++ b/Pixiview/Illust/IllustCollectionPage.cs
@@ -121,7 +121,15 @@ namespace Pixiview.Illust
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
- var columns = width > height ? 4 : 2;
+ int columns;
+ if (isPhone)
+ {
+ columns = width > height ? 4 : 2;
+ }
+ else
+ {
+ columns = width > height ? 6 : 4;
+ }
if (Columns != columns)
{
Columns = columns;
@@ -341,7 +349,7 @@ namespace Pixiview.Illust
IsLoading = false;
return;
}
- if (force)
+ if (force && IsFavoriteVisible)
{
NeedUpdate = true;
}
diff --git a/Pixiview/Illust/MainPage.xaml b/Pixiview/Illust/MainPage.xaml
index 0005048..090e33b 100644
--- a/Pixiview/Illust/MainPage.xaml
+++ b/Pixiview/Illust/MainPage.xaml
@@ -12,7 +12,7 @@
IconImageSource="{DynamicResource FontIconRefresh}"/>
-
+
-
+
-
+
-
+
成功保存图片到照片库。
原图已保存,是否继续?
无法识别该 URL。
+ 请选择收藏夹操作
+ 替换
+ 合并
\ No newline at end of file
diff --git a/Pixiview/Resources/ResourceHelper.cs b/Pixiview/Resources/ResourceHelper.cs
index d4936d6..c7f4f19 100644
--- a/Pixiview/Resources/ResourceHelper.cs
+++ b/Pixiview/Resources/ResourceHelper.cs
@@ -23,6 +23,10 @@ namespace Pixiview.Resources
public static string SaveSuccess => GetResource(nameof(SaveSuccess));
public static string AlreadySavedQuestion => GetResource(nameof(AlreadySavedQuestion));
public static string InvalidUrl => GetResource(nameof(InvalidUrl));
+ public static string Favorites => GetResource(nameof(Favorites));
+ public static string FavoritesOperation => GetResource(nameof(FavoritesOperation));
+ public static string FavoritesReplace => GetResource(nameof(FavoritesReplace));
+ public static string FavoritesCombine => GetResource(nameof(FavoritesCombine));
static readonly Dictionary dict = new Dictionary();
diff --git a/Pixiview/UI/AdaptedPage.cs b/Pixiview/UI/AdaptedPage.cs
index abae771..c99ae0d 100644
--- a/Pixiview/UI/AdaptedPage.cs
+++ b/Pixiview/UI/AdaptedPage.cs
@@ -22,7 +22,7 @@ namespace Pixiview.UI
public event EventHandler Unload;
public event EventHandler OrientationChanged;
- protected readonly bool isPhone = DeviceInfo.Idiom == DeviceIdiom.Phone;
+ protected static readonly bool isPhone = DeviceInfo.Idiom == DeviceIdiom.Phone;
public AdaptedPage()
{
@@ -48,13 +48,13 @@ namespace Pixiview.UI
PageTopMargin = AppShell.TotalBarOffset;
break;
case Orientation.PortraitUpsideDown:
- PageTopMargin = isPhone ? AppShell.NavigationBarOffset : AppShell.TotalBarOffset;
- break;
+ //PageTopMargin = isPhone ? AppShell.NavigationBarOffset : AppShell.TotalBarOffset;
+ //break;
case Orientation.Unknown:
case Orientation.LandscapeLeft:
case Orientation.LandscapeRight:
default:
- PageTopMargin = AppShell.NavigationBarOffset;
+ PageTopMargin = isPhone ? AppShell.NavigationBarOffset : AppShell.TotalBarOffset;
break;
}
OrientationChanged?.Invoke(this, new OrientationEventArgs { CurrentOrientation = orientation });
diff --git a/Pixiview/UI/StyleDefinition.cs b/Pixiview/UI/StyleDefinition.cs
index 393cded..2cef140 100644
--- a/Pixiview/UI/StyleDefinition.cs
+++ b/Pixiview/UI/StyleDefinition.cs
@@ -29,6 +29,7 @@ namespace Pixiview.UI
public const string IconOption = "\uf013";
public const string IconDownload = "\uf019";
public const string IconFavorite = "\uf02e";
+ public const string IconShare = "\uf35d";
static StyleDefinition()
{
diff --git a/Pixiview/UI/Theme/ThemeBase.cs b/Pixiview/UI/Theme/ThemeBase.cs
index b344d0c..81721ac 100644
--- a/Pixiview/UI/Theme/ThemeBase.cs
+++ b/Pixiview/UI/Theme/ThemeBase.cs
@@ -13,6 +13,7 @@ namespace Pixiview.UI.Theme
public const string FontIconOption = nameof(FontIconOption);
public const string FontIconDownload = nameof(FontIconDownload);
public const string FontIconFavorite = nameof(FontIconFavorite);
+ public const string FontIconShare = nameof(FontIconShare);
public const string StatusBarStyle = nameof(StatusBarStyle);
public const string WindowColor = nameof(WindowColor);
@@ -68,6 +69,7 @@ namespace Pixiview.UI.Theme
Add(FontIconOption, GetSolidIcon(StyleDefinition.IconOption, solidFontFamily));
Add(FontIconDownload, GetSolidIcon(StyleDefinition.IconDownload, solidFontFamily));
Add(FontIconFavorite, GetSolidIcon(StyleDefinition.IconFavorite, solidFontFamily));
+ Add(FontIconShare, GetSolidIcon(StyleDefinition.IconShare, solidFontFamily));
}
private FontImageSource GetSolidIcon(string icon, string family, Color color = default)
diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs
index 5f584e9..f6de5b2 100644
--- a/Pixiview/Utils/Stores.cs
+++ b/Pixiview/Utils/Stores.cs
@@ -18,10 +18,10 @@ namespace Pixiview.Utils
public static readonly string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
public static readonly string CacheFolder = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
+ private const string favoriteFile = "favorites.json";
private const string imageFolder = "img-original";
private const string previewFolder = "img-master";
private const string illustFile = "illust.json";
- private const string favoriteFile = "favorites.json";
private const string pagesFolder = "pages";
private const string preloadsFolder = "preloads";
@@ -45,38 +45,40 @@ namespace Pixiview.Utils
}
}
+ public static List Favorites => GetFavoriteObject().Illusts;
+ public static string FavoritesPath => Path.Combine(PersonalFolder, favoriteFile);
+
private static IllustFavorite favoriteObject;
- public static IllustFavorite FavoriteObject
+
+ public static IllustFavorite GetFavoriteObject(bool force = false)
{
- get
+ lock (sync)
{
- lock (sync)
+ if (force || favoriteObject == null)
{
- if (favoriteObject == null)
+ var favorites = LoadFavoritesIllusts();
+ if (favorites != null)
{
- var favorites = LoadFavoritesIllusts();
- if (favorites != null)
- {
- favoriteObject = favorites;
- }
- else
- {
- favoriteObject = new IllustFavorite
- {
- Illusts = new List()
- };
- }
+ favoriteObject = favorites;
+ }
+ else
+ {
+ favoriteObject = new IllustFavorite
+ {
+ Illusts = new List()
+ };
}
- return favoriteObject;
}
+ return favoriteObject;
}
}
- public static List Favorites => FavoriteObject.Illusts;
-
- private static IllustFavorite LoadFavoritesIllusts()
+ public static IllustFavorite LoadFavoritesIllusts(string file = null)
{
- var file = Path.Combine(PersonalFolder, favoriteFile);
+ if (file == null)
+ {
+ file = FavoritesPath;
+ }
lock (sync)
{
return ReadObject(file);
@@ -85,10 +87,10 @@ namespace Pixiview.Utils
public static void SaveFavoritesIllusts()
{
- var file = Path.Combine(PersonalFolder, favoriteFile);
+ var file = FavoritesPath;
lock (sync)
{
- var data = FavoriteObject;
+ var data = GetFavoriteObject();
data.LastFavoriteUtc = DateTime.UtcNow;
WriteObject(file, data);
}
@@ -236,9 +238,9 @@ namespace Pixiview.Utils
Configs.UrlIllustList,
Configs.Referer,
force: force);
- if (result.error)
+ if (result == null || result.error)
{
- App.DebugPrint($"error when load illust data: {result.message} ({force})");
+ App.DebugPrint($"error when load illust data: {result?.message} ({force})");
}
return result;
}
@@ -276,9 +278,9 @@ namespace Pixiview.Utils
string.Format(Configs.UrlIllustPage, id),
string.Format(Configs.UrlIllust, id),
force: force);
- if (result.error)
+ if (result == null || result.error)
{
- App.DebugPrint($"error when load page data: {result.message} ({force})");
+ App.DebugPrint($"error when load page data: {result?.message} ({force})");
}
return result;
}
@@ -290,22 +292,22 @@ namespace Pixiview.Utils
string.Format(Configs.UrlIllustUserAll, userId),
string.Format(Configs.UrlIllustUser, userId),
force: force);
- if (list.error)
+ if (list == null || list.error)
{
- App.DebugPrint($"error when load user data: {list.message} ({force})");
+ App.DebugPrint($"error when load user data: {list?.message} ({force})");
}
// TODO
- var ids = string.Join("&ids%5B%5D=", list.body.illusts.Keys.Take(20));
+ var ids = string.Join("", list.body.illusts.Keys.Take(20).Select(id => $"ids%5B%5D={id}&"));
var result = LoadObject(
null,
string.Format(Configs.UrlIllustUserArtworks, userId, ids, 1),
string.Format(Configs.UrlIllustUser, userId),
force: force);
- if (result.error)
+ if (result == null || result.error)
{
- App.DebugPrint($"error when load user illust data: {result.message} ({force})");
+ App.DebugPrint($"error when load user illust data: {result?.message} ({force})");
}
return result;
}
@@ -451,20 +453,21 @@ namespace Pixiview.Utils
}
var client = new HttpClient(handler)
{
- BaseAddress = new Uri($"{uri.Scheme}://{uri.Host}")
+ BaseAddress = new Uri($"{uri.Scheme}://{uri.Host}"),
+ Timeout = TimeSpan.FromSeconds(30)
};
return TryCount(() =>
{
using (var request = new HttpRequestMessage(HttpMethod.Get, uri.PathAndQuery)
{
- Version = new Version(2, 0)
+ Version = new Version(2, 0),
})
{
var headers = request.Headers;
headerAction(headers);
headers.Add("accept-language", Configs.AcceptLanguage);
headers.Add("accept-encoding", Configs.AcceptEncoding);
- return client.SendAsync(request).Result;
+ return client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
}
});
}
@@ -485,7 +488,7 @@ namespace Pixiview.Utils
public const string SuffixPreload = " id=\"meta-preload-data\" content='";
public const int SuffixPreloadLength = 33; // SuffixPreload.Length
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 UrlIllustUserArtworks = "https://www.pixiv.net/ajax/user/{0}/profile/illusts?{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";