diff --git a/Ooui.Forms/Exports.cs b/Ooui.Forms/Exports.cs index 18a9908..566bd81 100644 --- a/Ooui.Forms/Exports.cs +++ b/Ooui.Forms/Exports.cs @@ -4,7 +4,7 @@ using Ooui.Forms.Renderers; using Xamarin.Forms; using Xamarin.Forms.Internals; - +[assembly: Dependency (typeof (ResourcesProvider))] [assembly: ExportRenderer (typeof (Button), typeof (ButtonRenderer))] namespace Ooui.Forms diff --git a/Ooui.Forms/IVisualElementRenderer.cs b/Ooui.Forms/IVisualElementRenderer.cs new file mode 100644 index 0000000..dbe6820 --- /dev/null +++ b/Ooui.Forms/IVisualElementRenderer.cs @@ -0,0 +1,9 @@ +using System; +using Xamarin.Forms; + +namespace Ooui.Forms +{ + public interface IVisualElementRenderer : IRegisterable, IDisposable + { + } +} diff --git a/Ooui.Forms/PageExtensions.cs b/Ooui.Forms/PageExtensions.cs index d9cc03d..8380447 100644 --- a/Ooui.Forms/PageExtensions.cs +++ b/Ooui.Forms/PageExtensions.cs @@ -1,26 +1,38 @@ using System; +using Xamarin.Forms; -namespace Ooui.Forms +namespace Xamarin.Forms { public static class PageExtensions { public static void Publish (this Xamarin.Forms.Page page, string path) { - UI.Publish (path, () => page.CreateElement ()); + Ooui.UI.Publish (path, () => page.CreateElement ()); } public static void PublishShared (this Xamarin.Forms.Page page, string path) { - var lazyPage = new Lazy ((() => page.CreateElement ()), true); - UI.Publish (path, () => lazyPage.Value); + var lazyPage = new Lazy ((() => page.CreateElement ()), true); + Ooui.UI.Publish (path, () => lazyPage.Value); } - public static Element CreateElement (this Xamarin.Forms.Page page) + public static Ooui.Element CreateElement (this Xamarin.Forms.Page page) { if (!Xamarin.Forms.Forms.IsInitialized) throw new InvalidOperationException ("call Forms.Init() before this"); - throw new NotImplementedException (); + if (!(page.RealParent is Application)) { + var app = new DefaultApplication (); + app.MainPage = page; + } + + var result = new Ooui.Forms.Platform (); + result.SetPage (page); + return result.Element; + } + + class DefaultApplication : Application + { } } } diff --git a/Ooui.Forms/Platform.cs b/Ooui.Forms/Platform.cs index 8a15080..1c7dcab 100644 --- a/Ooui.Forms/Platform.cs +++ b/Ooui.Forms/Platform.cs @@ -1,12 +1,30 @@ using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Ooui.Forms.Renderers; using Xamarin.Forms; using Xamarin.Forms.Internals; namespace Ooui.Forms { - public class Platform : BindableObject, IPlatform, IDisposable + public class Platform : BindableObject, IPlatform, INavigation, IDisposable { - bool _disposed; + bool _disposed; + + public Element Element { get; private set; } + + public Page Page { get; private set; } + + IReadOnlyList INavigation.ModalStack => throw new NotImplementedException (); + + IReadOnlyList INavigation.NavigationStack => throw new NotImplementedException (); + + public 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; + }); void IDisposable.Dispose() { @@ -17,11 +35,130 @@ namespace Ooui.Forms MessagingCenter.Unsubscribe(this, Page.ActionSheetSignalName); MessagingCenter.Unsubscribe(this, Page.AlertSignalName); MessagingCenter.Unsubscribe(this, Page.BusySetSignalName); + } + + public static IVisualElementRenderer CreateRenderer (VisualElement element) + { + var renderer = Registrar.Registered.GetHandler (element.GetType ()) ?? new DefaultRenderer (); + //renderer.SetElement (element); + return renderer; + } + + public static IVisualElementRenderer GetRenderer (VisualElement bindable) + { + return (IVisualElementRenderer)bindable.GetValue (RendererProperty); + } + + public static void SetRenderer (VisualElement bindable, IVisualElementRenderer value) + { + bindable.SetValue (RendererProperty, value); + } + + protected override void OnBindingContextChanged () + { + SetInheritedBindingContext (Page, BindingContext); + + base.OnBindingContextChanged (); } public SizeRequest GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint) { return new SizeRequest(new Size(100, 100)); } + + public void SetPage (Page newRoot) + { + if (newRoot == null) + return; + if (Page != null) + throw new NotImplementedException (); + Page = newRoot; + + Page.Platform = this; + AddChild (Page); + + //Page.DescendantRemoved += HandleChildRemoved; + + Application.Current.NavigationProxy.Inner = this; + } + + void AddChild (VisualElement view) + { + if (!Application.IsApplicationOrNull (view.RealParent)) + Console.Error.WriteLine ("Tried to add parented view to canvas directly"); + + if (GetRenderer (view) == null) { + var viewRenderer = CreateRenderer (view); + SetRenderer (view, viewRenderer); + + //_renderer.View.AddSubview (viewRenderer.NativeView); + //if (viewRenderer.ViewController != null) + // _renderer.AddChildViewController (viewRenderer.ViewController); + //viewRenderer.NativeView.Frame = new RectangleF (0, 0, _renderer.View.Bounds.Width, _renderer.View.Bounds.Height); + //viewRenderer.SetElementSize (new Size (_renderer.View.Bounds.Width, _renderer.View.Bounds.Height)); + } + else + Console.Error.WriteLine ("Potential view double add"); + } + + void INavigation.InsertPageBefore (Page page, Page before) + { + throw new NotImplementedException (); + } + + Task INavigation.PopAsync () + { + throw new NotImplementedException (); + } + + Task INavigation.PopAsync (bool animated) + { + throw new NotImplementedException (); + } + + Task INavigation.PopModalAsync () + { + throw new NotImplementedException (); + } + + Task INavigation.PopModalAsync (bool animated) + { + throw new NotImplementedException (); + } + + Task INavigation.PopToRootAsync () + { + throw new NotImplementedException (); + } + + Task INavigation.PopToRootAsync (bool animated) + { + throw new NotImplementedException (); + } + + Task INavigation.PushAsync (Page page) + { + throw new NotImplementedException (); + } + + Task INavigation.PushAsync (Page page, bool animated) + { + throw new NotImplementedException (); + } + + Task INavigation.PushModalAsync (Page page) + { + throw new NotImplementedException (); + } + + Task INavigation.PushModalAsync (Page page, bool animated) + { + throw new NotImplementedException (); + } + + void INavigation.RemovePage (Page page) + { + throw new NotImplementedException (); + } } } diff --git a/Ooui.Forms/Renderers/DefaultRenderer.cs b/Ooui.Forms/Renderers/DefaultRenderer.cs new file mode 100644 index 0000000..c727ce0 --- /dev/null +++ b/Ooui.Forms/Renderers/DefaultRenderer.cs @@ -0,0 +1,12 @@ +using System; +using Xamarin.Forms; + +namespace Ooui.Forms.Renderers +{ + public class DefaultRenderer : VisualElementRenderer + { + public DefaultRenderer () : base ("div") + { + } + } +} diff --git a/Ooui.Forms/Renderers/ElementRenderer.cs b/Ooui.Forms/Renderers/ElementRenderer.cs index e1eed11..75d4d79 100644 --- a/Ooui.Forms/Renderers/ElementRenderer.cs +++ b/Ooui.Forms/Renderers/ElementRenderer.cs @@ -3,7 +3,40 @@ using Xamarin.Forms; namespace Ooui.Forms.Renderers { - public class ElementRenderer where TElement : View where TNativeElement : Ooui.Element + public class ElementRenderer : IVisualElementRenderer where TElement : View where TNativeElement : Ooui.Element { + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose (bool disposing) + { + if (!disposedValue) { + if (disposing) { + // TODO: dispose managed state (managed objects). + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + disposedValue = true; + } + } + + // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. + // ~ElementRenderer() { + // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + // Dispose(false); + // } + + // This code added to correctly implement the disposable pattern. + public void Dispose () + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose (true); + // TODO: uncomment the following line if the finalizer is overridden above. + // GC.SuppressFinalize(this); + } + #endregion } } \ No newline at end of file diff --git a/Ooui.Forms/ResourcesProvider.cs b/Ooui.Forms/ResourcesProvider.cs new file mode 100644 index 0000000..824406f --- /dev/null +++ b/Ooui.Forms/ResourcesProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using Xamarin.Forms.Internals; + +namespace Ooui.Forms +{ + public class ResourcesProvider : ISystemResourcesProvider + { + readonly Res res = new Res (); + + public IResourceDictionary GetSystemResources () + { + return res; + } + + class Res : IResourceDictionary + { + readonly ConcurrentDictionary values = + new ConcurrentDictionary (); + + public event EventHandler ValuesChanged; + + public bool TryGetValue (string key, out object value) + { + return values.TryGetValue (key, out value); + } + + public IEnumerator> GetEnumerator () + { + return values.GetEnumerator (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return values.GetEnumerator (); + } + } + } +} diff --git a/Ooui.Forms/VisualElementRenderer.cs b/Ooui.Forms/VisualElementRenderer.cs new file mode 100644 index 0000000..948a9ad --- /dev/null +++ b/Ooui.Forms/VisualElementRenderer.cs @@ -0,0 +1,45 @@ +using System; +using Xamarin.Forms; + +namespace Ooui.Forms +{ + public class VisualElementRenderer : Element, IVisualElementRenderer where TElement : VisualElement + { + public VisualElementRenderer (string tagName) : base (tagName) + { + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose (bool disposing) + { + if (!disposedValue) { + if (disposing) { + // TODO: dispose managed state (managed objects). + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + disposedValue = true; + } + } + + // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. + // ~VisualElementRenderer() { + // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + // Dispose(false); + // } + + // This code added to correctly implement the disposable pattern. + public void Dispose () + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose (true); + // TODO: uncomment the following line if the finalizer is overridden above. + // GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/Ooui/UI.cs b/Ooui/UI.cs index deb7901..b18319b 100644 --- a/Ooui/UI.cs +++ b/Ooui/UI.cs @@ -402,6 +402,9 @@ namespace Ooui Element element = null; try { element = elementHandler.GetElement (); + + if (element == null) + throw new Exception ("Handler returned a null element"); } catch (Exception ex) { listenerContext.Response.StatusCode = 500;