2017-09-28 14:52:27 +03:00
|
|
|
|
using Gtk;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Xamarin.Forms.Internals;
|
|
|
|
|
using Xamarin.Forms.Platform.GTK.Helpers;
|
|
|
|
|
using Xamarin.Forms.Platform.GTK.Renderers;
|
|
|
|
|
|
|
|
|
|
namespace Xamarin.Forms.Platform.GTK
|
|
|
|
|
{
|
2018-11-01 00:12:22 +03:00
|
|
|
|
public class Platform : BindableObject, INavigation, IDisposable
|
2018-09-20 22:11:20 +03:00
|
|
|
|
{
|
|
|
|
|
private bool _disposed;
|
|
|
|
|
readonly List<Page> _modals;
|
|
|
|
|
private readonly PlatformRenderer _renderer;
|
|
|
|
|
|
|
|
|
|
internal static readonly BindableProperty RendererProperty =
|
|
|
|
|
BindableProperty.CreateAttached("Renderer", typeof(IVisualElementRenderer),
|
|
|
|
|
typeof(Platform), default(IVisualElementRenderer),
|
|
|
|
|
propertyChanged: (bindable, oldvalue, newvalue) =>
|
|
|
|
|
{
|
|
|
|
|
var view = bindable as VisualElement;
|
|
|
|
|
if (view != null)
|
|
|
|
|
view.IsPlatformEnabled = newvalue != null;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
internal PlatformRenderer PlatformRenderer => _renderer;
|
|
|
|
|
|
|
|
|
|
Page Page { get; set; }
|
|
|
|
|
|
|
|
|
|
IReadOnlyList<Page> INavigation.ModalStack
|
|
|
|
|
{
|
|
|
|
|
get { return _modals; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IReadOnlyList<Page> INavigation.NavigationStack
|
|
|
|
|
{
|
|
|
|
|
get { return new List<Page>(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal Platform()
|
|
|
|
|
{
|
|
|
|
|
_renderer = new PlatformRenderer(this);
|
|
|
|
|
_modals = new List<Page>();
|
|
|
|
|
Application.Current.NavigationProxy.Inner = this;
|
|
|
|
|
|
|
|
|
|
MessagingCenter.Subscribe(this, Page.AlertSignalName, (Page sender, AlertArguments arguments) => DialogHelper.ShowAlert(PlatformRenderer, arguments));
|
|
|
|
|
MessagingCenter.Subscribe(this, Page.ActionSheetSignalName, (Page sender, ActionSheetArguments arguments) => DialogHelper.ShowActionSheet(PlatformRenderer, arguments));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static void DisposeModelAndChildrenRenderers(Element view)
|
|
|
|
|
{
|
|
|
|
|
IVisualElementRenderer renderer;
|
|
|
|
|
|
|
|
|
|
foreach (VisualElement child in view.Descendants())
|
|
|
|
|
DisposeModelAndChildrenRenderers(child);
|
|
|
|
|
|
|
|
|
|
renderer = GetRenderer((VisualElement)view);
|
|
|
|
|
|
2018-10-30 20:06:47 +03:00
|
|
|
|
(renderer as Widget)?.Destroy();
|
2018-09-20 22:11:20 +03:00
|
|
|
|
view.ClearValue(RendererProperty);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 00:12:22 +03:00
|
|
|
|
public static SizeRequest GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
|
2018-09-20 22:11:20 +03:00
|
|
|
|
{
|
|
|
|
|
var renderView = GetRenderer(view);
|
|
|
|
|
|
|
|
|
|
if (renderView == null || renderView.Container == null)
|
|
|
|
|
return new SizeRequest(Size.Zero);
|
|
|
|
|
|
|
|
|
|
return renderView.GetDesiredSize(widthConstraint, heightConstraint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IVisualElementRenderer GetRenderer(VisualElement element)
|
|
|
|
|
{
|
|
|
|
|
return (IVisualElementRenderer)element.GetValue(RendererProperty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SetRenderer(VisualElement element, IVisualElementRenderer value)
|
|
|
|
|
{
|
|
|
|
|
if (element != null)
|
|
|
|
|
{
|
|
|
|
|
element.SetValue(RendererProperty, value);
|
|
|
|
|
element.IsPlatformEnabled = value != null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IVisualElementRenderer CreateRenderer(VisualElement element)
|
|
|
|
|
{
|
|
|
|
|
var renderer = Registrar.Registered.GetHandlerForObject<IVisualElementRenderer>(element) ?? new DefaultRenderer();
|
|
|
|
|
renderer.SetElement(element);
|
|
|
|
|
|
|
|
|
|
return renderer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IDisposable.Dispose()
|
|
|
|
|
{
|
|
|
|
|
if (_disposed)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_disposed = true;
|
2018-10-05 04:24:22 +03:00
|
|
|
|
|
2018-09-20 22:11:20 +03:00
|
|
|
|
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
|
|
|
|
|
MessagingCenter.Unsubscribe<Page, AlertArguments>(this, Page.AlertSignalName);
|
|
|
|
|
MessagingCenter.Unsubscribe<Page, bool>(this, Page.BusySetSignalName);
|
|
|
|
|
|
|
|
|
|
foreach (var modal in _modals)
|
|
|
|
|
DisposeModelAndChildrenRenderers(modal);
|
2018-10-30 20:06:47 +03:00
|
|
|
|
DisposeModelAndChildrenRenderers(Page);
|
2018-09-20 22:11:20 +03:00
|
|
|
|
|
2018-10-30 20:06:47 +03:00
|
|
|
|
PlatformRenderer.Destroy();
|
2018-09-20 22:11:20 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void SetPage(Page newRoot)
|
|
|
|
|
{
|
|
|
|
|
if (newRoot == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (Page != null)
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
Page = newRoot;
|
|
|
|
|
|
|
|
|
|
AddChild(Page);
|
|
|
|
|
|
|
|
|
|
Application.Current.NavigationProxy.Inner = this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddChild(Page mainPage)
|
|
|
|
|
{
|
|
|
|
|
var viewRenderer = GetRenderer(mainPage);
|
|
|
|
|
|
|
|
|
|
if (viewRenderer == null)
|
|
|
|
|
{
|
|
|
|
|
viewRenderer = CreateRenderer(mainPage);
|
|
|
|
|
SetRenderer(mainPage, viewRenderer);
|
|
|
|
|
|
|
|
|
|
PlatformRenderer.Add(viewRenderer.Container);
|
|
|
|
|
PlatformRenderer.ShowAll();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleChildRemoved(object sender, ElementEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var view = e.Element;
|
|
|
|
|
DisposeModelAndChildrenRenderers(view);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void INavigation.InsertPageBefore(Page page, Page before)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("InsertPageBefore is not supported globally on GTK, please use a NavigationPage.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task<Page> INavigation.PopAsync()
|
|
|
|
|
{
|
|
|
|
|
return ((INavigation)this).PopAsync(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task<Page> INavigation.PopAsync(bool animated)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("PopAsync is not supported globally on GTK, please use a NavigationPage.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task<Page> INavigation.PopModalAsync()
|
|
|
|
|
{
|
|
|
|
|
return ((INavigation)this).PopModalAsync(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task<Page> INavigation.PopModalAsync(bool animated)
|
|
|
|
|
{
|
|
|
|
|
var modal = _modals.Last();
|
|
|
|
|
_modals.Remove(modal);
|
|
|
|
|
modal.DescendantRemoved -= HandleChildRemoved;
|
|
|
|
|
|
|
|
|
|
var modalPage = GetRenderer(modal) as Container;
|
|
|
|
|
|
|
|
|
|
var pageControl = PlatformRenderer.Child as IPageControl;
|
|
|
|
|
|
|
|
|
|
Device.BeginInvokeOnMainThread(() =>
|
|
|
|
|
{
|
2018-10-02 21:45:16 +03:00
|
|
|
|
pageControl?.Control?.PopModal(modalPage);
|
2018-09-20 22:11:20 +03:00
|
|
|
|
|
|
|
|
|
DisposeModelAndChildrenRenderers(modal);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Task.FromResult<Page>(modal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task INavigation.PopToRootAsync()
|
|
|
|
|
{
|
|
|
|
|
return ((INavigation)this).PopToRootAsync(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task INavigation.PopToRootAsync(bool animated)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("PopToRootAsync is not supported globally on GTK, please use a NavigationPage.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task INavigation.PushAsync(Page root)
|
|
|
|
|
{
|
|
|
|
|
return ((INavigation)this).PushAsync(root, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task INavigation.PushAsync(Page root, bool animated)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("PushAsync is not supported globally on GTK, please use a NavigationPage.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task INavigation.PushModalAsync(Page modal)
|
|
|
|
|
{
|
|
|
|
|
return ((INavigation)this).PushModalAsync(modal, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Task INavigation.PushModalAsync(Page modal, bool animated)
|
|
|
|
|
{
|
|
|
|
|
_modals.Add(modal);
|
|
|
|
|
modal.DescendantRemoved += HandleChildRemoved;
|
|
|
|
|
|
|
|
|
|
var modalRenderer = GetRenderer(modal);
|
|
|
|
|
if (modalRenderer == null)
|
|
|
|
|
{
|
|
|
|
|
modalRenderer = CreateRenderer(modal);
|
|
|
|
|
SetRenderer(modal, modalRenderer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var pageControl = PlatformRenderer.Child as IPageControl;
|
|
|
|
|
|
|
|
|
|
Device.BeginInvokeOnMainThread(() =>
|
|
|
|
|
{
|
|
|
|
|
if (pageControl != null)
|
|
|
|
|
{
|
|
|
|
|
var page = pageControl.Control;
|
|
|
|
|
|
|
|
|
|
if (page != null)
|
|
|
|
|
{
|
2018-10-02 21:45:16 +03:00
|
|
|
|
page.PushModal(modalRenderer.Container);
|
2018-09-20 22:11:20 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Task.FromResult<object>(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void INavigation.RemovePage(Page page)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("RemovePage is not supported globally on GTK, please use a NavigationPage.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal class DefaultRenderer : VisualElementRenderer<VisualElement, Widget>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|