Pixiview/Gallery/UI/AdaptedPage.cs

194 lines
5.5 KiB
C#

using System;
using Gallery.UI.Theme;
using Gallery.Utils;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Gallery.UI
{
public class AdaptedPage : ContentPage
{
public static readonly BindableProperty PageTopMarginProperty = BindableProperty.Create(
nameof(PageTopMargin), typeof(Thickness), typeof(AdaptedPage));
public static readonly BindableProperty PanelTopMarginProperty = BindableProperty.Create(
nameof(PanelTopMargin), typeof(Thickness), typeof(AdaptedPage));
public Thickness PageTopMargin
{
get => (Thickness)GetValue(PageTopMarginProperty);
protected set => SetValue(PageTopMarginProperty, value);
}
public Thickness PanelTopMargin
{
get => (Thickness)GetValue(PanelTopMarginProperty);
protected set => SetValue(PanelTopMarginProperty, value);
}
public event EventHandler Load;
public event EventHandler Unload;
protected static readonly bool isPhone = DeviceInfo.Idiom == DeviceIdiom.Phone;
public AdaptedPage()
{
SetDynamicResource(Screen.StatusBarStyleProperty, ThemeBase.StatusBarStyle);
Shell.SetNavBarHasShadow(this, true);
}
public virtual void OnLoad()
{
Load?.Invoke(this, EventArgs.Empty);
}
public virtual void OnUnload()
{
Unload?.Invoke(this, EventArgs.Empty);
}
#if __IOS__
public virtual void OnOrientationChanged(bool landscape)
{
var oldMargin = PageTopMargin;
var oldPanelMargin = PanelTopMargin;
Thickness newMargin;
Thickness newPanelMargin;
if (StyleDefinition.IsFullscreenDevice)
{
var iPhone12 =
#if DEBUG
DeviceInfo.Name.StartsWith("iPhone 12") ||
#endif
DeviceInfo.Model.StartsWith("iPhone13,");
newMargin = landscape ?
AppShell.NavigationBarOffset :
AppShell.TotalBarOffset;
newPanelMargin = landscape ?
AppShell.HalfNavigationBarOffset :
AppShell.NavigationBarOffset;
}
else if (isPhone)
{
newMargin = landscape ?
StyleDefinition.TopOffset32 :
AppShell.TotalBarOffset;
newPanelMargin = landscape ?
StyleDefinition.TopOffset16 :
StyleDefinition.TopOffset32;
}
else
{
// iPad
newMargin = AppShell.TotalBarOffset;
newPanelMargin = StyleDefinition.TopOffset37;
}
if (oldMargin != newMargin)
{
PageTopMargin = newMargin;
OnPageTopMarginChanged(oldMargin, newMargin);
}
if (oldPanelMargin != newPanelMargin)
{
PanelTopMargin = newPanelMargin;
}
}
protected virtual void OnPageTopMarginChanged(Thickness old, Thickness @new) { }
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
OnOrientationChanged(width > height);
}
protected void AnimateToMargin(View element, Thickness margin, bool animate = true)
{
var m = margin;
var start = element.Margin.Top - m.Top;
#if DEBUG
if (start != 0)
{
App.DebugPrint($"{element.GetType()}, margin-top from {element.Margin.Top} to {margin.Top}");
}
#endif
element.Margin = m;
if (start > 0 && animate)
{
ViewExtensions.CancelAnimations(element);
element.Animate("margin", top =>
{
element.TranslationY = top;
},
start, 0,
#if DEBUG
length: 500,
#else
length: 300,
#endif
easing: Easing.SinInOut,
finished: (v, r) =>
{
element.TranslationY = 0;
});
}
}
#endif
protected void Start(Action action)
{
if (Tap.IsBusy)
{
#if LOG
App.DebugPrint("gesture recognizer is now busy...");
#endif
return;
}
using (Tap.Start())
{
action();
}
}
private class Tap : IDisposable
{
public static bool IsBusy
{
get
{
lock (sync)
{
return _instance?.isBusy == true;
}
}
}
private static readonly object sync = new object();
private static readonly Tap _instance = new Tap();
private Tap() { }
public static Tap Start()
{
lock (sync)
{
_instance.isBusy = true;
}
return _instance;
}
private bool isBusy = false;
public void Dispose()
{
isBusy = false;
}
}
}
public class ThicknessEventArgs : EventArgs
{
public Thickness OldMargin { get; set; }
public Thickness NewMargin { get; set; }
}
}