rename from Pixiview to Gallery
This commit is contained in:
43
Gallery.Android/Renderers/AdaptedPageRenderer.cs
Executable file
43
Gallery.Android/Renderers/AdaptedPageRenderer.cs
Executable file
@ -0,0 +1,43 @@
|
||||
using Android.Content;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(AdaptedPage), typeof(AdaptedPageRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class AdaptedPageRenderer : PageRenderer
|
||||
{
|
||||
public AdaptedPageRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnAttachedToWindow()
|
||||
{
|
||||
base.OnAttachedToWindow();
|
||||
|
||||
if (Element is AdaptedPage page)
|
||||
{
|
||||
page.OnLoad();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (Element is AdaptedPage page)
|
||||
{
|
||||
page.OnUnload();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//protected override void OnDetachedFromWindow()
|
||||
//{
|
||||
// App.DebugPrint("detached from window");
|
||||
|
||||
// base.OnDetachedFromWindow();
|
||||
//}
|
||||
}
|
||||
}
|
21
Gallery.Android/Renderers/AppShellRenderer.cs
Executable file
21
Gallery.Android/Renderers/AppShellRenderer.cs
Executable file
@ -0,0 +1,21 @@
|
||||
using Android.Content;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.Droid.Renderers.AppShellSection;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Shell), typeof(AppShellRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class AppShellRenderer : ShellRenderer
|
||||
{
|
||||
public AppShellRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
|
||||
{
|
||||
return new AppShellBottomNavViewAppearanceTracker(this, shellItem);
|
||||
}
|
||||
}
|
||||
}
|
98
Gallery.Android/Renderers/AppShellSection/AppColorChangeRevealDrawable.cs
Executable file
98
Gallery.Android/Renderers/AppShellSection/AppColorChangeRevealDrawable.cs
Executable file
@ -0,0 +1,98 @@
|
||||
using Android.Animation;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using System;
|
||||
using AColor = Android.Graphics.Color;
|
||||
|
||||
namespace Gallery.Droid.Renderers.AppShellSection
|
||||
{
|
||||
public class AppColorChangeRevealDrawable : AnimationDrawable
|
||||
{
|
||||
readonly Point _center;
|
||||
float _progress;
|
||||
bool _disposed;
|
||||
ValueAnimator _animator;
|
||||
|
||||
internal AColor StartColor { get; }
|
||||
internal AColor EndColor { get; }
|
||||
|
||||
public AppColorChangeRevealDrawable(AColor startColor, AColor endColor, Point center) : base()
|
||||
{
|
||||
StartColor = startColor;
|
||||
EndColor = endColor;
|
||||
|
||||
if (StartColor != EndColor)
|
||||
{
|
||||
_animator = ValueAnimator.OfFloat(0, 1);
|
||||
_animator.SetInterpolator(new Android.Views.Animations.DecelerateInterpolator());
|
||||
_animator.SetDuration(500);
|
||||
_animator.Update += OnUpdate;
|
||||
_animator.Start();
|
||||
_center = center;
|
||||
}
|
||||
else
|
||||
{
|
||||
_progress = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw(Canvas canvas)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (_progress == 1)
|
||||
{
|
||||
canvas.DrawColor(EndColor);
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.DrawColor(StartColor);
|
||||
var bounds = Bounds;
|
||||
float centerX = _center.X;
|
||||
float centerY = _center.Y;
|
||||
|
||||
float width = bounds.Width();
|
||||
float distanceFromCenter = Math.Abs(width / 2 - _center.X);
|
||||
float radius = (width / 2 + distanceFromCenter) * 1.1f;
|
||||
|
||||
var paint = new Paint
|
||||
{
|
||||
Color = EndColor
|
||||
};
|
||||
|
||||
canvas.DrawCircle(centerX, centerY, radius * _progress, paint);
|
||||
}
|
||||
|
||||
void OnUpdate(object sender, ValueAnimator.AnimatorUpdateEventArgs e)
|
||||
{
|
||||
_progress = (float)e.Animation.AnimatedValue;
|
||||
|
||||
InvalidateSelf();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_disposed = true;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.Update -= OnUpdate;
|
||||
|
||||
_animator.Cancel();
|
||||
|
||||
_animator.Dispose();
|
||||
|
||||
_animator = null;
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics.Drawables;
|
||||
#if __ANDROID_29__
|
||||
using AndroidX.Core.Widget;
|
||||
using Google.Android.Material.BottomNavigation;
|
||||
#else
|
||||
using Android.Support.Design.Internal;
|
||||
using Android.Support.Design.Widget;
|
||||
#endif
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using AColor = Android.Graphics.Color;
|
||||
using R = Android.Resource;
|
||||
|
||||
namespace Gallery.Droid.Renderers.AppShellSection
|
||||
{
|
||||
public class AppShellBottomNavViewAppearanceTracker : IShellBottomNavViewAppearanceTracker
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "<Pending>")]
|
||||
IShellContext _shellContext;
|
||||
ShellItem _shellItem;
|
||||
ColorStateList _defaultList;
|
||||
bool _disposed;
|
||||
ColorStateList _colorStateList;
|
||||
|
||||
public AppShellBottomNavViewAppearanceTracker(IShellContext shellContext, ShellItem shellItem)
|
||||
{
|
||||
_shellItem = shellItem;
|
||||
_shellContext = shellContext;
|
||||
}
|
||||
|
||||
public virtual void ResetAppearance(BottomNavigationView bottomView)
|
||||
{
|
||||
if (_defaultList != null)
|
||||
{
|
||||
bottomView.ItemTextColor = _defaultList;
|
||||
bottomView.ItemIconTintList = _defaultList;
|
||||
}
|
||||
|
||||
SetBackgroundColor(bottomView, Color.White);
|
||||
}
|
||||
|
||||
public virtual void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
|
||||
{
|
||||
IShellAppearanceElement controller = appearance;
|
||||
var backgroundColor = controller.EffectiveTabBarBackgroundColor;
|
||||
var foregroundColor = controller.EffectiveTabBarForegroundColor;
|
||||
var disabledColor = controller.EffectiveTabBarDisabledColor;
|
||||
var unselectedColor = controller.EffectiveTabBarUnselectedColor; // currently unused
|
||||
var titleColor = controller.EffectiveTabBarTitleColor;
|
||||
|
||||
if (_defaultList == null)
|
||||
{
|
||||
#if __ANDROID_28__
|
||||
_defaultList = bottomView.ItemTextColor ?? bottomView.ItemIconTintList
|
||||
?? MakeColorStateList(titleColor.ToAndroid().ToArgb(), disabledColor.ToAndroid().ToArgb(), foregroundColor.ToAndroid().ToArgb());
|
||||
#else
|
||||
_defaultList = bottomView.ItemTextColor ?? bottomView.ItemIconTintList;
|
||||
#endif
|
||||
}
|
||||
|
||||
_colorStateList = MakeColorStateList(titleColor, disabledColor, foregroundColor);
|
||||
bottomView.ItemTextColor = _colorStateList;
|
||||
bottomView.ItemIconTintList = _colorStateList;
|
||||
|
||||
var menu = bottomView.Menu;
|
||||
if (menu != null && menu.HasVisibleItems && menu.Size() == 4)
|
||||
{
|
||||
var itemUser = menu.GetItem(0);
|
||||
itemUser.SetIcon(itemUser.IsChecked ?
|
||||
Resource.Drawable.ic_user :
|
||||
Resource.Drawable.ic_user_regular);
|
||||
var itemRecommend = menu.GetItem(1);
|
||||
itemRecommend.SetIcon(itemRecommend.IsChecked ?
|
||||
Resource.Drawable.ic_sparkles :
|
||||
Resource.Drawable.ic_sparkles_regular);
|
||||
var itemRank = menu.GetItem(2);
|
||||
itemRank.SetIcon(itemRank.IsChecked ?
|
||||
Resource.Drawable.ic_rank :
|
||||
Resource.Drawable.ic_rank_regular);
|
||||
var itemFavorite = menu.GetItem(3);
|
||||
itemFavorite.SetIcon(itemFavorite.IsChecked ?
|
||||
Resource.Drawable.ic_bookmark :
|
||||
Resource.Drawable.ic_bookmark_regular);
|
||||
}
|
||||
|
||||
SetBackgroundColor(bottomView, backgroundColor);
|
||||
}
|
||||
|
||||
protected virtual void SetBackgroundColor(BottomNavigationView bottomView, Color color)
|
||||
{
|
||||
var oldBackground = bottomView.Background;
|
||||
var colorDrawable = oldBackground as ColorDrawable;
|
||||
var colorChangeRevealDrawable = oldBackground as AppColorChangeRevealDrawable;
|
||||
AColor lastColor = colorChangeRevealDrawable?.EndColor ?? colorDrawable?.Color ?? Color.Default.ToAndroid();
|
||||
AColor newColor;
|
||||
|
||||
if (color == Color.Default)
|
||||
newColor = Color.White.ToAndroid();
|
||||
else
|
||||
newColor = color.ToAndroid();
|
||||
|
||||
if (!(bottomView.GetChildAt(0) is BottomNavigationMenuView menuView))
|
||||
{
|
||||
if (colorDrawable != null && lastColor == newColor)
|
||||
return;
|
||||
|
||||
if (lastColor != newColor || colorDrawable == null)
|
||||
{
|
||||
bottomView.SetBackground(new ColorDrawable(newColor));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (colorChangeRevealDrawable != null && lastColor == newColor)
|
||||
return;
|
||||
|
||||
var index = ((IShellItemController)_shellItem).GetItems().IndexOf(_shellItem.CurrentItem);
|
||||
var menu = bottomView.Menu;
|
||||
index = Math.Min(index, menu.Size() - 1);
|
||||
|
||||
var child = menuView.GetChildAt(index);
|
||||
if (child == null)
|
||||
return;
|
||||
|
||||
var touchPoint = new Android.Graphics.Point(child.Left + (child.Right - child.Left) / 2, child.Top + (child.Bottom - child.Top) / 2);
|
||||
|
||||
bottomView.SetBackground(new AppColorChangeRevealDrawable(lastColor, newColor, touchPoint));
|
||||
}
|
||||
}
|
||||
|
||||
ColorStateList MakeColorStateList(Color titleColor, Color disabledColor, Color unselectedColor)
|
||||
{
|
||||
var disabledInt = disabledColor.IsDefault ?
|
||||
_defaultList.GetColorForState(new[] { -R.Attribute.StateEnabled }, AColor.Gray) :
|
||||
disabledColor.ToAndroid().ToArgb();
|
||||
|
||||
var checkedInt = titleColor.IsDefault ?
|
||||
_defaultList.GetColorForState(new[] { R.Attribute.StateChecked }, AColor.Black) :
|
||||
titleColor.ToAndroid().ToArgb();
|
||||
|
||||
var defaultColor = unselectedColor.IsDefault ?
|
||||
_defaultList.DefaultColor :
|
||||
unselectedColor.ToAndroid().ToArgb();
|
||||
|
||||
return MakeColorStateList(checkedInt, disabledInt, defaultColor);
|
||||
}
|
||||
|
||||
ColorStateList MakeColorStateList(int titleColorInt, int disabledColorInt, int defaultColor)
|
||||
{
|
||||
var states = new int[][] {
|
||||
new int[] { -R.Attribute.StateEnabled },
|
||||
new int[] {R.Attribute.StateChecked },
|
||||
new int[] { }
|
||||
};
|
||||
|
||||
var colors = new[] { disabledColorInt, titleColorInt, defaultColor };
|
||||
|
||||
return new ColorStateList(states, colors);
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_disposed = true;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_defaultList?.Dispose();
|
||||
_colorStateList?.Dispose();
|
||||
|
||||
_shellItem = null;
|
||||
_shellContext = null;
|
||||
_defaultList = null;
|
||||
_colorStateList = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion IDisposable
|
||||
}
|
||||
}
|
30
Gallery.Android/Renderers/BlurryPanelRenderer.cs
Executable file
30
Gallery.Android/Renderers/BlurryPanelRenderer.cs
Executable file
@ -0,0 +1,30 @@
|
||||
using Android.Content;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(BlurryPanel), typeof(BlurryPanelRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class BlurryPanelRenderer : ViewRenderer
|
||||
{
|
||||
public BlurryPanelRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
var color = e.NewElement.BackgroundColor;
|
||||
if (!color.IsDefault)
|
||||
{
|
||||
SetBackgroundColor(color.MultiplyAlpha(.94).ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
84
Gallery.Android/Renderers/CardViewRenderer.cs
Executable file
84
Gallery.Android/Renderers/CardViewRenderer.cs
Executable file
@ -0,0 +1,84 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Views;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(CardView), typeof(CardViewRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class CardViewRenderer : VisualElementRenderer<CardView>
|
||||
{
|
||||
public CardViewRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<CardView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
var element = e.NewElement;
|
||||
if (element != null)
|
||||
{
|
||||
var radius = element.CornerRadius;
|
||||
if (radius > 0)
|
||||
{
|
||||
var density = Resources.DisplayMetrics.Density;
|
||||
|
||||
OutlineProvider = new CornerRadiusOutlineProvider(element, radius, density);
|
||||
ClipToOutline = true;
|
||||
|
||||
//var drawable = new RoundCornerDrawable(radius * density);
|
||||
//drawable.SetColorFilter(element.BackgroundColor.ToAndroid(), PorterDuff.Mode.Src);
|
||||
//((Android.Views.View)this).SetBackground(drawable);
|
||||
|
||||
Elevation = (float)(element.ShadowOffset.Height + 2) * density;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
var element = Element;
|
||||
if (element == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(CardView.ShadowOffset):
|
||||
var density = Resources.DisplayMetrics.Density;
|
||||
Elevation = (float)(element.ShadowOffset.Height + 2) * density;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class CornerRadiusOutlineProvider : ViewOutlineProvider
|
||||
{
|
||||
readonly Element element;
|
||||
readonly float radius;
|
||||
readonly float density;
|
||||
|
||||
public CornerRadiusOutlineProvider(Element formsElement, float radius, float density)
|
||||
{
|
||||
element = formsElement;
|
||||
this.radius = radius * density;
|
||||
this.density = density;
|
||||
}
|
||||
|
||||
public override void GetOutline(Android.Views.View view, Outline outline)
|
||||
{
|
||||
float scale = density;
|
||||
double width = (double)element.GetValue(VisualElement.WidthProperty) * scale;
|
||||
double height = (double)element.GetValue(VisualElement.HeightProperty) * scale;
|
||||
var rect = new Android.Graphics.Rect(0, 0, (int)width, (int)height);
|
||||
outline.SetRoundRect(rect, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
Gallery.Android/Renderers/CircleImageRenderer.cs
Executable file
66
Gallery.Android/Renderers/CircleImageRenderer.cs
Executable file
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
|
||||
[assembly: ExportRenderer(typeof(CircleImage), typeof(CircleImageRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class CircleImageRenderer : Xamarin.Forms.Platform.Android.FastRenderers.ImageRenderer
|
||||
{
|
||||
private Paint paint;
|
||||
private int radius;
|
||||
private float scale;
|
||||
|
||||
public CircleImageRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
int size = Math.Min(MeasuredWidth, MeasuredHeight);
|
||||
radius = size / 2;
|
||||
SetMeasuredDimension(size, size);
|
||||
}
|
||||
|
||||
protected override void OnDraw(Canvas canvas)
|
||||
{
|
||||
paint = new Paint();
|
||||
var bitmap = DrawableToBitmap(Drawable);
|
||||
if (bitmap == null)
|
||||
{
|
||||
base.OnDraw(canvas);
|
||||
return;
|
||||
}
|
||||
var bitmapShader = new BitmapShader(bitmap, Shader.TileMode.Clamp, Shader.TileMode.Clamp);
|
||||
scale = radius * 2.0f / Math.Min(bitmap.Width, bitmap.Height);
|
||||
|
||||
var matrix = new Matrix();
|
||||
matrix.SetScale(scale, scale);
|
||||
bitmapShader.SetLocalMatrix(matrix);
|
||||
paint.SetShader(bitmapShader);
|
||||
|
||||
canvas.DrawCircle(radius, radius, radius, paint);
|
||||
}
|
||||
|
||||
private Bitmap DrawableToBitmap(Drawable drawable)
|
||||
{
|
||||
if (drawable is BitmapDrawable bd)
|
||||
{
|
||||
return bd.Bitmap;
|
||||
}
|
||||
int w = drawable.IntrinsicWidth;
|
||||
int h = drawable.IntrinsicHeight;
|
||||
var bitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
|
||||
var canvas = new Canvas(bitmap);
|
||||
drawable.SetBounds(0, 0, w, h);
|
||||
drawable.Draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
117
Gallery.Android/Renderers/HybridWebViewRenderer.cs
Executable file
117
Gallery.Android/Renderers/HybridWebViewRenderer.cs
Executable file
@ -0,0 +1,117 @@
|
||||
using Android.Content;
|
||||
using Android.Webkit;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.Login;
|
||||
using Gallery.Utils;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class HybridWebViewRenderer : WebViewRenderer
|
||||
{
|
||||
public HybridWebViewRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (e.NewElement is HybridWebView webView)
|
||||
{
|
||||
Control.SetWebViewClient(new PixivWebViewClient(this));
|
||||
Control.LoadUrl(webView.Uri);
|
||||
}
|
||||
}
|
||||
|
||||
private class PixivWebViewClient : FormsWebViewClient
|
||||
{
|
||||
private readonly HybridWebView webView;
|
||||
|
||||
public PixivWebViewClient(HybridWebViewRenderer renderer) : base(renderer)
|
||||
{
|
||||
if (renderer.Element is HybridWebView view)
|
||||
{
|
||||
webView = view;
|
||||
}
|
||||
}
|
||||
|
||||
//public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
|
||||
//{
|
||||
// var uri = request.Url;
|
||||
// if (uri.Host == "www.pixiv.net" && uri.Path == "/")
|
||||
// {
|
||||
// var client = new HttpClient(new HttpClientHandler { UseCookies = false })
|
||||
// {
|
||||
// BaseAddress = new Uri($"{uri.Scheme}://{uri.Host}"),
|
||||
// Timeout = TimeSpan.FromSeconds(30)
|
||||
// };
|
||||
// var pathAndQuery = uri.Path;
|
||||
// if (!string.IsNullOrEmpty(uri.Query))
|
||||
// {
|
||||
// pathAndQuery += "?" + uri.EncodedQuery;
|
||||
// }
|
||||
// using (var req = new HttpRequestMessage(
|
||||
// request.Method == "POST" ? HttpMethod.Post : HttpMethod.Get,
|
||||
// pathAndQuery))
|
||||
// {
|
||||
// var headers = req.Headers;
|
||||
// if (request.RequestHeaders != null)
|
||||
// {
|
||||
// foreach (var h in request.RequestHeaders)
|
||||
// {
|
||||
// headers.Add(h.Key, h.Value);
|
||||
// }
|
||||
// }
|
||||
|
||||
// using (var response = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead).Result)
|
||||
// {
|
||||
// if (response.Headers.TryGetValues("x-userid", out var vals))
|
||||
// {
|
||||
// Configs.SetUserId(string.Join(';', vals), true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// return base.ShouldOverrideUrlLoading(view, request);
|
||||
//}
|
||||
|
||||
public override void OnPageFinished(Android.Webkit.WebView view, string url)
|
||||
{
|
||||
base.OnPageFinished(view, url);
|
||||
|
||||
if (url == "https://www.pixiv.net/" ||
|
||||
url == "https://www.pixiv.net/en/")
|
||||
{
|
||||
var cookieManager = CookieManager.Instance;
|
||||
var cookie = cookieManager.GetCookie(url);
|
||||
Configs.SetCookie(cookie, true);
|
||||
|
||||
// user-id
|
||||
if (cookie != null)
|
||||
{
|
||||
var index = cookie.IndexOf("PHPSESSID=");
|
||||
if (index >= 0)
|
||||
{
|
||||
var session = cookie.Substring(index + 10);
|
||||
index = session.IndexOf('_');
|
||||
if (index > 0)
|
||||
{
|
||||
session = session.Substring(0, index);
|
||||
Configs.SetUserId(session, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (webView != null)
|
||||
{
|
||||
webView.OnLoginHandle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
Gallery.Android/Renderers/OptionEntryRenderer.cs
Executable file
28
Gallery.Android/Renderers/OptionEntryRenderer.cs
Executable file
@ -0,0 +1,28 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics.Drawables;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(OptionEntry), typeof(OptionEntryRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class OptionEntryRenderer : EntryRenderer
|
||||
{
|
||||
public OptionEntryRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
var drawable = new ColorDrawable(e.NewElement.BackgroundColor.ToAndroid());
|
||||
Control.SetBackground(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
Gallery.Android/Renderers/OptionPickerRenderer.cs
Executable file
29
Gallery.Android/Renderers/OptionPickerRenderer.cs
Executable file
@ -0,0 +1,29 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics.Drawables;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(OptionPicker), typeof(OptionPickerRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class OptionPickerRenderer : PickerRenderer
|
||||
{
|
||||
public OptionPickerRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
var drawable = new ColorDrawable(e.NewElement.BackgroundColor.ToAndroid());
|
||||
Control.Gravity = Android.Views.GravityFlags.Right;
|
||||
Control.SetBackground(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
60
Gallery.Android/Renderers/RoundImageRenderer.cs
Executable file
60
Gallery.Android/Renderers/RoundImageRenderer.cs
Executable file
@ -0,0 +1,60 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
|
||||
[assembly: ExportRenderer(typeof(RoundImage), typeof(RoundImageRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class RoundImageRenderer : Xamarin.Forms.Platform.Android.FastRenderers.ImageRenderer
|
||||
{
|
||||
public RoundImageRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetBackgroundColor(Android.Graphics.Color color)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
protected override void OnDraw(Canvas canvas)
|
||||
{
|
||||
if (Element is RoundImage image)
|
||||
{
|
||||
var radius = image.CornerRadius;
|
||||
var mask = image.CornerMasks;
|
||||
if (radius > 0 && mask != CornerMask.None)
|
||||
{
|
||||
var r = Resources.DisplayMetrics.Density * radius;
|
||||
|
||||
var radii = new float[8];
|
||||
if ((mask & CornerMask.LeftTop) == CornerMask.LeftTop)
|
||||
{
|
||||
radii[0] = radii[1] = r;
|
||||
}
|
||||
if ((mask & CornerMask.RightTop) == CornerMask.RightTop)
|
||||
{
|
||||
radii[2] = radii[3] = r;
|
||||
}
|
||||
if ((mask & CornerMask.RightBottom) == CornerMask.RightBottom)
|
||||
{
|
||||
radii[4] = radii[5] = r;
|
||||
}
|
||||
if ((mask & CornerMask.LeftBottom) == CornerMask.LeftBottom)
|
||||
{
|
||||
radii[6] = radii[7] = r;
|
||||
}
|
||||
|
||||
var path = new Path();
|
||||
int width = Width;
|
||||
int height = Height;
|
||||
path.AddRoundRect(new RectF(0, 0, width, height), radii, Path.Direction.Cw);
|
||||
canvas.ClipPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnDraw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
70
Gallery.Android/Renderers/RoundLabelRenderer.cs
Executable file
70
Gallery.Android/Renderers/RoundLabelRenderer.cs
Executable file
@ -0,0 +1,70 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(RoundLabel), typeof(RoundLabelRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class RoundLabelRenderer : Xamarin.Forms.Platform.Android.FastRenderers.LabelRenderer
|
||||
{
|
||||
public RoundLabelRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (e.NewElement is RoundLabel label)
|
||||
{
|
||||
var density = Resources.DisplayMetrics.Density;
|
||||
var drawable = new RoundCornerDrawable(label.CornerRadius * density);
|
||||
drawable.SetColorFilter(label.BackgroundColor.ToAndroid(), PorterDuff.Mode.Src);
|
||||
Control.SetBackground(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RoundCornerDrawable : Drawable
|
||||
{
|
||||
private readonly Paint paint;
|
||||
private readonly float radius;
|
||||
private RectF rect;
|
||||
|
||||
public override int Opacity => (int)Format.Translucent;
|
||||
|
||||
public RoundCornerDrawable(float radius)
|
||||
{
|
||||
paint = new Paint
|
||||
{
|
||||
AntiAlias = true
|
||||
};
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public override void SetBounds(int left, int top, int right, int bottom)
|
||||
{
|
||||
base.SetBounds(left, top, right, bottom);
|
||||
rect = new RectF(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public override void Draw(Canvas canvas)
|
||||
{
|
||||
canvas.DrawRoundRect(rect, radius, radius, paint);
|
||||
}
|
||||
|
||||
public override void SetAlpha(int alpha)
|
||||
{
|
||||
paint.Alpha = alpha;
|
||||
}
|
||||
|
||||
public override void SetColorFilter(ColorFilter colorFilter)
|
||||
{
|
||||
paint.SetColorFilter(colorFilter);
|
||||
}
|
||||
}
|
||||
}
|
30
Gallery.Android/Renderers/SearchBarRenderer.cs
Executable file
30
Gallery.Android/Renderers/SearchBarRenderer.cs
Executable file
@ -0,0 +1,30 @@
|
||||
using Android.Content;
|
||||
using Android.Widget;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(SearchBar), typeof(Gallery.Droid.Renderers.SearchBarRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class SearchBarRenderer : Xamarin.Forms.Platform.Android.SearchBarRenderer
|
||||
{
|
||||
public SearchBarRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (e.NewElement != null && Control is SearchView searchView)
|
||||
{
|
||||
searchView.Iconified = true;
|
||||
searchView.SetIconifiedByDefault(false);
|
||||
// (Resource.Id.search_mag_icon); is wrong / Xammie bug
|
||||
int searchIconId = Context.Resources.GetIdentifier("android:id/search_mag_icon", null, null);
|
||||
var icon = searchView.FindViewById(searchIconId);
|
||||
(icon as ImageView).SetImageResource(Resource.Drawable.ic_search);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
246
Gallery.Android/Renderers/SegmentedControlRenderer.cs
Executable file
246
Gallery.Android/Renderers/SegmentedControlRenderer.cs
Executable file
@ -0,0 +1,246 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Gallery.Droid.Renderers;
|
||||
using Gallery.UI;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: Xamarin.Forms.ExportRenderer(typeof(SegmentedControl), typeof(SegmentedControlRenderer))]
|
||||
namespace Gallery.Droid.Renderers
|
||||
{
|
||||
public class SegmentedControlRenderer : ViewRenderer<SegmentedControl, RadioGroup>
|
||||
{
|
||||
RadioGroup nativeControl;
|
||||
RadioButton _rb;
|
||||
readonly Context context;
|
||||
|
||||
public SegmentedControlRenderer(Context context) : base(context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<SegmentedControl> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Control == null)
|
||||
{
|
||||
// Instantiate the native control and assign it to the Control property with
|
||||
// the SetNativeControl method
|
||||
|
||||
var layoutInflater = LayoutInflater.From(context);
|
||||
|
||||
var view = layoutInflater.Inflate(Resource.Layout.RadioGroup, null);
|
||||
|
||||
nativeControl = (RadioGroup)layoutInflater.Inflate(Resource.Layout.RadioGroup, null);
|
||||
var density = context.Resources.DisplayMetrics.Density;
|
||||
|
||||
for (var i = 0; i < Element.Children.Count; i++)
|
||||
{
|
||||
var o = Element.Children[i];
|
||||
var rb = (RadioButton)layoutInflater.Inflate(Resource.Layout.RadioButton, null);
|
||||
|
||||
var width = rb.Paint.MeasureText(o.Text) * density + 0.5f;
|
||||
rb.LayoutParameters = new RadioGroup.LayoutParams((int)width, LayoutParams.WrapContent, 1f);
|
||||
rb.Text = o.Text;
|
||||
|
||||
if (i == 0)
|
||||
rb.SetBackgroundResource(Resource.Drawable.segmented_control_first_background);
|
||||
else if (i == Element.Children.Count - 1)
|
||||
rb.SetBackgroundResource(Resource.Drawable.segmented_control_last_background);
|
||||
else
|
||||
rb.SetBackgroundResource(Resource.Drawable.segmented_control_background);
|
||||
|
||||
ConfigureRadioButton(i, rb);
|
||||
|
||||
nativeControl.AddView(rb);
|
||||
}
|
||||
|
||||
var option = (RadioButton)nativeControl.GetChildAt(Element.SelectedSegmentIndex);
|
||||
|
||||
if (option != null)
|
||||
option.Checked = true;
|
||||
|
||||
SetNativeControl(nativeControl);
|
||||
}
|
||||
|
||||
if (e.OldElement != null)
|
||||
{
|
||||
// Unsubscribe from event handlers and cleanup any resources
|
||||
|
||||
if (nativeControl != null)
|
||||
nativeControl.CheckedChange -= NativeControl_ValueChanged;
|
||||
}
|
||||
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
// Configure the control and subscribe to event handlers
|
||||
|
||||
nativeControl.CheckedChange += NativeControl_ValueChanged;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (nativeControl == null || Element == null) return;
|
||||
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case "Renderer":
|
||||
Element?.SendValueChanged();
|
||||
break;
|
||||
case nameof(SegmentedControl.SelectedSegmentIndex):
|
||||
var option = (RadioButton)nativeControl.GetChildAt(Element.SelectedSegmentIndex);
|
||||
|
||||
if (option != null)
|
||||
option.Checked = true;
|
||||
|
||||
if (Element.SelectedSegmentIndex < 0)
|
||||
{
|
||||
var layoutInflater = LayoutInflater.From(context);
|
||||
|
||||
nativeControl = (RadioGroup)layoutInflater.Inflate(Resource.Layout.RadioGroup, null);
|
||||
|
||||
for (var i = 0; i < Element.Children.Count; i++)
|
||||
{
|
||||
var o = Element.Children[i];
|
||||
var rb = (RadioButton)layoutInflater.Inflate(Resource.Layout.RadioButton, null);
|
||||
|
||||
var width = rb.Paint.MeasureText(o.Text);
|
||||
rb.LayoutParameters = new RadioGroup.LayoutParams((int)width, LayoutParams.WrapContent, 1f);
|
||||
rb.Text = o.Text;
|
||||
|
||||
if (i == 0)
|
||||
rb.SetBackgroundResource(Resource.Drawable.segmented_control_first_background);
|
||||
else if (i == Element.Children.Count - 1)
|
||||
rb.SetBackgroundResource(Resource.Drawable.segmented_control_last_background);
|
||||
else
|
||||
rb.SetBackgroundResource(Resource.Drawable.segmented_control_background);
|
||||
|
||||
ConfigureRadioButton(i, rb);
|
||||
|
||||
nativeControl.AddView(rb);
|
||||
}
|
||||
|
||||
nativeControl.CheckedChange += NativeControl_ValueChanged;
|
||||
|
||||
SetNativeControl(nativeControl);
|
||||
}
|
||||
|
||||
Element.SendValueChanged();
|
||||
break;
|
||||
case nameof(SegmentedControl.TintColor):
|
||||
OnPropertyChanged();
|
||||
break;
|
||||
case nameof(SegmentedControl.IsEnabled):
|
||||
OnPropertyChanged();
|
||||
break;
|
||||
case nameof(SegmentedControl.SelectedTextColor):
|
||||
var v = (RadioButton)nativeControl.GetChildAt(Element.SelectedSegmentIndex);
|
||||
v.SetTextColor(Element.SelectedTextColor.ToAndroid());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnPropertyChanged()
|
||||
{
|
||||
if (nativeControl != null && Element != null)
|
||||
{
|
||||
for (var i = 0; i < Element.Children.Count; i++)
|
||||
{
|
||||
var rb = (RadioButton)nativeControl.GetChildAt(i);
|
||||
|
||||
ConfigureRadioButton(i, rb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureRadioButton(int i, RadioButton rb)
|
||||
{
|
||||
var textColor = Element.SelectedTextColor;
|
||||
if (i == Element.SelectedSegmentIndex)
|
||||
{
|
||||
rb.SetTextColor(textColor.ToAndroid());
|
||||
rb.Paint.FakeBoldText = true;
|
||||
_rb = rb;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tColor = Element.IsEnabled ?
|
||||
textColor.IsDefault ? Element.TintColor.ToAndroid() : textColor.MultiplyAlpha(.6).ToAndroid() :
|
||||
Element.DisabledColor.ToAndroid();
|
||||
rb.SetTextColor(tColor);
|
||||
}
|
||||
|
||||
GradientDrawable selectedShape;
|
||||
GradientDrawable unselectedShape;
|
||||
|
||||
var gradientDrawable = (StateListDrawable)rb.Background;
|
||||
var drawableContainerState = (DrawableContainer.DrawableContainerState)gradientDrawable.GetConstantState();
|
||||
var children = drawableContainerState.GetChildren();
|
||||
|
||||
// Doesnt works on API < 18
|
||||
selectedShape = children[0] is GradientDrawable ? (GradientDrawable)children[0] : (GradientDrawable)((InsetDrawable)children[0]).Drawable;
|
||||
unselectedShape = children[1] is GradientDrawable ? (GradientDrawable)children[1] : (GradientDrawable)((InsetDrawable)children[1]).Drawable;
|
||||
|
||||
var color = Element.IsEnabled ? Element.TintColor.ToAndroid() : Element.DisabledColor.ToAndroid();
|
||||
|
||||
selectedShape.SetStroke(3, color);
|
||||
selectedShape.SetColor(color);
|
||||
unselectedShape.SetStroke(3, color);
|
||||
|
||||
rb.Enabled = Element.IsEnabled;
|
||||
}
|
||||
|
||||
void NativeControl_ValueChanged(object sender, RadioGroup.CheckedChangeEventArgs e)
|
||||
{
|
||||
var rg = (RadioGroup)sender;
|
||||
if (rg.CheckedRadioButtonId != -1)
|
||||
{
|
||||
var id = rg.CheckedRadioButtonId;
|
||||
var radioButton = rg.FindViewById(id);
|
||||
var radioId = rg.IndexOfChild(radioButton);
|
||||
|
||||
var rb = (RadioButton)rg.GetChildAt(radioId);
|
||||
|
||||
var textColor = Element.SelectedTextColor;
|
||||
var color = Element.IsEnabled ?
|
||||
textColor.IsDefault ? Element.TintColor.ToAndroid() : textColor.MultiplyAlpha(.6).ToAndroid() :
|
||||
Element.DisabledColor.ToAndroid();
|
||||
if (_rb != null)
|
||||
{
|
||||
_rb.SetTextColor(color);
|
||||
_rb.Paint.FakeBoldText = false;
|
||||
}
|
||||
rb.SetTextColor(Element.SelectedTextColor.ToAndroid());
|
||||
rb.Paint.FakeBoldText = true;
|
||||
_rb = rb;
|
||||
|
||||
Element.SelectedSegmentIndex = radioId;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (nativeControl != null)
|
||||
{
|
||||
nativeControl.CheckedChange -= NativeControl_ValueChanged;
|
||||
nativeControl.Dispose();
|
||||
nativeControl = null;
|
||||
_rb = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user