diff --git a/Pixiview.iOS/Pixiview.iOS.csproj b/Pixiview.iOS/Pixiview.iOS.csproj
index b4a394a..35d2c29 100644
--- a/Pixiview.iOS/Pixiview.iOS.csproj
+++ b/Pixiview.iOS/Pixiview.iOS.csproj
@@ -83,6 +83,7 @@
+
diff --git a/Pixiview.iOS/Renderers/HybridWebViewRenderer.cs b/Pixiview.iOS/Renderers/HybridWebViewRenderer.cs
new file mode 100644
index 0000000..a3cdf90
--- /dev/null
+++ b/Pixiview.iOS/Renderers/HybridWebViewRenderer.cs
@@ -0,0 +1,80 @@
+using System;
+using Foundation;
+using Pixiview.iOS.Renderers;
+using Pixiview.Login;
+using Pixiview.Utils;
+using WebKit;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.iOS;
+
+[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
+namespace Pixiview.iOS.Renderers
+{
+ public class HybridWebViewRenderer : WkWebViewRenderer
+ {
+ public HybridWebViewRenderer() : this(new WKWebViewConfiguration())
+ {
+ }
+
+ public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
+ {
+ }
+
+ protected override void OnElementChanged(VisualElementChangedEventArgs e)
+ {
+ base.OnElementChanged(e);
+
+ if (e.NewElement is HybridWebView webView)
+ {
+ string url = webView.Uri;
+ //Configuration.SetUrlSchemeHandler
+ CustomUserAgent = webView.UserAgent;
+ NavigationDelegate = new PixivNavigationDelegate(webView);
+
+ LoadRequest(new NSUrlRequest(NSUrl.FromString(url)));
+ }
+ }
+
+ private class PixivNavigationDelegate : WKNavigationDelegate
+ {
+ private readonly HybridWebView hybridWebView;
+
+ public PixivNavigationDelegate(HybridWebView hybrid)
+ {
+ hybridWebView = hybrid;
+ }
+
+ public override void DecidePolicy(WKWebView webView, WKNavigationResponse navigationResponse, Action decisionHandler)
+ {
+ var url = webView.Url;
+ if (url.Host == "www.pixiv.net" && url.Path == "/")
+ {
+ if (navigationResponse.Response is NSHttpUrlResponse response)
+ {
+ if (response.AllHeaderFields.TryGetValue(new NSString("x-userid"), out var val))
+ {
+ Configs.SetUserId(val.ToString(), true);
+ }
+ }
+ }
+
+ decisionHandler(WKNavigationResponsePolicy.Allow);
+ }
+
+ public override async void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
+ {
+ var url = webView.Url;
+ if (url.Host == "www.pixiv.net" && url.Path == "/")
+ {
+ var store = webView.Configuration.WebsiteDataStore.HttpCookieStore;
+ var result = await Configs.RequestCookieContainer(store);
+
+ if (result && hybridWebView != null)
+ {
+ hybridWebView.OnLoginHandle();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Pixiview/App.cs b/Pixiview/App.cs
index 27d7d70..3f522f0 100644
--- a/Pixiview/App.cs
+++ b/Pixiview/App.cs
@@ -31,6 +31,9 @@ namespace Pixiview
private void InitPreferences()
{
+ Configs.SetCookie(Preferences.Get(Configs.CookieKey, null));
+ Configs.SetUserId(Preferences.Get(Configs.UserIdKey, null));
+
Configs.IsOnR18 = Preferences.Get(Configs.IsOnR18Key, false);
var isProxied = Preferences.Get(Configs.IsProxiedKey, false);
if (isProxied)
diff --git a/Pixiview/AppShell.xaml b/Pixiview/AppShell.xaml
index dea4794..16eb2b4 100644
--- a/Pixiview/AppShell.xaml
+++ b/Pixiview/AppShell.xaml
@@ -15,6 +15,9 @@
+
+
+
diff --git a/Pixiview/AppShell.xaml.cs b/Pixiview/AppShell.xaml.cs
index 9fa8a8e..4360359 100644
--- a/Pixiview/AppShell.xaml.cs
+++ b/Pixiview/AppShell.xaml.cs
@@ -1,5 +1,7 @@
using System;
+using Pixiview.Login;
using Pixiview.Utils;
+using Xamarin.Essentials;
using Xamarin.Forms;
namespace Pixiview
@@ -42,6 +44,35 @@ namespace Pixiview
StatusBarHeight = height
});
}
+
+ private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
+ {
+ PushToLogin(null);
+ }
+
+ private bool isLoginOpened;
+
+ public void PushToLogin(Action after)
+ {
+ if (isLoginOpened)
+ {
+ return;
+ }
+ isLoginOpened = true;
+ var loginPage = new LoginPage(()=>
+ {
+ isLoginOpened = false;
+ after?.Invoke();
+ });
+ loginPage.Disappearing += (sender, e) =>
+ {
+ isLoginOpened = false;
+ };
+ MainThread.BeginInvokeOnMainThread(async () =>
+ {
+ await Navigation.PushModalAsync(loginPage);
+ });
+ }
}
public class BarHeightEventArgs : EventArgs
diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs
index 62e2fa7..2a3018c 100644
--- a/Pixiview/Illust/IllustCollectionPage.cs
+++ b/Pixiview/Illust/IllustCollectionPage.cs
@@ -530,6 +530,10 @@ namespace Pixiview.Illust
illustData = DoLoadIllustData(force);
if (illustData == null)
{
+ AppShell.Current.PushToLogin(()=>
+ {
+ StartLoad(true);
+ });
//App.DebugError("illusts.load", "failed to load illusts data.");
IsLoading = false;
IsBottomLoading = false;
diff --git a/Pixiview/Login/HybridWebView.cs b/Pixiview/Login/HybridWebView.cs
new file mode 100644
index 0000000..67c9961
--- /dev/null
+++ b/Pixiview/Login/HybridWebView.cs
@@ -0,0 +1,35 @@
+using System;
+using Xamarin.Forms;
+
+namespace Pixiview.Login
+{
+ public class HybridWebView : WebView
+ {
+ public static readonly BindableProperty UriProperty = BindableProperty.Create(
+ nameof(Uri),
+ typeof(string),
+ typeof(HybridWebView));
+ public static readonly BindableProperty UserAgentProperty = BindableProperty.Create(
+ nameof(UserAgent),
+ typeof(string),
+ typeof(HybridWebView));
+
+ public event EventHandler LoginHandle;
+
+ public string Uri
+ {
+ get => (string)GetValue(UriProperty);
+ set => SetValue(UriProperty, value);
+ }
+ public string UserAgent
+ {
+ get => (string)GetValue(UserAgentProperty);
+ set => SetValue(UserAgentProperty, value);
+ }
+
+ public void OnLoginHandle()
+ {
+ LoginHandle?.Invoke(this, EventArgs.Empty);
+ }
+ }
+}
diff --git a/Pixiview/Login/LoginPage.xaml b/Pixiview/Login/LoginPage.xaml
new file mode 100644
index 0000000..73deaee
--- /dev/null
+++ b/Pixiview/Login/LoginPage.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/Pixiview/Login/LoginPage.xaml.cs b/Pixiview/Login/LoginPage.xaml.cs
new file mode 100644
index 0000000..5642829
--- /dev/null
+++ b/Pixiview/Login/LoginPage.xaml.cs
@@ -0,0 +1,31 @@
+using System;
+using Pixiview.UI;
+using Pixiview.Utils;
+
+namespace Pixiview.Login
+{
+ public partial class LoginPage : AdaptedPage
+ {
+ private readonly Action action;
+
+ public LoginPage(Action after)
+ {
+ InitializeComponent();
+ webView.UserAgent = Configs.UserAgent;
+
+ BindingContext = this;
+ action = after;
+ }
+
+ private async void Button_Clicked(object sender, EventArgs e)
+ {
+ await Navigation.PopModalAsync();
+ }
+
+ private async void WebView_LoginHandle(object sender, EventArgs e)
+ {
+ await Navigation.PopModalAsync();
+ action?.Invoke();
+ }
+ }
+}
diff --git a/Pixiview/Pixiview.projitems b/Pixiview/Pixiview.projitems
index 8925fe3..a953e68 100644
--- a/Pixiview/Pixiview.projitems
+++ b/Pixiview/Pixiview.projitems
@@ -46,6 +46,10 @@
Designer
MSBuild:UpdateDesignTimeXaml
+
+ Designer
+ MSBuild:UpdateDesignTimeXaml
+
@@ -101,6 +105,10 @@
RelatedIllustsPage.xaml
+
+ LoginPage.xaml
+
+
@@ -109,5 +117,6 @@
+
\ No newline at end of file
diff --git a/Pixiview/Resources/Languages/zh-CN.xml b/Pixiview/Resources/Languages/zh-CN.xml
index 5dafb2f..35f916b 100644
--- a/Pixiview/Resources/Languages/zh-CN.xml
+++ b/Pixiview/Resources/Languages/zh-CN.xml
@@ -5,6 +5,7 @@
取消
是
否
+ 登录
插画
代理
详细
diff --git a/Pixiview/UI/StyleDefinition.cs b/Pixiview/UI/StyleDefinition.cs
index daf0f07..920a059 100644
--- a/Pixiview/UI/StyleDefinition.cs
+++ b/Pixiview/UI/StyleDefinition.cs
@@ -51,6 +51,7 @@ namespace Pixiview.UI
public const string IconCaretCircleLeft = "\uf32e";
public const string IconCaretCircleRight = "\uf330";
public const string IconCalendarDay = "\uf783";
+ public const string IconClose = "\uf057";
static StyleDefinition()
{
diff --git a/Pixiview/UI/Theme/ThemeBase.cs b/Pixiview/UI/Theme/ThemeBase.cs
index f8e848d..f0f7e61 100644
--- a/Pixiview/UI/Theme/ThemeBase.cs
+++ b/Pixiview/UI/Theme/ThemeBase.cs
@@ -19,6 +19,7 @@ namespace Pixiview.UI.Theme
public const string FontIconCalendarDay = nameof(FontIconCalendarDay);
public const string IconCircleCheck = nameof(IconCircleCheck);
public const string IconCaretDown = nameof(IconCaretDown);
+ public const string IconClose = nameof(IconClose);
public const string StatusBarStyle = nameof(StatusBarStyle);
public const string WindowColor = nameof(WindowColor);
@@ -66,6 +67,7 @@ namespace Pixiview.UI.Theme
Add(IconCircleCheck, StyleDefinition.IconCircleCheck);
Add(IconCaretDown, StyleDefinition.IconCaretDown);
+ Add(IconClose, StyleDefinition.IconClose);
}
private FontImageSource GetSolidIcon(string icon, string family, Color color = default)
diff --git a/Pixiview/Utils/Extensions.cs b/Pixiview/Utils/Extensions.cs
index 903a265..9e0d222 100644
--- a/Pixiview/Utils/Extensions.cs
+++ b/Pixiview/Utils/Extensions.cs
@@ -132,17 +132,19 @@ namespace Pixiview.Utils
for (int i = from; i < to; i++)
{
var index = i;
- bool flag;
- lock (sync)
+ while (true)
{
- flag = count >= max;
- }
- while (flag)
- {
- if (disposed)
+ lock (sync)
{
- App.DebugPrint($"parallel task determinate, disposed");
- return;
+ if (count < max)
+ {
+ break;
+ }
+ if (disposed)
+ {
+ App.DebugPrint($"parallel task determinate, disposed");
+ return;
+ }
}
Thread.Sleep(100);
}
@@ -175,6 +177,7 @@ namespace Pixiview.Utils
}
});
}
+ App.DebugPrint($"parallel task done");
}
public void Dispose()
diff --git a/Pixiview/Utils/HttpUtility.cs b/Pixiview/Utils/HttpUtility.cs
index 7d3e0d4..01833ca 100644
--- a/Pixiview/Utils/HttpUtility.cs
+++ b/Pixiview/Utils/HttpUtility.cs
@@ -39,10 +39,18 @@ namespace Pixiview.Utils
}
headers.Add("User-Agent", Configs.UserAgent);
headers.Add("Accept", Configs.AcceptJson);
- headers.Add("Cookie", Configs.Cookie);
+ var cookie = Configs.Cookie;
+ if (cookie != null)
+ {
+ headers.Add("Cookie", cookie);
+ }
if (header == null)
{
- headers.Add("X-User-Id", Configs.UserId);
+ var userId = Configs.UserId;
+ if (userId != null)
+ {
+ headers.Add("X-User-Id", userId);
+ }
}
else
{
diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs
index 3eeb2b1..9ac7c08 100644
--- a/Pixiview/Utils/Stores.cs
+++ b/Pixiview/Utils/Stores.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Text;
+using System.Threading.Tasks;
using Newtonsoft.Json;
using Pixiview.Illust;
using Xamarin.Essentials;
@@ -470,6 +471,8 @@ namespace Pixiview.Utils
public static class Configs
{
+ public const string CookieKey = "cookies";
+ public const string UserIdKey = "user_id";
public const string IsOnR18Key = "is_on_r18";
public const string IsProxiedKey = "is_proxied";
public const string HostKey = "host";
@@ -490,6 +493,65 @@ namespace Pixiview.Utils
private static string Prefix => Proxy == null ?
"https://hk.tsanie.us/reverse/" :
"https://www.pixiv.net/";
+ public static string UserId { get; private set; }
+ public static string Cookie { get; private set; }
+
+ public static void SetUserId(string userId, bool save = false)
+ {
+ UserId = userId;
+ if (!save)
+ {
+ return;
+ }
+ if (userId == null)
+ {
+ Preferences.Remove(UserIdKey);
+ }
+ else
+ {
+ Preferences.Set(UserIdKey, userId);
+ }
+ }
+
+ public static void SetCookie(string cookie)
+ {
+ Cookie = cookie;
+ }
+
+#if __IOS__
+ public static Task RequestCookieContainer(WebKit.WKHttpCookieStore cookieStore)
+ {
+ var task = new TaskCompletionSource();
+ cookieStore.GetAllCookies(cookies =>
+ {
+ var list = new List();
+ foreach (var c in cookies)
+ {
+#if DEBUG
+ App.DebugPrint($"domain: {c.Domain}, path: {c.Path}, {c.Name}={c.Value}, http only: {c.IsHttpOnly}, session only: {c.IsSessionOnly}");
+#endif
+ var domain = c.Domain;
+ if (domain == null)
+ {
+ continue;
+ }
+ if (domain != "www.pixiv.net" && domain != ".pixiv.net")
+ {
+ continue;
+ }
+ list.Add($"{c.Name}={c.Value}");
+ }
+ var cookie = string.Join("; ", list);
+ Cookie = cookie;
+
+ Preferences.Set(CookieKey, cookie);
+ task.SetResult(true);
+ });
+ return task.Task;
+ }
+#elif __ANDROID__
+ task.SetResult(false);
+#endif
public const string SuffixPreload = " id=\"meta-preload-data\" content='";
public const int SuffixPreloadLength = 33; // SuffixPreload.Length
@@ -508,29 +570,6 @@ namespace Pixiview.Utils
//public const string AcceptEncoding = "gzip, deflate";
public const string AcceptLanguage = "zh-cn";
-#if __ANDROID__
- public const string UserId = "53887721";
- public const string Cookie =
- "PHPSESSID=5sn8n049j5c18l0tlj91qrjhesgddhjv; " +
- "a_type=0; b_type=1; c_type=29; d_type=2; " +
- "p_ab_d_id=1021624041; p_ab_id=2; p_ab_id_2=0; " +
- "privacy_policy_agreement=2; " +
- "login_ever=yes; " +
- "__cfduid=d84153bf70ae67315a8bc297299d39eb61588856027; " +
- "first_visit_datetime_pc=2020-05-07+21%3A53%3A47; " +
- "yuid_b=MYkIJXc";
-#else
- public const string UserId = "2603358";
- public const string Cookie =
- "PHPSESSID=2603358_VHyGPeRaz7LpeoFkRsHvjXIpApCMb56a; " +
- "a_type=0; b_type=1; c_type=31; d_type=2; " +
- "p_ab_id=2; p_ab_id_2=6; p_ab_d_id=1155161977; " +
- "privacy_policy_agreement=2; " +
- "login_ever=yes; " +
- "__cfduid=d9fa2d4d1ddd30db85ebb519f9855d2561587806747; " +
- "first_visit_datetime_pc=2019-10-29+22%3A05%3A30; " +
- "yuid_b=NgcXQWQ";
-#endif
private const string URL_PREVIEW = "https://i.pximg.net/c/360x360_70";
public static string GetThumbnailUrl(string url)