diff --git a/ReactWindows/Playground/App.xaml.cs b/ReactWindows/Playground/App.xaml.cs
index 5cf14d70460..f7562c9b5d1 100644
--- a/ReactWindows/Playground/App.xaml.cs
+++ b/ReactWindows/Playground/App.xaml.cs
@@ -1,18 +1,11 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
+using ReactNative;
+using ReactNative.Shell;
+using System;
using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Controls.Primitives;
-using Windows.UI.Xaml.Data;
-using Windows.UI.Xaml.Input;
-using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace Playground
@@ -22,6 +15,8 @@ namespace Playground
///
sealed partial class App : Application
{
+ private readonly ReactPage _reactPage;
+
///
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
@@ -33,6 +28,13 @@ public App()
Microsoft.ApplicationInsights.WindowsCollectors.Session);
this.InitializeComponent();
this.Suspending += OnSuspending;
+ this.Resuming += OnResuming;
+
+ _reactPage = new ReactPage(
+ "ms-appx:///Resources/main.dev.jsbundle",
+ "ReactRoot",
+ new[] { new MainReactPackage() }.ToList(),
+ () => { /* TODO: back button handling */ });
}
///
@@ -42,6 +44,8 @@ public App()
/// Details about the launch request and process.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
+ _reactPage.OnCreate();
+ _reactPage.OnResume();
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
@@ -75,8 +79,9 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
- rootFrame.Navigate(typeof(MainPage), e.Arguments);
+ rootFrame.Content = _reactPage;
}
+
// Ensure the current window is active
Window.Current.Activate();
}
@@ -101,8 +106,21 @@ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
+
//TODO: Save application state and stop any background activity
+ _reactPage.OnSuspend();
+
deferral.Complete();
}
+
+ ///
+ /// Invoked when application execution is being resumed.
+ ///
+ /// The source of the resume request.
+ /// Details about the resume request.
+ private void OnResuming(object sender, object e)
+ {
+ _reactPage.OnResume();
+ }
}
}
diff --git a/ReactWindows/Playground/MainPage.xaml b/ReactWindows/Playground/MainPage.xaml
deleted file mode 100644
index 778358f2df0..00000000000
--- a/ReactWindows/Playground/MainPage.xaml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ReactWindows/Playground/MainPage.xaml.cs b/ReactWindows/Playground/MainPage.xaml.cs
deleted file mode 100644
index 1fc6bd88177..00000000000
--- a/ReactWindows/Playground/MainPage.xaml.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using ReactNative.Hosting;
-using ReactNative.Hosting.Bridge;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Controls.Primitives;
-using Windows.UI.Xaml.Data;
-using Windows.UI.Xaml.Input;
-using Windows.UI.Xaml.Media;
-using Windows.UI.Xaml.Navigation;
-
-// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
-
-namespace Playground
-{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class MainPage : Page
- {
- public MainPage()
- {
- this.InitializeComponent();
- }
-
- private void LiftReactNativeApp()
- {
- var jsModuleName = "ReactRoot";
- var bundleAssetName = "ms-appx:///Resources/main.dev.jsbundle";
- RootView?.LiftAsync(bundleAssetName, jsModuleName);
- }
-
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- base.OnNavigatedTo(e);
- this.LiftReactNativeApp();
- }
- }
-}
diff --git a/ReactWindows/Playground/Playground.csproj b/ReactWindows/Playground/Playground.csproj
index e5ea7c85dcc..4c216aeedae 100644
--- a/ReactWindows/Playground/Playground.csproj
+++ b/ReactWindows/Playground/Playground.csproj
@@ -104,9 +104,6 @@
App.xaml
-
- MainPage.xaml
-
@@ -130,10 +127,6 @@
MSBuild:Compile
Designer
-
- MSBuild:Compile
- Designer
-
diff --git a/ReactWindows/ReactNative.Tests/Bridge/CatalystInstanceTests.cs b/ReactWindows/ReactNative.Tests/Bridge/CatalystInstanceTests.cs
index 6a4f7caf344..bad3debb068 100644
--- a/ReactWindows/ReactNative.Tests/Bridge/CatalystInstanceTests.cs
+++ b/ReactWindows/ReactNative.Tests/Bridge/CatalystInstanceTests.cs
@@ -31,7 +31,7 @@ public async Task CatalystInstance_GetModules()
QueueConfigurationSpec = CatalystQueueConfigurationSpec.Default,
Registry = registry,
JavaScriptModulesConfig = jsConfig,
- JavaScriptExecutor = executor,
+ JavaScriptExecutorFactory = () => executor,
BundleLoader = JavaScriptBundleLoader.CreateFileLoader("ms-appx:///Resources/test.js"),
NativeModuleCallExceptionHandler = _ => { }
};
@@ -63,7 +63,7 @@ public async Task CatalystInstance_Initialize_Dispose()
QueueConfigurationSpec = CatalystQueueConfigurationSpec.Default,
Registry = registry,
JavaScriptModulesConfig = jsConfig,
- JavaScriptExecutor = executor,
+ JavaScriptExecutorFactory = () => executor,
BundleLoader = JavaScriptBundleLoader.CreateFileLoader("ms-appx:///Resources/test.js"),
NativeModuleCallExceptionHandler = _ => { },
};
@@ -109,7 +109,7 @@ public async Task CatalystInstance_ExceptionHandled_Disposes()
QueueConfigurationSpec = CatalystQueueConfigurationSpec.Default,
Registry = registry,
JavaScriptModulesConfig = jsConfig,
- JavaScriptExecutor = executor,
+ JavaScriptExecutorFactory = () => executor,
BundleLoader = JavaScriptBundleLoader.CreateFileLoader("ms-appx:///Resources/test.js"),
NativeModuleCallExceptionHandler = handler,
};
diff --git a/ReactWindows/ReactNative.Tests/Bridge/ReactContextNativeModuleBaseTests.cs b/ReactWindows/ReactNative.Tests/Bridge/ReactContextNativeModuleBaseTests.cs
index f30d07bf7b8..1571dbd68be 100644
--- a/ReactWindows/ReactNative.Tests/Bridge/ReactContextNativeModuleBaseTests.cs
+++ b/ReactWindows/ReactNative.Tests/Bridge/ReactContextNativeModuleBaseTests.cs
@@ -14,14 +14,14 @@ public void ReactContextNativeModuleBase_ArgumentChecks()
() => new TestModule(null),
ex => Assert.AreEqual("reactContext", ex.ParamName));
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var module = new TestModule(context);
Assert.AreSame(context, module.Context);
}
class TestModule : ReactContextNativeModuleBase
{
- public TestModule(ReactApplicationContext reactContext)
+ public TestModule(ReactContext reactContext)
: base(reactContext)
{
}
diff --git a/ReactWindows/ReactNative.Tests/Internal/JavaScriptHelpers.cs b/ReactWindows/ReactNative.Tests/Internal/JavaScriptHelpers.cs
index 01103dc6720..5d3b10e7380 100644
--- a/ReactWindows/ReactNative.Tests/Internal/JavaScriptHelpers.cs
+++ b/ReactWindows/ReactNative.Tests/Internal/JavaScriptHelpers.cs
@@ -62,8 +62,6 @@ public static async Task Initialize(ChakraJavaScriptExecutor executor, IMessageQ
await jsQueueThread.CallOnQueue(() =>
{
- executor.Initialize();
-
foreach (var script in scripts)
{
executor.RunScript(script);
diff --git a/ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs b/ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs
index 1e3bc6125da..fa41bdb0889 100644
--- a/ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs
+++ b/ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs
@@ -19,7 +19,7 @@ public void ToastModule_Null_ArgumentsTest()
ex => Assert.AreEqual("reactContext", ex.ParamName));
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var module = new ToastModule(context);
Assert.AreSame(context, module.Context);
@@ -29,7 +29,7 @@ public void ToastModule_Null_ArgumentsTest()
[TestCategory(TEST_CATEGORY)]
public void Send_Toast_Invalid_Duration()
{
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var module = new ToastModule(context);
AssertEx.Throws(
@@ -41,7 +41,7 @@ public void Send_Toast_Invalid_Duration()
[TestCategory(TEST_CATEGORY)]
public void Send_Basic_Toast()
{
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var module = new ToastModule(context);
module.show("SHORT TOAST", 0);
@@ -51,7 +51,7 @@ public void Send_Basic_Toast()
[TestCategory(TEST_CATEGORY)]
public void Send_Long_Toast()
{
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var module = new ToastModule(context);
module.show("LONG TOAST container", 1);
diff --git a/ReactWindows/ReactNative.Tests/ReactInstanceManagerTests.cs b/ReactWindows/ReactNative.Tests/ReactInstanceManagerTests.cs
index 2aaa7df2bbd..e81255fb06c 100644
--- a/ReactWindows/ReactNative.Tests/ReactInstanceManagerTests.cs
+++ b/ReactWindows/ReactNative.Tests/ReactInstanceManagerTests.cs
@@ -1,5 +1,8 @@
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
-using ReactNative.Views;
+using ReactNative.Bridge;
+using ReactNative.Modules.Core;
+using System;
+using System.Threading;
using System.Threading.Tasks;
namespace ReactNative.Tests
@@ -7,14 +10,161 @@ namespace ReactNative.Tests
[TestClass]
public class ReactInstanceManagerTests
{
- //TODO: Looking into XAML custom control issue. This test is currently being ignored for the meantime until the issue has been resolved.
- public async Task ReactInstanceManagerInitializationSuccess()
- {
- var jsModuleName = "index.windows";
- var bundleAssetName = "ms-appx:///Resources/main.jsbundle";
- var rootView = await DispatcherHelpers.CallOnDispatcherAsync(() => new ReactRootView());
- rootView.LiftAsync(bundleAssetName, jsModuleName);
- Assert.AreEqual(rootView.TagId, 0);
+ [TestMethod]
+ public void ReactInstanceManager_Builder_SetterChecks()
+ {
+ AssertEx.Throws(
+ () => new ReactInstanceManager.Builder
+ {
+ JavaScriptBundleFile = "ms-appx:///Resources/main.jsbundle",
+ }.Build());
+
+ AssertEx.Throws(
+ () => new ReactInstanceManager.Builder
+ {
+ InitialLifecycleState = LifecycleState.Resumed,
+ }.Build());
+ }
+
+ [TestMethod]
+ public void ReactInstanceManager_ArgumentChecks()
+ {
+ var manager = CreateReactInstanceManager();
+
+ AssertEx.Throws(
+ () => manager.AttachMeasuredRootView(null),
+ ex => Assert.AreEqual("rootView", ex.ParamName));
+
+ AssertEx.Throws(
+ () => manager.CreateAllViewManagers(null),
+ ex => Assert.AreEqual("reactContext", ex.ParamName));
+
+ AssertEx.Throws(
+ () => manager.DetachRootView(null),
+ ex => Assert.AreEqual("rootView", ex.ParamName));
+
+ AssertEx.Throws(
+ () => manager.OnResume(null),
+ ex => Assert.AreEqual("onBackPressed", ex.ParamName));
+ }
+
+ [TestMethod]
+ public async Task ReactInstanceManager_CreateInBackground()
+ {
+ var jsBundleFile = "ms-appx:///Resources/test.js";
+ var manager = CreateReactInstanceManager(jsBundleFile);
+
+ var waitHandle = new AutoResetEvent(false);
+ manager.ReactContextInitialized += (sender, args) => waitHandle.Set();
+
+ await DispatcherHelpers.RunOnDispatcherAsync(
+ () => manager.CreateReactContextInBackground());
+
+ Assert.IsTrue(waitHandle.WaitOne());
+ Assert.AreEqual(jsBundleFile, manager.SourceUrl);
+ }
+
+ [TestMethod]
+ public async Task ReactInstanceManager_CreateInBackground_EnsuresOneCall()
+ {
+ var jsBundleFile = "ms-appx:///Resources/test.js";
+ var manager = CreateReactInstanceManager(jsBundleFile);
+
+ var waitHandle = new AutoResetEvent(false);
+ manager.ReactContextInitialized += (sender, args) => waitHandle.Set();
+
+ await AssertEx.ThrowsAsync(() =>
+ DispatcherHelpers.RunOnDispatcherAsync(() =>
+ {
+ manager.CreateReactContextInBackground();
+ manager.CreateReactContextInBackground();
+ }));
+ }
+
+ [TestMethod]
+ public async Task ReactInstanceManager_RecreateInBackground()
+ {
+ var jsBundleFile = "ms-appx:///Resources/test.js";
+ var manager = CreateReactInstanceManager(jsBundleFile);
+
+ var waitHandle = new AutoResetEvent(false);
+ manager.ReactContextInitialized += (sender, args) => waitHandle.Set();
+
+ await DispatcherHelpers.RunOnDispatcherAsync(() =>
+ {
+ manager.CreateReactContextInBackground();
+ manager.RecreateReactContextInBackground();
+ });
+
+ Assert.IsTrue(waitHandle.WaitOne());
+ Assert.IsTrue(waitHandle.WaitOne());
+ Assert.AreEqual(jsBundleFile, manager.SourceUrl);
+ }
+
+ [TestMethod]
+ public async Task ReactInstanceManager_RecreateInBackground_EnsuresCalledOnce()
+ {
+ var jsBundleFile = "ms-appx:///Resources/test.js";
+ var manager = CreateReactInstanceManager(jsBundleFile);
+
+ var waitHandle = new AutoResetEvent(false);
+ manager.ReactContextInitialized += (sender, args) => waitHandle.Set();
+
+ await AssertEx.ThrowsAsync(() =>
+ DispatcherHelpers.RunOnDispatcherAsync(() =>
+ manager.RecreateReactContextInBackground()));
+ }
+
+ [TestMethod]
+ public async Task ReactInstanceManager_OnBackPressed_NoContext()
+ {
+ var waitHandle = new AutoResetEvent(false);
+ var manager = CreateReactInstanceManager();
+ await DispatcherHelpers.RunOnDispatcherAsync(() =>
+ {
+ manager.OnResume(() => waitHandle.Set());
+ manager.OnBackPressed();
+ });
+
+ Assert.IsTrue(waitHandle.WaitOne());
+ }
+
+ [TestMethod]
+ public async Task ReactInstanceManager_OnDestroy_CreateInBackground()
+ {
+ var jsBundleFile = "ms-appx:///Resources/test.js";
+ var manager = CreateReactInstanceManager(jsBundleFile);
+
+ var waitHandle = new AutoResetEvent(false);
+ manager.ReactContextInitialized += (sender, args) => waitHandle.Set();
+
+ await DispatcherHelpers.RunOnDispatcherAsync(
+ () => manager.CreateReactContextInBackground());
+
+ Assert.IsTrue(waitHandle.WaitOne());
+ Assert.AreEqual(jsBundleFile, manager.SourceUrl);
+
+ await DispatcherHelpers.RunOnDispatcherAsync(
+ () => manager.OnDestroy());
+
+ await DispatcherHelpers.RunOnDispatcherAsync(
+ () => manager.CreateReactContextInBackground());
+
+ Assert.IsTrue(waitHandle.WaitOne());
+ }
+
+ private static ReactInstanceManager CreateReactInstanceManager()
+ {
+ return CreateReactInstanceManager("ms-appx:///Resources/main.jsbundle");
+ }
+
+ private static ReactInstanceManager CreateReactInstanceManager(string jsBundleFile)
+ {
+ return new ReactInstanceManager.Builder
+ {
+ InitialLifecycleState = LifecycleState.Resumed,
+ JavaScriptBundleFile = jsBundleFile,
+ }.Build();
}
}
}
diff --git a/ReactWindows/ReactNative.Tests/UIManager/Events/EventDispatcherTests.cs b/ReactWindows/ReactNative.Tests/UIManager/Events/EventDispatcherTests.cs
index fc2cec07392..80b2bab9057 100644
--- a/ReactWindows/ReactNative.Tests/UIManager/Events/EventDispatcherTests.cs
+++ b/ReactWindows/ReactNative.Tests/UIManager/Events/EventDispatcherTests.cs
@@ -18,7 +18,7 @@ public void EventDispatcher_ArgumentChecks()
{
AssertEx.Throws(() => new EventDispatcher(null), ex => Assert.AreEqual("reactContext", ex.ParamName));
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var dispatcher = new EventDispatcher(context);
AssertEx.Throws(() => dispatcher.DispatchEvent(null), ex => Assert.AreEqual("event", ex.ParamName));
}
@@ -26,7 +26,7 @@ public void EventDispatcher_ArgumentChecks()
[TestMethod]
public void EventDispatcher_IncorrectThreadCalls()
{
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var dispatcher = new EventDispatcher(context);
AssertEx.Throws(() => dispatcher.OnResume());
@@ -269,7 +269,7 @@ public async Task EventDispatcher_OnShutdown_EventDoesNotDispatch()
using (BlockJavaScriptThread(context))
{
dispatcher.DispatchEvent(testEvent);
- await DispatcherHelpers.RunOnDispatcherAsync(dispatcher.OnShutdown);
+ await DispatcherHelpers.RunOnDispatcherAsync(dispatcher.OnDestroy);
}
Assert.IsFalse(waitDispatched.WaitOne(500));
@@ -325,11 +325,11 @@ public async Task EventDispatcher_DispatchedAfterSuspend_ThenResume()
Assert.IsTrue(waitDispatched.WaitOne());
}
- private static async Task CreateContextAsync(IJavaScriptExecutor executor)
+ private static async Task CreateContextAsync(IJavaScriptExecutor executor)
{
var catalystInstance = await DispatcherHelpers.CallOnDispatcherAsync(() => CreateCatalystInstance(executor));
await InitializeCatalystInstanceAsync(catalystInstance);
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
context.InitializeWithInstance(catalystInstance);
return context;
}
@@ -347,7 +347,7 @@ private static CatalystInstance CreateCatalystInstance(IJavaScriptExecutor execu
BundleLoader = JavaScriptBundleLoader.CreateFileLoader("ms-appx:///Resources/test.js"),
JavaScriptModulesConfig = jsModules,
Registry = registry,
- JavaScriptExecutor = executor,
+ JavaScriptExecutorFactory = () => executor,
NativeModuleCallExceptionHandler = ex => Assert.Fail(ex.ToString()),
}.Build();
diff --git a/ReactWindows/ReactNative.Tests/UIManager/UIManagerModuleTests.cs b/ReactWindows/ReactNative.Tests/UIManager/UIManagerModuleTests.cs
index 28ac4c75a22..7cdcfa419b3 100644
--- a/ReactWindows/ReactNative.Tests/UIManager/UIManagerModuleTests.cs
+++ b/ReactWindows/ReactNative.Tests/UIManager/UIManagerModuleTests.cs
@@ -15,7 +15,7 @@ public class UIManagerModuleTests
[TestMethod]
public void UIManagerModule_ArgumentChecks()
{
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var viewManagers = new List();
var uiImplementation = new UIImplementation(context, viewManagers);
@@ -31,7 +31,7 @@ public void UIManagerModule_ArgumentChecks()
[TestMethod]
public void UIManagerModule_CustomEvents_Constants()
{
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var viewManagers = new List();
var uiImplementation = new UIImplementation(context, viewManagers);
@@ -59,7 +59,7 @@ public void UIManagerModule_CustomEvents_Constants()
[TestMethod]
public void UIManagerModule_Constants_ViewManagerOverrides()
{
- var context = new ReactApplicationContext();
+ var context = new ReactContext();
var viewManagers = new List { new TestViewManager() };
var uiImplementation = new UIImplementation(context, viewManagers);
diff --git a/ReactWindows/ReactNative/Bridge/CatalystInstance.cs b/ReactWindows/ReactNative/Bridge/CatalystInstance.cs
index 5866e86c8fb..ab1186f6aee 100644
--- a/ReactWindows/ReactNative/Bridge/CatalystInstance.cs
+++ b/ReactWindows/ReactNative/Bridge/CatalystInstance.cs
@@ -20,7 +20,7 @@ class CatalystInstance : ICatalystInstance, IDisposable
{
private readonly NativeModuleRegistry _registry;
private readonly JavaScriptModuleRegistry _jsRegistry;
- private readonly IJavaScriptExecutor _jsExecutor;
+ private readonly Func _jsExecutorFactory;
private readonly JavaScriptBundleLoader _bundleLoader;
private readonly JavaScriptModulesConfig _jsModulesConfig;
private readonly Action _nativeModuleCallExceptionHandler;
@@ -31,14 +31,14 @@ class CatalystInstance : ICatalystInstance, IDisposable
private CatalystInstance(
CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,
- IJavaScriptExecutor jsExecutor,
+ Func jsExecutorFactory,
NativeModuleRegistry registry,
JavaScriptModulesConfig jsModulesConfig,
JavaScriptBundleLoader bundleLoader,
Action nativeModuleCallExceptionHandler)
{
_registry = registry;
- _jsExecutor = jsExecutor;
+ _jsExecutorFactory = jsExecutorFactory;
_jsModulesConfig = jsModulesConfig;
_nativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
_bundleLoader = bundleLoader;
@@ -90,6 +90,35 @@ public void Initialize()
_registry.NotifyCatalystInstanceInitialize();
}
+ public async Task InitializeBridgeAsync()
+ {
+ await _bundleLoader.InitializeAsync();
+
+ await QueueConfiguration.JSQueueThread.CallOnQueue(() =>
+ {
+ QueueConfiguration.JSQueueThread.AssertIsOnThread();
+
+ var jsExecutor = _jsExecutorFactory();
+
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "ReactBridgeCtor"))
+ {
+ _bridge = new ReactBridge(
+ jsExecutor,
+ new NativeModulesReactCallback(this),
+ QueueConfiguration.NativeModulesQueueThread);
+ }
+
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "setBatchedBridgeConfig"))
+ {
+ _bridge.SetGlobalVariable("__fbBatchedBridgeConfig", BuildModulesConfig());
+ }
+
+ _bundleLoader.LoadScript(jsExecutor);
+
+ return _bridge;
+ });
+ }
+
public void InvokeCallback(int callbackId, JArray arguments)
{
if (IsDisposed)
@@ -151,35 +180,6 @@ public void Dispose()
// TODO: notify bridge idle listeners
}
- public async Task InitializeBridgeAsync()
- {
- await _bundleLoader.InitializeAsync();
-
- await QueueConfiguration.JSQueueThread.CallOnQueue(() =>
- {
- QueueConfiguration.JSQueueThread.AssertIsOnThread();
-
- _jsExecutor.Initialize();
-
- using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "ReactBridgeCtor"))
- {
- _bridge = new ReactBridge(
- _jsExecutor,
- new NativeModulesReactCallback(this),
- QueueConfiguration.NativeModulesQueueThread);
- }
-
- using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "setBatchedBridgeConfig"))
- {
- _bridge.SetGlobalVariable("__fbBatchedBridgeConfig", BuildModulesConfig());
- }
-
- _bundleLoader.LoadScript(_jsExecutor);
-
- return _bridge;
- });
- }
-
private string BuildModulesConfig()
{
using (var stringWriter = new StringWriter())
@@ -209,7 +209,7 @@ public sealed class Builder
private CatalystQueueConfigurationSpec _catalystQueueConfigurationSpec;
private NativeModuleRegistry _registry;
private JavaScriptModulesConfig _jsModulesConfig;
- private IJavaScriptExecutor _jsExecutor;
+ private Func _jsExecutorFactory;
private JavaScriptBundleLoader _bundleLoader;
private Action _nativeModuleCallExceptionHandler;
@@ -237,11 +237,11 @@ public JavaScriptModulesConfig JavaScriptModulesConfig
}
}
- public IJavaScriptExecutor JavaScriptExecutor
+ public Func JavaScriptExecutorFactory
{
set
{
- _jsExecutor = value;
+ _jsExecutorFactory = value;
}
}
@@ -264,7 +264,7 @@ public Action NativeModuleCallExceptionHandler
public CatalystInstance Build()
{
AssertNotNull(_catalystQueueConfigurationSpec, nameof(QueueConfigurationSpec));
- AssertNotNull(_jsExecutor, nameof(IJavaScriptExecutor));
+ AssertNotNull(_jsExecutorFactory, nameof(JavaScriptExecutorFactory));
AssertNotNull(_registry, nameof(Registry));
AssertNotNull(_jsModulesConfig, nameof(JavaScriptModulesConfig));
AssertNotNull(_bundleLoader, nameof(BundleLoader));
@@ -272,7 +272,7 @@ public CatalystInstance Build()
return new CatalystInstance(
_catalystQueueConfigurationSpec,
- _jsExecutor,
+ _jsExecutorFactory,
_registry,
_jsModulesConfig,
_bundleLoader,
diff --git a/ReactWindows/ReactNative/Bridge/IJavaScriptExecutor.cs b/ReactWindows/ReactNative/Bridge/IJavaScriptExecutor.cs
index e2cd23207a9..1a226e0bab2 100644
--- a/ReactWindows/ReactNative/Bridge/IJavaScriptExecutor.cs
+++ b/ReactWindows/ReactNative/Bridge/IJavaScriptExecutor.cs
@@ -8,14 +8,6 @@ namespace ReactNative.Bridge
///
public interface IJavaScriptExecutor : IDisposable
{
- ///
- /// Initializes the JavaScript runtime.
- ///
- ///
- /// Must be called from the JavaScript thread.
- ///
- void Initialize();
-
///
/// Call the JavaScript method from the given module.
///
diff --git a/ReactWindows/ReactNative/Bridge/ILifecycleEventListener.cs b/ReactWindows/ReactNative/Bridge/ILifecycleEventListener.cs
index 55f17974718..86f40947bf7 100644
--- a/ReactWindows/ReactNative/Bridge/ILifecycleEventListener.cs
+++ b/ReactWindows/ReactNative/Bridge/ILifecycleEventListener.cs
@@ -18,6 +18,6 @@ public interface ILifecycleEventListener
///
/// Called when the host is shutting down.
///
- void OnShutdown();
+ void OnDestroy();
}
}
diff --git a/ReactWindows/ReactNative/Bridge/ReactApplicationContext.cs b/ReactWindows/ReactNative/Bridge/ReactApplicationContext.cs
deleted file mode 100644
index be30cf4a7ed..00000000000
--- a/ReactWindows/ReactNative/Bridge/ReactApplicationContext.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-
-namespace ReactNative.Bridge
-{
- ///
- /// This class serves as a base class on top of .
- ///
- public class ReactApplicationContext : ReactContext
- {
- public ReactApplicationContext()
- {
- }
- }
-}
diff --git a/ReactWindows/ReactNative/Bridge/ReactContext.cs b/ReactWindows/ReactNative/Bridge/ReactContext.cs
index 738825d7985..39c40007d79 100644
--- a/ReactWindows/ReactNative/Bridge/ReactContext.cs
+++ b/ReactWindows/ReactNative/Bridge/ReactContext.cs
@@ -9,7 +9,7 @@ namespace ReactNative.Bridge
/// Abstract context wrapper for the catalyst instance to manage
/// lifecycle events.
///
- public abstract class ReactContext
+ public class ReactContext
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private readonly List _lifecycleEventListeners =
@@ -162,7 +162,7 @@ public void OnResume()
///
/// Called by the host when the application shuts down.
///
- public void OnShutdown()
+ public void OnDestroy()
{
DispatcherHelpers.AssertOnDispatcher();
@@ -180,7 +180,13 @@ public void OnShutdown()
foreach (var listener in clone)
{
- listener.OnShutdown();
+ listener.OnDestroy();
+ }
+
+ var catalystInstance = _catalystInstance;
+ if (catalystInstance != null)
+ {
+ catalystInstance.Dispose();
}
}
diff --git a/ReactWindows/ReactNative/Bridge/ReactContextNativeModuleBase.cs b/ReactWindows/ReactNative/Bridge/ReactContextNativeModuleBase.cs
index 8c70c2bc6b1..ae32f2b9116 100644
--- a/ReactWindows/ReactNative/Bridge/ReactContextNativeModuleBase.cs
+++ b/ReactWindows/ReactNative/Bridge/ReactContextNativeModuleBase.cs
@@ -12,7 +12,7 @@ public abstract class ReactContextNativeModuleBase : NativeModuleBase
/// Instantiates the .
///
/// The React context.
- protected ReactContextNativeModuleBase(ReactApplicationContext reactContext)
+ protected ReactContextNativeModuleBase(ReactContext reactContext)
{
if (reactContext == null)
throw new ArgumentNullException(nameof(reactContext));
@@ -23,6 +23,6 @@ protected ReactContextNativeModuleBase(ReactApplicationContext reactContext)
///
/// The React context.
///
- public ReactApplicationContext Context { get; }
+ public ReactContext Context { get; }
}
}
diff --git a/ReactWindows/ReactNative/CoreModulesPackage.cs b/ReactWindows/ReactNative/CoreModulesPackage.cs
index 40b720f582c..cc7ee34b8a5 100644
--- a/ReactWindows/ReactNative/CoreModulesPackage.cs
+++ b/ReactWindows/ReactNative/CoreModulesPackage.cs
@@ -23,12 +23,12 @@ namespace ReactNative
class CoreModulesPackage : IReactPackage
{
private readonly IReactInstanceManager _reactInstanceManager;
- private readonly IDefaultHardwareBackButtonHandler _hardwareBackButtonHandler;
+ private readonly Action _hardwareBackButtonHandler;
private readonly UIImplementationProvider _uiImplementationProvider;
public CoreModulesPackage(
IReactInstanceManager reactInstanceManager,
- IDefaultHardwareBackButtonHandler hardwareBackButtonHandler,
+ Action hardwareBackButtonHandler,
UIImplementationProvider uiImplementationProvider)
{
_reactInstanceManager = reactInstanceManager;
@@ -36,7 +36,7 @@ public CoreModulesPackage(
_uiImplementationProvider = uiImplementationProvider;
}
- public IReadOnlyList CreateNativeModules(ReactApplicationContext reactContext)
+ public IReadOnlyList CreateNativeModules(ReactContext reactContext)
{
var uiManagerModule = default(INativeModule);
using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "createUIManagerModule"))
@@ -71,7 +71,7 @@ public IReadOnlyList CreateJavaScriptModulesConfig()
}
public IReadOnlyList CreateViewManagers(
- ReactApplicationContext reactContext)
+ ReactContext reactContext)
{
return new List(0);
}
diff --git a/ReactWindows/ReactNative/Hosting/Bridge/ChakraJavaScriptExecutor.cs b/ReactWindows/ReactNative/Hosting/Bridge/ChakraJavaScriptExecutor.cs
index 9d8beecae65..9cd1060f023 100644
--- a/ReactWindows/ReactNative/Hosting/Bridge/ChakraJavaScriptExecutor.cs
+++ b/ReactWindows/ReactNative/Hosting/Bridge/ChakraJavaScriptExecutor.cs
@@ -14,24 +14,16 @@ namespace ReactNative.Hosting.Bridge
///
public class ChakraJavaScriptExecutor : IJavaScriptExecutor
{
- private JavaScriptRuntime _runtime;
- private JavaScriptValue _globalObject;
+ private readonly JavaScriptRuntime _runtime;
+ private readonly JavaScriptValue _globalObject;
private JavaScriptSourceContext _sourceContext = JavaScriptSourceContext.None;
///
- /// Initializes the JavaScript runtime.
+ /// Instantiates the .
///
- ///
- /// Must be called from the JavaScript thread.
- ///
- public void Initialize()
+ public ChakraJavaScriptExecutor()
{
- if (_runtime.IsValid)
- {
- throw new InvalidOperationException("JavaScript runtime already initialized for this thread.");
- }
-
_runtime = JavaScriptRuntime.Create();
InitializeChakra();
_globalObject = JavaScriptValue.GlobalObject;
diff --git a/ReactWindows/ReactNative/IReactInstanceManager.cs b/ReactWindows/ReactNative/IReactInstanceManager.cs
index 31dcd595b22..3e90c2cdce4 100644
--- a/ReactWindows/ReactNative/IReactInstanceManager.cs
+++ b/ReactWindows/ReactNative/IReactInstanceManager.cs
@@ -11,58 +11,114 @@
namespace ReactNative
{
///
- /// This interface manages instances of . It expose a way to configure
- /// catalyst instance using and keeps track of the lifecycle of that
- /// instance.It also sets up connection between the instance and developers support functionality
- /// of the framework.
+ /// This interface manages instances of .
+ /// It exposes a way to configure catalyst instances using
+ /// and keeps track of the lifecycle of that
+ /// instance. It also sets up a connection between the instance and the
+ /// developer support functionality of the framework.
///
- /// An instance of this manager is required to start JS application in
- /// #startReactApplication for more info).
+ /// An instance of this manager is required to start the JavaScript
+ /// application in
+ /// ().
///
- /// The lifecycle of the instance of should be bound to the activity
- /// that owns the that is used to render react application using this
- /// instance manager . It's required to pass
- /// owning activity's lifecycle events to the instance manager #onPause, #onDestroy, #onResume
- /// TODO:
- /// 1.Add lifecycle event hooks
- /// 2.Add background mode
+ /// The lifecycle of the instance of
+ /// should be bound to the application that owns the
+ /// that is used to render the react
+ /// application using this instance manager. It is required to pass
+ /// lifecycle events to the instance manager (i.e., ,
+ /// , and ).
///
- public interface IReactInstanceManager : IDisposable
+ public interface IReactInstanceManager
{
- IReadOnlyList CreateAllViewManagers(ReactApplicationContext catalystApplicationContext);
+ ///
+ /// Event triggered when a react context has been initialized.
+ ///
+ event EventHandler ReactContextInitialized;
+
+ ///
+ /// Signals whether has
+ /// been called. Will return false
after
+ /// until a new initial context has been created.
+ ///
+ bool HasStartedCreatingInitialContext { get; }
+
+ ///
+ /// The URL where the last bundle was loaded from.
+ ///
+ string SourceUrl { get; }
+
+ ///
+ /// The current react context.
+ ///
+ ReactContext CurrentReactContext { get; }
///
- /// Trigger react context initialization asynchronously in a background async task.
+ /// Trigger the react context initialization asynchronously in a
+ /// background task. This enables applications to pre-load the
+ /// application JavaScript, and execute global core code before the
+ /// is available and measure. This should
+ /// only be called the first time the application is set up, which is
+ /// enforced to keep developers from accidentally creating their
+ /// applications multiple times.
///
- //public abstract void createReactContextInBackground();
+ void CreateReactContextInBackground();
///
- /// return whether createReactContextInBackground has been called
+ /// Method that gives JavaScript the opportunity to consume the back
+ /// button event. If JavaScript does not consume the event, the
+ /// default back press action will be invoked at the end of the
+ ///roundtrip to JavaScript.
///
- ///
- //public abstract bool hasStartedCreatingInitialContext();
+ void OnBackPressed();
- //public abstract void onBackPressed();
- //public abstract void onPause();
+ ///
+ /// Invoked when the application is suspended.
+ ///
+ void OnSuspend();
- //public abstract void onResume(DefaultHardwareBackBtnHandler defaultBackButtonImpl);
+ ///
+ /// Used when the application resumes to reset the back button handling
+ /// in JavaScript.
+ ///
+ ///
+ /// The action to take when back is pressed.
+ ///
+ void OnResume(Action onBackPressed);
+
+ ///
+ /// Destroy the .
+ ///
+ void OnDestroy();
///
- /// Attach given {@param rootView} to a catalyst instance manager and start JS application
+ /// Attach given to a catalyst instance
+ /// manager and start the JavaScript application using the JavaScript
+ /// module provided by the . If
+ /// the react context is currently being (re-)created, or if the react
+ /// context has not been created yet, the JavaScript application
+ /// associated with the provided root view will be started
+ /// asynchronously. This view will then be tracked by this manager and
+ /// in case of catalyst instance restart, it will be re-attached.
///
- /// The root view of the ReactJS app
+ /// The root view.
void AttachMeasuredRootView(ReactRootView rootView);
///
- /// Detach given rootView from current catalyst instance.
+ /// Detach given from the current catalyst
+ /// instance. This method is idempotent and can be called multiple
+ /// times on the same instance.
///
- /// The root view of the ReactJS app
+ /// The root view.
void DetachRootView(ReactRootView rootView);
///
- /// Loads the based on the user configured bundle instances to create
+ /// all s.
///
- Task RecreateReactContextInBackgroundFromBundleFileAsync();
-
+ ///
+ /// The application context.
+ ///
+ /// The list of view managers.
+ IReadOnlyList CreateAllViewManagers(ReactContext reactContext);
}
}
diff --git a/ReactWindows/ReactNative/IReactPackage.cs b/ReactWindows/ReactNative/IReactPackage.cs
index 2ed4b0bbe96..bf43ad34aee 100644
--- a/ReactWindows/ReactNative/IReactPackage.cs
+++ b/ReactWindows/ReactNative/IReactPackage.cs
@@ -30,7 +30,7 @@ public interface IReactPackage
///
/// The react application context.
/// The list of native modules.
- IReadOnlyList CreateNativeModules(ReactApplicationContext reactContext);
+ IReadOnlyList CreateNativeModules(ReactContext reactContext);
///
/// Creates the list of JavaScript modules to register with the
@@ -51,6 +51,6 @@ public interface IReactPackage
///
/// The react application context.
/// The list of view managers.
- IReadOnlyList CreateViewManagers(ReactApplicationContext reactContext);
+ IReadOnlyList CreateViewManagers(ReactContext reactContext);
}
}
diff --git a/ReactWindows/ReactNative/LifecycleState.cs b/ReactWindows/ReactNative/LifecycleState.cs
index bb3816add09..8dc003c3a8e 100644
--- a/ReactWindows/ReactNative/LifecycleState.cs
+++ b/ReactWindows/ReactNative/LifecycleState.cs
@@ -1,11 +1,11 @@
namespace ReactNative
{
///
- /// A enumeration to signify the current lifecycle state for a .
+ /// A enumeration to signify the current lifecycle state for a .
///
public enum LifecycleState
{
- BEFORE_RESUME,
- RESUMED,
+ BeforeResume,
+ Resumed,
}
}
diff --git a/ReactWindows/ReactNative/Modules/Core/DeviceEventManagerModule.cs b/ReactWindows/ReactNative/Modules/Core/DeviceEventManagerModule.cs
index 9e13fe7cfe3..0773b31a997 100644
--- a/ReactWindows/ReactNative/Modules/Core/DeviceEventManagerModule.cs
+++ b/ReactWindows/ReactNative/Modules/Core/DeviceEventManagerModule.cs
@@ -14,16 +14,18 @@ public class DeviceEventManagerModule : ReactContextNativeModuleBase
/// Instantiates the .
///
/// The react context.
- /// The back button handler.
+ ///
+ /// The action to take when back is pressed.
+ ///
public DeviceEventManagerModule(
- ReactApplicationContext reactContext,
- IDefaultHardwareBackButtonHandler backButtonHandler)
+ ReactContext reactContext,
+ Action onBackPressed)
: base(reactContext)
{
_invokeDefaultBackPressAction = () =>
{
DispatcherHelpers.AssertOnDispatcher();
- backButtonHandler.InvokeDefaultOnBackPressed();
+ onBackPressed();
};
}
diff --git a/ReactWindows/ReactNative/Modules/Core/IDefaultHardwareBackButtonHandler.cs b/ReactWindows/ReactNative/Modules/Core/IDefaultHardwareBackButtonHandler.cs
deleted file mode 100644
index eceba259653..00000000000
--- a/ReactWindows/ReactNative/Modules/Core/IDefaultHardwareBackButtonHandler.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace ReactNative.Modules.Core
-{
- ///
- /// Interface used by to delegate
- /// hardware back button events. It is suppose to provide a default
- /// behavior since it would be triggered in the case when the JavaScript
- /// side does not want to handle back press events.
- ///
- public interface IDefaultHardwareBackButtonHandler
- {
- ///
- /// By default, all back press calls should not execute the default
- /// backpress handler and should instead propagate it to the JavaScript
- /// instance. If JavaScript doesn't want to handle the back press
- /// itself, it shall call back into native to invoke this function,
- /// which should execute the default handler.
- ///
- void InvokeDefaultOnBackPressed();
- }
-}
diff --git a/ReactWindows/ReactNative/Modules/Core/Timing.cs b/ReactWindows/ReactNative/Modules/Core/Timing.cs
index 339152c82a1..d8b31b13f08 100644
--- a/ReactWindows/ReactNative/Modules/Core/Timing.cs
+++ b/ReactWindows/ReactNative/Modules/Core/Timing.cs
@@ -8,7 +8,7 @@ namespace ReactNative.Modules.Core
///
public class Timing : ReactContextNativeModuleBase
{
- public Timing(ReactApplicationContext reactContext)
+ public Timing(ReactContext reactContext)
: base(reactContext)
{
}
diff --git a/ReactWindows/ReactNative/Modules/Toast/ToastModule.cs b/ReactWindows/ReactNative/Modules/Toast/ToastModule.cs
index 0b962575936..0ea184422ac 100644
--- a/ReactWindows/ReactNative/Modules/Toast/ToastModule.cs
+++ b/ReactWindows/ReactNative/Modules/Toast/ToastModule.cs
@@ -11,7 +11,7 @@ public sealed class ToastModule : ReactContextNativeModuleBase
const string DURATION_SHORT_KEY = "SHORT";
const string DURATION_LONG_KEY = "LONG";
- public ToastModule(ReactApplicationContext reactContext)
+ public ToastModule(ReactContext reactContext)
: base(reactContext)
{ }
diff --git a/ReactWindows/ReactNative/Modules/WebSocket/WebSocketModule.cs b/ReactWindows/ReactNative/Modules/WebSocket/WebSocketModule.cs
index 338b1a2adb2..8fc68876ef5 100644
--- a/ReactWindows/ReactNative/Modules/WebSocket/WebSocketModule.cs
+++ b/ReactWindows/ReactNative/Modules/WebSocket/WebSocketModule.cs
@@ -4,7 +4,7 @@ namespace ReactNative.Modules.WebSocket
{
class WebSocketModule : ReactContextNativeModuleBase
{
- public WebSocketModule(ReactApplicationContext reactContext)
+ public WebSocketModule(ReactContext reactContext)
: base(reactContext)
{
}
diff --git a/ReactWindows/ReactNative/ReactContextInitializedEventArgs.cs b/ReactWindows/ReactNative/ReactContextInitializedEventArgs.cs
new file mode 100644
index 00000000000..dcb5fc9f9b0
--- /dev/null
+++ b/ReactWindows/ReactNative/ReactContextInitializedEventArgs.cs
@@ -0,0 +1,26 @@
+using ReactNative.Bridge;
+using System;
+
+namespace ReactNative
+{
+ ///
+ /// Event arguments for the
+ /// event.
+ ///
+ public sealed class ReactContextInitializedEventArgs : EventArgs
+ {
+ ///
+ /// Instantiates the .
+ ///
+ /// The react context.
+ internal ReactContextInitializedEventArgs(ReactContext context)
+ {
+ Context = context;
+ }
+
+ ///
+ /// The react context.
+ ///
+ public ReactContext Context { get; }
+ }
+}
diff --git a/ReactWindows/ReactNative/ReactInstanceManager.cs b/ReactWindows/ReactNative/ReactInstanceManager.cs
new file mode 100644
index 00000000000..015d5dc6270
--- /dev/null
+++ b/ReactWindows/ReactNative/ReactInstanceManager.cs
@@ -0,0 +1,685 @@
+using ReactNative.Bridge;
+using ReactNative.Bridge.Queue;
+using ReactNative.Common;
+using ReactNative.Hosting.Bridge;
+using ReactNative.Modules.Core;
+using ReactNative.Tracing;
+using ReactNative.UIManager;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Threading.Tasks;
+
+namespace ReactNative
+{
+ ///
+ /// This interface manages instances of .
+ /// It exposes a way to configure catalyst instances using
+ /// and keeps track of the lifecycle of that
+ /// instance. It also sets up a connection between the instance and the
+ /// developer support functionality of the framework.
+ ///
+ /// An instance of this manager is required to start the JavaScript
+ /// application in
+ /// ().
+ ///
+ /// The lifecycle of the instance of
+ /// should be bound to the application that owns the
+ /// that is used to render the react
+ /// application using this instance manager. It is required to pass
+ /// lifecycle events to the instance manager (i.e., ,
+ /// , and ).
+ ///
+ /// TODO:
+ /// 1.Implement background task functionality and ReactContextInitAsyncTask class hierarchy.
+ /// 2.Lifecycle managment functoinality. i.e. resume, pause, etc
+ /// 3.Implement Backbutton handler
+ /// 4.Implement js bundler load progress checks to ensure thread safety
+ /// 5.Implement the ViewGroupManager as well as the main ReactViewManager
+ /// 6.Create DevManager functionality to manage things like exceptions.
+ ///
+ public class ReactInstanceManager : IReactInstanceManager
+ {
+ private readonly List _attachedRootViews = new List();
+
+ private readonly string _jsBundleFile;
+ private readonly IReadOnlyList _packages;
+ private readonly UIImplementationProvider _uiImplementationProvider;
+ private readonly Action _nativeModuleCallExceptionHandler;
+
+ private LifecycleState _lifecycleState;
+ private bool _hasStartedCreatingInitialContext;
+ private Task _contextInitializationTask;
+ private Func _pendingJsExecutorFactory;
+ private JavaScriptBundleLoader _pendingJsBundleLoader;
+ private string _sourceUrl;
+ private ReactContext _currentReactContext;
+ private Action _defaultBackButtonHandler;
+
+ private ReactInstanceManager(
+ string jsBundleFile,
+ IReadOnlyList packages,
+ LifecycleState initialLifecycleState,
+ UIImplementationProvider uiImplementationProvider,
+ Action nativeModuleCallExceptionHandler)
+ {
+ if (packages == null)
+ throw new ArgumentNullException(nameof(packages));
+ if (uiImplementationProvider == null)
+ throw new ArgumentNullException(nameof(uiImplementationProvider));
+
+ _jsBundleFile = jsBundleFile;
+ _packages = packages;
+ _lifecycleState = initialLifecycleState;
+ _uiImplementationProvider = uiImplementationProvider;
+ _nativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler
+ ?? /* TODO: use dev support manager */ (_ => { });
+ }
+
+ ///
+ /// Event triggered when a react context has been initialized.
+ ///
+ public event EventHandler ReactContextInitialized;
+
+ ///
+ /// Signals whether has
+ /// been called. Will return false
after
+ /// until a new initial context has been created.
+ ///
+ public bool HasStartedCreatingInitialContext
+ {
+ get
+ {
+ return _hasStartedCreatingInitialContext;
+ }
+ }
+
+ ///
+ /// The URL where the last bundle was loaded from.
+ ///
+ public string SourceUrl
+ {
+ get
+ {
+ return _sourceUrl;
+ }
+ }
+
+ ///
+ /// Gets the current react context instance.
+ ///
+ public ReactContext CurrentReactContext
+ {
+ get
+ {
+ return _currentReactContext;
+ }
+ }
+
+ ///
+ /// Trigger the react context initialization asynchronously in a
+ /// background task. This enables applications to pre-load the
+ /// application JavaScript, and execute global core code before the
+ /// is available and measure. This should
+ /// only be called the first time the application is set up, which is
+ /// enforced to keep developers from accidentally creating their
+ /// applications multiple times.
+ ///
+ public void CreateReactContextInBackground()
+ {
+ if (_hasStartedCreatingInitialContext)
+ {
+ throw new InvalidOperationException(
+ "React context creation should only be called when creating the react " +
+ "application for the first time. When reloading JavaScript, e.g., from " +
+ "a new file, explicitly, use the re-create method.");
+ }
+
+ _hasStartedCreatingInitialContext = true;
+ RecreateReactContextInBackgroundInner();
+ }
+
+ ///
+ /// Recreate the react application and context. This should be called
+ /// if configuration has changed or the developer has requested the
+ /// applicatio
+ ///
+ public void RecreateReactContextInBackground()
+ {
+ if (!_hasStartedCreatingInitialContext)
+ {
+ throw new InvalidOperationException(
+ "React context re-creation should only be called after the initial " +
+ "create context background call.");
+ }
+
+ RecreateReactContextInBackgroundInner();
+ }
+
+ ///
+ /// Method that gives JavaScript the opportunity to consume the back
+ /// button event. If JavaScript does not consume the event, the
+ /// default back press action will be invoked at the end of the
+ /// roundtrip to JavaScript.
+ ///
+ public void OnBackPressed()
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+ var reactContext = _currentReactContext;
+ if (reactContext == null)
+ {
+ Tracer.Write(ReactConstants.Tag, "Instance detached from instance manager.");
+ InvokeDefaultOnBackPressed();
+ }
+ else
+ {
+ reactContext.GetNativeModule().EmitHardwareBackPressed();
+ }
+ }
+
+ ///
+ /// Called when the application is suspended.
+ ///
+ public void OnSuspend()
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+
+ _lifecycleState = LifecycleState.BeforeResume;
+ _defaultBackButtonHandler = null;
+
+ // TODO: dev support manager settings
+
+ var currentReactContext = _currentReactContext;
+ if (currentReactContext != null)
+ {
+ _currentReactContext.OnSuspend();
+ }
+ }
+
+ ///
+ /// Used when the application resumes to reset the back button handling
+ /// in JavaScript.
+ ///
+ ///
+ /// The action to take when back is pressed.
+ ///
+ public void OnResume(Action onBackPressed)
+ {
+ if (onBackPressed == null)
+ throw new ArgumentNullException(nameof(onBackPressed));
+
+ DispatcherHelpers.AssertOnDispatcher();
+
+ _lifecycleState = LifecycleState.Resumed;
+
+ _defaultBackButtonHandler = onBackPressed;
+
+ // TODO: dev support manager notifications
+
+ var currentReactContext = _currentReactContext;
+ if (currentReactContext != null)
+ {
+ currentReactContext.OnResume();
+ }
+ }
+
+ ///
+ /// Destroy the .
+ ///
+ public void OnDestroy()
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+
+ // TODO: dev support manager and memory pressure hooks
+
+ var currentReactContext = _currentReactContext;
+ if (currentReactContext != null)
+ {
+ currentReactContext.OnDestroy();
+ _currentReactContext = null;
+ _hasStartedCreatingInitialContext = false;
+ }
+ }
+
+ ///
+ /// Attach given to a catalyst instance
+ /// manager and start the JavaScript application using the JavaScript
+ /// module provided by the . If
+ /// the react context is currently being (re-)created, or if the react
+ /// context has not been created yet, the JavaScript application
+ /// associated with the provided root view will be started
+ /// asynchronously. This view will then be tracked by this manager and
+ /// in case of catalyst instance restart, it will be re-attached.
+ ///
+ /// The root view.
+ public void AttachMeasuredRootView(ReactRootView rootView)
+ {
+ if (rootView == null)
+ throw new ArgumentNullException(nameof(rootView));
+
+ DispatcherHelpers.AssertOnDispatcher();
+
+ _attachedRootViews.Add(rootView);
+
+ // If the react context is being created in the background, the
+ // JavaScript application will be started automatically when
+ // creation completes, as root view is part of the attached root
+ // view list.
+ var currentReactContext = _currentReactContext;
+ if (_contextInitializationTask == null && currentReactContext != null)
+ {
+ AttachMeasuredRootViewToInstance(rootView, currentReactContext.CatalystInstance);
+ }
+ }
+
+ ///
+ /// Detach given from the current catalyst
+ /// instance. This method is idempotent and can be called multiple
+ /// times on the same instance.
+ ///
+ /// The root view.
+ public void DetachRootView(ReactRootView rootView)
+ {
+ if (rootView == null)
+ throw new ArgumentNullException(nameof(rootView));
+
+ DispatcherHelpers.AssertOnDispatcher();
+
+ if (_attachedRootViews.Remove(rootView))
+ {
+ var currentReactContext = _currentReactContext;
+ if (currentReactContext != null && currentReactContext.HasActiveCatalystInstance)
+ {
+ DetachViewFromInstance(rootView, currentReactContext.CatalystInstance);
+ }
+ }
+ }
+
+ ///
+ /// Uses the configured instances to create
+ /// all s.
+ ///
+ ///
+ /// The application context.
+ ///
+ /// The list of view managers.
+ public IReadOnlyList CreateAllViewManagers(ReactContext reactContext)
+ {
+ if (reactContext == null)
+ throw new ArgumentNullException(nameof(reactContext));
+
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "createAllViewManagers"))
+ {
+ var allViewManagers = new List();
+ foreach (var package in _packages)
+ {
+ allViewManagers.AddRange(
+ package.CreateViewManagers(reactContext));
+ }
+
+ return allViewManagers;
+ }
+ }
+
+ private void RecreateReactContextInBackgroundInner()
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+ // TODO: handle developer support loading.
+ RecreateReactContextInBackgroundFromBundleFile();
+ }
+
+ private void RecreateReactContextInBackgroundFromBundleFile()
+ {
+ RecreateReactContextInBackground(
+ () => new ChakraJavaScriptExecutor(),
+ JavaScriptBundleLoader.CreateFileLoader(_jsBundleFile));
+ }
+
+ private void InvokeDefaultOnBackPressed()
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+
+ var defaultBackButtonHandler = _defaultBackButtonHandler;
+ if (defaultBackButtonHandler != null)
+ {
+ defaultBackButtonHandler();
+ }
+ }
+
+ private void RecreateReactContextInBackground(
+ Func jsExecutorFactory,
+ JavaScriptBundleLoader jsBundleLoader)
+ {
+ if (_contextInitializationTask == null)
+ {
+ _contextInitializationTask = InitializeReactContextAsync(jsExecutorFactory, jsBundleLoader);
+ }
+ else
+ {
+ _pendingJsExecutorFactory = jsExecutorFactory;
+ _pendingJsBundleLoader = jsBundleLoader;
+ }
+ }
+ private async Task InitializeReactContextAsync(
+ Func jsExecutorFactory,
+ JavaScriptBundleLoader jsBundleLoader)
+ {
+ var currentReactContext = _currentReactContext;
+ if (currentReactContext != null)
+ {
+ TearDownReactContext(currentReactContext);
+ _currentReactContext = null;
+ }
+
+ try
+ {
+ var reactContext = await CreateReactContextAsync(jsExecutorFactory, jsBundleLoader);
+ SetupReactContext(reactContext);
+ }
+ catch
+ {
+ // TODO: add exception handler through dev support manager.
+ }
+ finally
+ {
+ _contextInitializationTask = null;
+ }
+
+ if (_pendingJsExecutorFactory != null)
+ {
+ var pendingJsExecutorFactory = _pendingJsExecutorFactory;
+ var pendingJsBundleLoader = _pendingJsBundleLoader;
+
+ _pendingJsExecutorFactory = null;
+ _pendingJsBundleLoader = null;
+
+ RecreateReactContextInBackground(
+ pendingJsExecutorFactory,
+ pendingJsBundleLoader);
+ }
+ }
+
+ private void SetupReactContext(ReactContext reactContext)
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+ if (_currentReactContext != null)
+ {
+ throw new InvalidOperationException(
+ "React context has already been setup and has not been destroyed.");
+ }
+
+ _currentReactContext = reactContext;
+ var catalystInstance = reactContext.CatalystInstance;
+
+ catalystInstance.Initialize();
+
+ // TODO: set up dev support and memory pressure hooks
+
+ MoveReactContextToCurrentLifecycleState(reactContext);
+
+ foreach (var rootView in _attachedRootViews)
+ {
+ AttachMeasuredRootViewToInstance(rootView, catalystInstance);
+ }
+
+ OnReactContextInitialized(reactContext);
+ }
+
+ private void AttachMeasuredRootViewToInstance(
+ ReactRootView rootView,
+ ICatalystInstance catalystInstance)
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+
+ // Reset view content as it's going to be populated by the
+ // application content from JavaScript
+ rootView.Children.Clear();
+ // TODO: reset root view tag?
+
+ var uiManagerModule = catalystInstance.GetNativeModule();
+ var rootTag = uiManagerModule.AddMeasuredRootView(rootView);
+
+ var jsAppModuleName = rootView.JavaScriptModuleName;
+ var appParameters = new Dictionary
+ {
+ { "rootTag", rootTag },
+ { "initalProps", null /* TODO: add launch options to root view */ }
+ };
+
+ catalystInstance.GetJavaScriptModule().runApplication(jsAppModuleName, appParameters);
+ }
+
+ private void DetachViewFromInstance(ReactRootView rootView, ICatalystInstance catalystInstance)
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+ catalystInstance.GetJavaScriptModule().unmountApplicationComponentAtRootTag(rootView.GetTag());
+ }
+
+ private void TearDownReactContext(ReactContext reactContext)
+ {
+ DispatcherHelpers.AssertOnDispatcher();
+
+ if (_lifecycleState == LifecycleState.Resumed)
+ {
+ reactContext.OnSuspend();
+ }
+
+ foreach (var rootView in _attachedRootViews)
+ {
+ DetachViewFromInstance(rootView, reactContext.CatalystInstance);
+ }
+
+ reactContext.OnDestroy();
+ // TODO: add dev manager and memory pressure hooks
+ }
+
+ private async Task CreateReactContextAsync(
+ Func jsExecutorFactory,
+ JavaScriptBundleLoader jsBundleLoader)
+ {
+ Tracer.Write(ReactConstants.Tag, "Creating react context.");
+
+ _sourceUrl = jsBundleLoader.SourceUrl;
+
+ var nativeRegistryBuilder = new NativeModuleRegistry.Builder();
+ var jsModulesBuilder = new JavaScriptModulesConfig.Builder();
+
+ var reactContext = new ReactContext();
+
+ // TODO: set dev support manager on the context.
+
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "createAndProcessCoreModulesPackage"))
+ {
+ var coreModulesPackage =
+ new CoreModulesPackage(this, OnBackPressed, _uiImplementationProvider);
+
+ ProcessPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+ }
+
+ foreach (var reactPackage in _packages)
+ {
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "createAndProcessCustomReactPackage"))
+ {
+ ProcessPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+ }
+ }
+
+ var nativeModuleRegistry = default(NativeModuleRegistry);
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "buildNativeModuleRegistry"))
+ {
+ nativeModuleRegistry = nativeRegistryBuilder.Build();
+ }
+
+ var javaScriptModulesConfig = default(JavaScriptModulesConfig);
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "buildJSModuleConfig"))
+ {
+ javaScriptModulesConfig = jsModulesBuilder.Build();
+ }
+
+ var catalystInstanceBuilder = new CatalystInstance.Builder
+ {
+ QueueConfigurationSpec = CatalystQueueConfigurationSpec.Default,
+ JavaScriptExecutorFactory = jsExecutorFactory,
+ Registry = nativeModuleRegistry,
+ JavaScriptModulesConfig = javaScriptModulesConfig,
+ BundleLoader = jsBundleLoader,
+ NativeModuleCallExceptionHandler = _nativeModuleCallExceptionHandler,
+ };
+
+ var catalystInstance = default(CatalystInstance);
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "createCatalystInstance"))
+ {
+ catalystInstance = catalystInstanceBuilder.Build();
+ }
+
+ // TODO: add bridge idle debug listener
+
+ reactContext.InitializeWithInstance(catalystInstance);
+
+ using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "RunJavaScriptBundle"))
+ {
+ await catalystInstance.InitializeBridgeAsync();
+ }
+
+ return reactContext;
+ }
+
+ private void ProcessPackage(
+ IReactPackage reactPackage,
+ ReactContext reactContext,
+ NativeModuleRegistry.Builder nativeRegistryBuilder,
+ JavaScriptModulesConfig.Builder jsModulesBuilder)
+ {
+ foreach (var nativeModule in reactPackage.CreateNativeModules(reactContext))
+ {
+ nativeRegistryBuilder.Add(nativeModule);
+ }
+
+ foreach (var type in reactPackage.CreateJavaScriptModulesConfig())
+ {
+ if (JavaScriptModulesConfig.Builder.ValidJavaScriptModuleType(type))
+ {
+ jsModulesBuilder.Add(type);
+ }
+ }
+ }
+
+ private void MoveReactContextToCurrentLifecycleState(ReactContext reactContext)
+ {
+ if (_lifecycleState == LifecycleState.Resumed)
+ {
+ reactContext.OnResume();
+ }
+ }
+
+ private void OnReactContextInitialized(ReactContext reactContext)
+ {
+ var reactContextInitialized = ReactContextInitialized;
+ if (reactContextInitialized != null)
+ {
+ reactContextInitialized(this, new ReactContextInitializedEventArgs(reactContext));
+ }
+ }
+
+ ///
+ /// A Builder responsible for creating a React Instance Manager.
+ ///
+ public sealed class Builder
+ {
+ private readonly List _packages = new List();
+
+ private string _jsBundleFile;
+ private LifecycleState? _initialLifecycleState;
+ private UIImplementationProvider _uiImplementationProvider;
+ private Action _nativeModuleCallExceptionHandler;
+
+ ///
+ /// A provider of .
+ ///
+ public UIImplementationProvider UIImplementationProvider
+ {
+ set
+ {
+ _uiImplementationProvider = value;
+ }
+ }
+
+ ///
+ /// Path to the JavaScript bundle file to be loaded from the file
+ /// system.
+ ///
+ public string JavaScriptBundleFile
+ {
+ set
+ {
+ _jsBundleFile = value;
+ }
+ }
+
+ ///
+ /// The mutable list of react packages.
+ ///
+ public IList Packages
+ {
+ get
+ {
+ return _packages;
+ }
+ }
+
+ ///
+ /// The initial lifecycle state of the host.
+ ///
+ public LifecycleState InitialLifecycleState
+ {
+ set
+ {
+ _initialLifecycleState = value;
+ }
+ }
+
+ ///
+ /// The exception handler for all native module calls.
+ ///
+ public Action NativeModuleCallExceptionHandler
+ {
+ set
+ {
+ _nativeModuleCallExceptionHandler = value;
+ }
+ }
+
+ ///
+ /// Instantiates a new .
+ ///
+ /// A react instance manager.
+ public ReactInstanceManager Build()
+ {
+ AssertNotNull(_jsBundleFile, nameof(JavaScriptBundleFile));
+ AssertNotNull(_initialLifecycleState, nameof(InitialLifecycleState));
+
+ if (_uiImplementationProvider == null)
+ {
+ _uiImplementationProvider = new UIImplementationProvider();
+ }
+
+ return new ReactInstanceManager(
+ _jsBundleFile,
+ _packages,
+ _initialLifecycleState.Value,
+ _uiImplementationProvider,
+ _nativeModuleCallExceptionHandler);
+ }
+
+ private void AssertNotNull(object value, string name)
+ {
+ if (value == null)
+ throw new InvalidOperationException(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "{0} has not been set.",
+ name));
+ }
+ }
+ }
+}
diff --git a/ReactWindows/ReactNative/ReactInstanceManagerImpl.cs b/ReactWindows/ReactNative/ReactInstanceManagerImpl.cs
deleted file mode 100644
index e648cf72516..00000000000
--- a/ReactWindows/ReactNative/ReactInstanceManagerImpl.cs
+++ /dev/null
@@ -1,398 +0,0 @@
-using ReactNative.Bridge;
-using ReactNative.Bridge.Queue;
-using ReactNative.Common;
-using ReactNative.Hosting.Bridge;
-using ReactNative.Modules.Core;
-using ReactNative.Tracing;
-using ReactNative.UIManager;
-using ReactNative.Views;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Threading.Tasks;
-using Windows.UI.Xaml;
-
-namespace ReactNative
-{
- ///
- /// This class is managing instances of . It expose a way to configure
- /// catalyst instance using and keeps track of the lifecycle of that
- /// instance. It also sets up connection between the instance and developers support functionality
- /// of the framework.
- ///
- /// An instance of this manager is required to start JS application in (see
- /// for more info).
- ///
- /// TODO:
- /// 1.Implement background task functionality and ReactContextInitAsyncTask class hierarchy.
- /// 2.Lifecycle managment functoinality. i.e. resume, pause, etc
- /// 3.Implement Backbutton handler
- /// 4.Implement js bundler load progress checks to ensure thread safety
- /// 5.Implement the ViewGroupManager as well as the main ReactViewManager
- /// 6.Create DevManager functionality to manage things like exceptions.
- ///
- public class ReactInstanceManagerImpl : IReactInstanceManager
- {
- private readonly List _attachedRootViews = new List();
- private LifecycleState _lifecycleState;
- private readonly string _jsBundleFile;
- private readonly List _packages;
- private ReactContext _reactContext;
- private readonly string _jsMainModuleName;
- private readonly UIImplementationProvider _uiImplementationProvider;
- private readonly IDefaultHardwareBackButtonHandler _defaultHardwareBackButtonHandler;
-
- public ReactInstanceManagerImpl(
- string jsMainModuleName,
- List packages,
- LifecycleState initialLifecycleState,
- UIImplementationProvider uiImplementationProvider,
- string jsBundleFile)
- {
- _jsBundleFile = jsBundleFile;
- _jsMainModuleName = jsMainModuleName;
- _packages = packages;
- _reactContext = new ReactApplicationContext();
- _lifecycleState = initialLifecycleState;
- _uiImplementationProvider = uiImplementationProvider;
- _defaultHardwareBackButtonHandler = new DefaultHardwareBackButtonHandlerImpl(this);
- }
-
- ///
- /// Uses configured instances to create all view managers.
- ///
- /// react application instance
- ///
- public IReadOnlyList CreateAllViewManagers(ReactApplicationContext catalystApplicationContext)
- {
- var allViewManagers = new List();
- _packages.ForEach(reactPackage =>
- allViewManagers.AddRange(
- reactPackage.CreateViewManagers(catalystApplicationContext)));
- return allViewManagers;
- }
-
- ///
- /// Loads the based on the user configured bundle.
- ///
- public async Task RecreateReactContextInBackgroundFromBundleFileAsync()
- {
- var jsExecutor = new ChakraJavaScriptExecutor();
- var jsBundler = JavaScriptBundleLoader.CreateFileLoader(_jsBundleFile);
-
- try
- {
- _reactContext = await CreateReactContextAsync(jsExecutor, jsBundler);
- }
- catch (Exception ex)
- {
- throw ex;
- }
-
- return _reactContext;
- }
-
- ///
- /// Creates the react context instance which is based off the .
- ///
- /// The Javascript Executor instance
- /// The Javascript bundle loader responsible for loading the assembly
- /// An async task containing the created react context
- private async Task CreateReactContextAsync(IJavaScriptExecutor jsExecutor, JavaScriptBundleLoader jsBundleLoader)
- {
- var reactContext = new ReactApplicationContext();
- var nativeRegistryBuilder = new NativeModuleRegistry.Builder();
- var jsModulesBuilder = new JavaScriptModulesConfig.Builder();
-
- using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "createAndProcessCoreModulesPackage"))
- {
- var coreModulesPackage = new CoreModulesPackage(
- this,
- _defaultHardwareBackButtonHandler,
- _uiImplementationProvider);
-
- ProcessPackage(
- coreModulesPackage,
- reactContext,
- nativeRegistryBuilder,
- jsModulesBuilder);
- }
-
- foreach (var reactPackage in _packages)
- {
- using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "createAndProcessCustomReactPackage"))
- {
- ProcessPackage(
- reactPackage,
- reactContext,
- nativeRegistryBuilder,
- jsModulesBuilder);
- }
- }
-
- var nativeModuleRegistry = default(NativeModuleRegistry);
- using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "buildNativeModuleRegistry"))
- {
- nativeModuleRegistry = nativeRegistryBuilder.Build();
- }
-
- var javaScriptModulesConfig = default(JavaScriptModulesConfig);
- using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "buildJSModuleConfig"))
- {
- javaScriptModulesConfig = jsModulesBuilder.Build();
- }
-
- var exceptionHandler = new Action(ex =>
- {
- Tracer.Write(ReactConstants.Tag, String.Format("Exception Occured {0}", ex.Message));
- });
-
- var javascriptRuntime = new CatalystInstance.Builder
- {
- QueueConfigurationSpec = CatalystQueueConfigurationSpec.Default,
- JavaScriptExecutor = jsExecutor,
- Registry = nativeModuleRegistry,
- JavaScriptModulesConfig = javaScriptModulesConfig,
- BundleLoader = jsBundleLoader,
- NativeModuleCallExceptionHandler = exceptionHandler
- }.Build();
-
- reactContext.InitializeWithInstance(javascriptRuntime);
-
- await javascriptRuntime.InitializeBridgeAsync();
-
- return reactContext;
- }
-
- private void ProcessPackage(
- IReactPackage reactPackage,
- ReactApplicationContext reactContext,
- NativeModuleRegistry.Builder nativeRegistryBuilder,
- JavaScriptModulesConfig.Builder jsModulesBuilder)
- {
- foreach (var nativeModule in reactPackage.CreateNativeModules(reactContext))
- {
- nativeRegistryBuilder.Add(nativeModule);
- }
-
- foreach (var type in reactPackage.CreateJavaScriptModulesConfig())
- {
- if (JavaScriptModulesConfig.Builder.ValidJavaScriptModuleType(type))
- {
- jsModulesBuilder.Add(type);
- }
- }
- }
-
- ///
- /// Attaches the to the list of tracked root views.
- ///
- /// The root view for the ReactJS app
- public void AttachMeasuredRootView(ReactRootView rootView)
- {
- _attachedRootViews.Add(rootView);
-
- if (_reactContext != null)
- {
- AttachMeasuredRootViewToInstance(rootView, _reactContext.CatalystInstance);
- }
- }
-
- ///
- /// Detach given from current catalyst instance.
- ///
- /// The root view for the ReactJS app
- public void DetachRootView(ReactRootView rootView)
- {
- if (_attachedRootViews.RemoveAll(view => view.TagId == rootView.TagId) > -1)
- {
- if (_reactContext != null)
- {
- DetachViewFromInstance(rootView, _reactContext.CatalystInstance);
- }
- }
- }
-
- private void DetachViewFromInstance(ReactRootView rootView, ICatalystInstance catalystInstance)
- {
- try
- {
- catalystInstance.GetJavaScriptModule()?.unmountApplicationComponentAtRootTag(rootView.TagId);
- }
- catch (InvalidOperationException ex)
- {
- throw new InvalidOperationException("Unable to load AppRegistry JS module. Error message: " + ex.Message, ex);
- }
- }
-
- private void AttachMeasuredRootViewToInstance(ReactRootView rootView, ICatalystInstance catalystInstance)
- {
- DispatcherHelpers.AssertOnDispatcher();
-
- // Reset view content as it's going to be populated by the
- // application content from JavaScript
- var uiManagerModule = catalystInstance.GetNativeModule();
-
- var rootTag = uiManagerModule.AddMeasuredRootView(rootView);
- var initialProps = new Dictionary();
- initialProps.Add("rootTag", rootTag);
-
- try
- {
- catalystInstance.GetJavaScriptModule()?.runApplication(rootView.JSModuleName, initialProps);
- }
- catch (InvalidOperationException ex)
- {
- throw new InvalidOperationException("Unable to load AppRegistry JS module. Error message: " + ex.Message, ex);
- }
- }
-
- private void InvokeDefaultOnBackPressed()
- {
- DispatcherHelpers.AssertOnDispatcher();
- // TODO: implement
- }
-
- class DefaultHardwareBackButtonHandlerImpl : IDefaultHardwareBackButtonHandler
- {
- private readonly ReactInstanceManagerImpl _parent;
-
- public DefaultHardwareBackButtonHandlerImpl(ReactInstanceManagerImpl parent)
- {
- _parent = parent;
- }
-
- public void InvokeDefaultOnBackPressed()
- {
- _parent.InvokeDefaultOnBackPressed();
- }
- }
-
- ///
- /// A Builder responsible for creating a React Instance Manager.
- ///
- public sealed class Builder
- {
- private readonly List _reactPackages = new List();
- private LifecycleState _LifecycleState;
- private UIImplementationProvider _UIImplementationProvider;
- private string _jsBundleFile;
- private string _jsMainModuleName;
-
- ///
- /// Sets a provider of .
- ///
- public UIImplementationProvider UIImplementationProvider
- {
- set
- {
- _UIImplementationProvider = value;
- }
- }
-
- ///
- /// Path to the JS bundle file to be loaded from the file system.
- ///
- public string JSBundleFile
- {
- set
- {
- _jsBundleFile = value;
- }
- }
-
- ///
- /// Path to your app's main module on the packager server. This is used when
- /// reloading JS during development. All paths are relative to the root folder
- /// the packager is serving files from.
- ///
- public string JSMainModuleName
- {
- set
- {
- _jsMainModuleName = value;
- }
- }
-
- ///
- /// Adds a specified to the package list.
- ///
- /// Client requested package to load.
- ///
- public Builder AddPackage(IReactPackage reactPackage)
- {
- _reactPackages.Add(reactPackage);
- return this;
- }
-
- ///
- /// Concatenates a list of packages to the builder list.
- ///
- /// Client requested package list to include
- ///
- public Builder AddPackages(List packages)
- {
- _reactPackages.AddRange(packages);
- return this;
- }
-
- ///
- /// Instantiates a new {@link ReactInstanceManagerImpl}.
- ///
- ///
- public LifecycleState InitialLifecycleState
- {
- set
- {
- _LifecycleState = value;
- }
- }
-
- ///
- /// Instantiates a new .
- /// Before calling , the following must be called: setApplication then setJSMainModuleName
- ///
- /// A IReactInstanceManager instance
- public IReactInstanceManager Build()
- {
- AssertNotNull(_LifecycleState, nameof(LifecycleState));
- AssertNotNull(_jsMainModuleName, "string");
- AssertNotNull(_jsBundleFile, "string");
-
- if (_UIImplementationProvider == null)
- {
- // create default UIImplementationProvider if the provided one is null.
- _UIImplementationProvider = new UIImplementationProvider();
- }
-
- return new ReactInstanceManagerImpl(_jsMainModuleName, _reactPackages,
- _LifecycleState, _UIImplementationProvider, _jsBundleFile);
- }
-
- private void AssertNotNull(object value, string name)
- {
- if (value == null)
- throw new InvalidOperationException(
- string.Format(
- CultureInfo.InvariantCulture,
- "{0} has not been set.",
- name));
- }
- }
-
- ///
- /// Dispose the instance of , which entails disposing
- /// and detaching all from the instance.
- ///
- public void Dispose()
- {
- _reactContext.CatalystInstance.Dispose();
-
- foreach (var rootView in _attachedRootViews)
- {
- this.DetachRootView(rootView);
- }
- }
- }
-}
diff --git a/ReactWindows/ReactNative/ReactNative.csproj b/ReactWindows/ReactNative/ReactNative.csproj
index 5adcade4909..8c81f091ad9 100644
--- a/ReactWindows/ReactNative/ReactNative.csproj
+++ b/ReactWindows/ReactNative/ReactNative.csproj
@@ -152,8 +152,10 @@
-
+
+
+
@@ -165,7 +167,7 @@
-
+
@@ -190,11 +192,9 @@
-
-
diff --git a/ReactWindows/ReactNative/ReactPage.cs b/ReactWindows/ReactNative/ReactPage.cs
new file mode 100644
index 00000000000..23c2234e58a
--- /dev/null
+++ b/ReactWindows/ReactNative/ReactPage.cs
@@ -0,0 +1,110 @@
+using ReactNative.Modules.Core;
+using System;
+using System.Collections.Generic;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace ReactNative
+{
+ ///
+ /// Base page for React Native applications.
+ ///
+ public class ReactPage : Page
+ {
+ private readonly IReactInstanceManager _reactInstanceManager;
+ private readonly string _mainComponentName;
+ private readonly Action _onBackPressed;
+
+ ///
+ /// Instantiates the .
+ ///
+ /// The JavaScript bundle file.
+ /// The main component name.
+ /// The list of react packages.
+ public ReactPage(
+ string jsBundleFile,
+ string mainComponentName,
+ IReadOnlyList packages,
+ Action onBackPressed)
+ {
+ _mainComponentName = mainComponentName;
+ _onBackPressed = onBackPressed;
+ _reactInstanceManager = CreateReactInstanceManager(jsBundleFile, packages);
+
+ RootView = CreateRootView();
+ RootView.HorizontalAlignment = HorizontalAlignment.Stretch;
+ RootView.VerticalAlignment = VerticalAlignment.Stretch;
+
+ Content = RootView;
+ }
+
+ ///
+ /// The root view managed by the page.
+ ///
+ public ReactRootView RootView
+ {
+ get;
+ }
+
+ ///
+ /// Called when the application is first initialized.
+ ///
+ public void OnCreate()
+ {
+ RootView.StartReactApplication(_reactInstanceManager, _mainComponentName);
+ }
+
+ ///
+ /// Called before the application is suspended.
+ ///
+ public void OnSuspend()
+ {
+ _reactInstanceManager.OnSuspend();
+ }
+
+ ///
+ /// Called when the application is resumed.
+ ///
+ public void OnResume()
+ {
+ _reactInstanceManager.OnResume(_onBackPressed);
+ }
+
+ ///
+ /// Called before the application shuts down.
+ ///
+ public void OnDestroy()
+ {
+ _reactInstanceManager.OnDestroy();
+ }
+
+ ///
+ /// Creates the React root view.
+ ///
+ /// The root view.
+ ///
+ /// Subclasses may override this method if it needs to use a custom
+ /// root view.
+ ///
+ protected virtual ReactRootView CreateRootView()
+ {
+ return new ReactRootView();
+ }
+
+ private IReactInstanceManager CreateReactInstanceManager(string jsBundleFile, IReadOnlyList packages)
+ {
+ var builder = new ReactInstanceManager.Builder
+ {
+ InitialLifecycleState = LifecycleState.Resumed,
+ JavaScriptBundleFile = jsBundleFile,
+ };
+
+ foreach (var package in packages)
+ {
+ builder.Packages.Add(package);
+ }
+
+ return builder.Build();
+ }
+ }
+}
diff --git a/ReactWindows/ReactNative/ReactRootView.cs b/ReactWindows/ReactNative/ReactRootView.cs
index 579b1a1551b..9c4f9b66412 100644
--- a/ReactWindows/ReactNative/ReactRootView.cs
+++ b/ReactWindows/ReactNative/ReactRootView.cs
@@ -1,113 +1,116 @@
-using ReactNative.Modules.Core;
-using ReactNative.Shell;
+using ReactNative.Bridge;
using ReactNative.UIManager;
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
using Windows.UI.Xaml;
+using Windows.Foundation;
namespace ReactNative
{
+ ///
+ /// Default root view for applicaitons. Provides the ability to listen for
+ /// size changes so that the UI manager can re-layout its elements.
+ ///
+ /// It is also responsible for handling touch events passed to any of it's
+ /// child views and sending those events to JavaScript via the
+ /// module.
+ ///
public class ReactRootView : SizeMonitoringPanel, IRootView
{
private IReactInstanceManager _reactInstanceManager;
private string _jsModuleName;
- private int _rootTageNode;
- private bool _isAttachedToWindow;
- public void OnChildStartedNativeGesture(RoutedEventArgs ev)
- {
- throw new NotImplementedException("Native gesture event handling is not yet supported");
- }
+ private bool _wasMeasured;
+ private bool _attachScheduled;
///
- /// Initializes and starts a instance.
+ /// Gets the JavaScript module name.
///
- /// The Javascript Bundle location
- /// The core Javascript module name
- public void LiftAsync(string bundleAssetName, string jsModuleName)
+ internal string JavaScriptModuleName
{
- var defaultPackageList = new List()
+ get
{
- new MainReactPackage()
- };
-
- this.LiftAsync(bundleAssetName, jsModuleName, defaultPackageList);
+ return _jsModuleName;
+ }
}
///
- /// Initializes and starts a i nstance.
+ /// Schedule rendering of the react component rendered by the
+ /// JavaScript application from the given JavaScript module
+ /// using the provided
+ /// to attach to the JavaScript
+ /// context of that manager.
///
- /// The Javascript Bundle location
- /// The core Javascript module name
- /// The list of react packges to initialize
- public void LiftAsync(string bundleAssetName, string jsModuleName, List packages)
+ ///
+ /// The react instance manager.
+ ///
+ ///
+ /// The module name.
+ ///
+ public void StartReactApplication(IReactInstanceManager reactInstanceManager, string moduleName)
{
- var builder = new ReactInstanceManagerImpl.Builder()
+ DispatcherHelpers.AssertOnDispatcher();
+
+ if (_reactInstanceManager != null)
{
- InitialLifecycleState = LifecycleState.RESUMED,
- JSMainModuleName = jsModuleName,
- JSBundleFile = bundleAssetName
+ throw new InvalidOperationException("This root view has already been attached to an instance manager.");
}
- .AddPackages(packages)
- .Build();
- this.StartReactApplication(builder, jsModuleName);
- }
+ _reactInstanceManager = reactInstanceManager;
+ _jsModuleName = moduleName;
- ///
- /// Exposes the Javascript module name of the root view
- ///
- public string JSModuleName
- {
- get
+ if (!_reactInstanceManager.HasStartedCreatingInitialContext)
{
- return _jsModuleName;
+ _reactInstanceManager.CreateReactContextInBackground();
}
- }
- ///
- /// Exposes the react tag id of the view
- ///
- public int TagId
- {
- get { return _rootTageNode; }
+ // We need to wait for the initial `Measure` call, if this view has
+ // not yet been measured, we set the `_attachScheduled` flag, which
+ // will enable deferred attachment of the root node.
+ if (_wasMeasured)
+ {
+ _reactInstanceManager.AttachMeasuredRootView(this);
+ }
+ else
+ {
+ _attachScheduled = true;
+ }
}
///
- /// Sets the react tag id to the view
+ /// Called when a child starts a native gesture.
///
- ///
- public void BindTagToView(int tagId)
+ /// The event.
+ public void OnChildStartedNativeGesture(RoutedEventArgs ev)
{
- _rootTageNode = tagId;
+ throw new NotImplementedException();
}
///
- /// Schedule rendering of the react component rendered by the JS application from the given JS
- /// module using provided
+ /// Hooks into the measurement event to potentially attach the react
+ /// root view.
///
- /// The React Instance Manager
- /// module to load
- public async void StartReactApplication(IReactInstanceManager reactInstanceManager, string moduleName)
+ /// The available size.
+ /// The desired size.
+ protected override Size MeasureOverride(Size availableSize)
{
- _reactInstanceManager = reactInstanceManager;
- _jsModuleName = moduleName;
+ DispatcherHelpers.AssertOnDispatcher();
- await _reactInstanceManager.RecreateReactContextInBackgroundFromBundleFileAsync();
+ var result = base.MeasureOverride(availableSize);
- // We need to wait for the initial onMeasure, if this view has not yet been measured, we set
- // mAttachScheduled flag, which will make this view startReactApplication itself to instance
- // manager once onMeasure is called.
- if (!_isAttachedToWindow)
+ _wasMeasured = true;
+
+ var reactInstanceManager = _reactInstanceManager;
+ if (_attachScheduled && reactInstanceManager != null)
{
- _reactInstanceManager.AttachMeasuredRootView(this);
- _isAttachedToWindow = true;
+ _attachScheduled = false;
+ reactInstanceManager.AttachMeasuredRootView(this);
}
- }
- private void OnDetachedFromWindow(object sender, RoutedEventArgs e)
- {
- _reactInstanceManager.DetachRootView(this);
+ return result;
}
}
}
diff --git a/ReactWindows/ReactNative/Shell/MainReactPackage.cs b/ReactWindows/ReactNative/Shell/MainReactPackage.cs
index 7e1a7fa9edc..fec3f38b489 100644
--- a/ReactWindows/ReactNative/Shell/MainReactPackage.cs
+++ b/ReactWindows/ReactNative/Shell/MainReactPackage.cs
@@ -17,7 +17,7 @@ namespace ReactNative.Shell
///
public class MainReactPackage : IReactPackage
{
- public IReadOnlyList CreateNativeModules(ReactApplicationContext reactContext)
+ public IReadOnlyList CreateNativeModules(ReactContext reactContext)
{
return new List
{
@@ -31,7 +31,7 @@ public IReadOnlyList CreateJavaScriptModulesConfig()
}
public IReadOnlyList CreateViewManagers(
- ReactApplicationContext reactContext)
+ ReactContext reactContext)
{
return new List
{
diff --git a/ReactWindows/ReactNative/UIManager/Events/EventDispatcher.cs b/ReactWindows/ReactNative/UIManager/Events/EventDispatcher.cs
index 5e3982a60ca..2732e639e29 100644
--- a/ReactWindows/ReactNative/UIManager/Events/EventDispatcher.cs
+++ b/ReactWindows/ReactNative/UIManager/Events/EventDispatcher.cs
@@ -79,7 +79,7 @@ public class EventDispatcher : ILifecycleEventListener
private readonly IDictionary _eventCookieToLastEventIndex = new Dictionary();
private readonly IDictionary _eventNameToEventId = new Dictionary();
- private readonly ReactApplicationContext _reactContext;
+ private readonly ReactContext _reactContext;
private RCTEventEmitter _rctEventEmitter;
private EventDispatcherCallback _currentFrameCallback;
@@ -88,7 +88,7 @@ public class EventDispatcher : ILifecycleEventListener
/// Instantiates the .
///
/// The context.
- public EventDispatcher(ReactApplicationContext reactContext)
+ public EventDispatcher(ReactContext reactContext)
{
if (reactContext == null)
throw new ArgumentNullException(nameof(reactContext));
@@ -146,7 +146,7 @@ public void OnResume()
///
/// Called when the host is shutting down.
///
- public void OnShutdown()
+ public void OnDestroy()
{
ClearCallback();
}
diff --git a/ReactWindows/ReactNative/UIManager/IRootView.cs b/ReactWindows/ReactNative/UIManager/IRootView.cs
index 4ac484bc098..b5db2b27f84 100644
--- a/ReactWindows/ReactNative/UIManager/IRootView.cs
+++ b/ReactWindows/ReactNative/UIManager/IRootView.cs
@@ -3,14 +3,14 @@
namespace ReactNative.UIManager
{
///
- /// Interface for the root native view of a React native application.
+ /// Interface for the root native view of a react native application.
///
public interface IRootView
{
///
- /// Called when a child starts a native gesture (e.g. a scroll in a ScrollView).
+ /// Called when a child starts a native gesture.
///
- ///
- void OnChildStartedNativeGesture(RoutedEventArgs ev);
+ /// The event.
+ void OnChildStartedNativeGesture(RoutedEventArgs e);
}
}
diff --git a/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs b/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs
index 8f956549f6f..0faf2dcb3d5 100644
--- a/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs
+++ b/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs
@@ -304,6 +304,12 @@ public void RemoveRootView(int rootViewTag)
}
var rootView = _tagsToViews[rootViewTag];
+ var sizeMonitoringPanel = rootView as SizeMonitoringPanel;
+ if (sizeMonitoringPanel != null)
+ {
+ sizeMonitoringPanel.RemoveSizeChanged();
+ }
+
DropView(rootView);
_rootTags.Remove(rootViewTag);
}
diff --git a/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs b/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs
index 417938556ae..d6039a32e33 100644
--- a/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs
+++ b/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs
@@ -6,18 +6,27 @@ namespace ReactNative.UIManager
///
/// allows registering for size change events. The main purpose for this class is to hide complexity of ReactRootView
///
- public partial class SizeMonitoringPanel : Canvas
+ public class SizeMonitoringPanel : Canvas
{
- private ISizeChangedListener _onSizeChangedListener;
+ private SizeChangedEventHandler _sizeChangedEventHandler;
///
- /// Sets and registers the size change listener for the XAML panel control
+ /// Sets and registers the event handler responsible for monitoring
+ /// size change events.
///
- /// The listener
- public void SetOnSizeChangedListener(ISizeChangedListener sizeChangedListener)
+ /// The event handler.
+ public void SetOnSizeChangedListener(SizeChangedEventHandler sizeChangedEventHandler)
{
- _onSizeChangedListener = sizeChangedListener;
- this.SizeChanged += _onSizeChangedListener.OnSizeChanged;
+ _sizeChangedEventHandler = sizeChangedEventHandler;
+ SizeChanged += _sizeChangedEventHandler;
+ }
+
+ ///
+ /// Unsets the size changed event handler.
+ ///
+ public void RemoveSizeChanged()
+ {
+ SizeChanged -= _sizeChangedEventHandler;
}
}
}
diff --git a/ReactWindows/ReactNative/UIManager/ThemedReactContext.cs b/ReactWindows/ReactNative/UIManager/ThemedReactContext.cs
index 9c9b49334e6..f9b05b85408 100644
--- a/ReactWindows/ReactNative/UIManager/ThemedReactContext.cs
+++ b/ReactWindows/ReactNative/UIManager/ThemedReactContext.cs
@@ -5,21 +5,21 @@ namespace ReactNative.UIManager
public class ThemedReactContext : ReactContext
{
- private readonly ReactApplicationContext mReactApplicationContext;
+ private readonly ReactContext mReactContext;
- public ThemedReactContext(ReactApplicationContext reactApplicationContext) {
+ public ThemedReactContext(ReactContext reactApplicationContext) {
InitializeWithInstance(reactApplicationContext.CatalystInstance);
- mReactApplicationContext = reactApplicationContext;
+ mReactContext = reactApplicationContext;
}
public void addLifecycleEventListener(ILifecycleEventListener listener)
{
- mReactApplicationContext.AddLifecycleEventListener(listener);
+ mReactContext.AddLifecycleEventListener(listener);
}
public void removeLifecycleEventListener(ILifecycleEventListener listener)
{
- mReactApplicationContext.RemoveLifecycleEventListener(listener);
+ mReactContext.RemoveLifecycleEventListener(listener);
}
}
diff --git a/ReactWindows/ReactNative/UIManager/UIImplementation.cs b/ReactWindows/ReactNative/UIManager/UIImplementation.cs
index 8509811e0dc..3cd353dff46 100644
--- a/ReactWindows/ReactNative/UIManager/UIImplementation.cs
+++ b/ReactWindows/ReactNative/UIManager/UIImplementation.cs
@@ -34,12 +34,12 @@ public class UIImplementation
///
/// The react context.
/// The view managers.
- public UIImplementation(ReactApplicationContext reactContext, IReadOnlyList viewManagers)
+ public UIImplementation(ReactContext reactContext, IReadOnlyList viewManagers)
: this(reactContext, new ViewManagerRegistry(viewManagers))
{
}
- private UIImplementation(ReactApplicationContext reactContext, ViewManagerRegistry viewManagers)
+ private UIImplementation(ReactContext reactContext, ViewManagerRegistry viewManagers)
: this(
viewManagers,
new UIViewOperationQueue(reactContext, new NativeViewHierarchyManager(viewManagers)))
diff --git a/ReactWindows/ReactNative/UIManager/UIImplementationProvider.cs b/ReactWindows/ReactNative/UIManager/UIImplementationProvider.cs
index d4db622f1e5..524384d1855 100644
--- a/ReactWindows/ReactNative/UIManager/UIImplementationProvider.cs
+++ b/ReactWindows/ReactNative/UIManager/UIImplementationProvider.cs
@@ -11,7 +11,7 @@ namespace ReactNative.UIManager
public class UIImplementationProvider
{
public UIImplementation CreateUIImplementation(
- ReactApplicationContext reactContext,
+ ReactContext reactContext,
IReadOnlyList viewManagers)
{
return new UIImplementation(reactContext, viewManagers);
diff --git a/ReactWindows/ReactNative/UIManager/UIManagerModule.cs b/ReactWindows/ReactNative/UIManager/UIManagerModule.cs
index 6f08173e5bc..6e12ffedf67 100644
--- a/ReactWindows/ReactNative/UIManager/UIManagerModule.cs
+++ b/ReactWindows/ReactNative/UIManager/UIManagerModule.cs
@@ -35,7 +35,7 @@ public partial class UIManagerModule : ReactContextNativeModuleBase, ILifecycleE
/// The view managers.
/// The UI implementation.
public UIManagerModule(
- ReactApplicationContext reactContext,
+ ReactContext reactContext,
IReadOnlyList viewManagers,
UIImplementation uiImplementation)
: base(reactContext)
@@ -102,7 +102,8 @@ public int AddMeasuredRootView(SizeMonitoringPanel rootView)
var context = new ThemedReactContext(Context);
_uiImplementation.RegisterRootView(rootView, tag, width, height, context);
- rootView.SetOnSizeChangedListener(new RootViewSizeChangedListener());
+ // TODO: ensure this gets unset
+ rootView.SetOnSizeChangedListener(OnSizeChanged);
return tag;
}
@@ -369,7 +370,7 @@ public void OnResume()
///
/// Called when the host is shutting down.
///
- public void OnShutdown()
+ public void OnDestroy()
{
_uiImplementation.OnShutdown();
}
@@ -409,16 +410,16 @@ public override void OnCatalystInstanceDispose()
#endregion
- sealed class RootViewSizeChangedListener : ISizeChangedListener
+ #region SizeChangedEventHandler
+
+ private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
- public void OnSizeChanged(object sender, SizeChangedEventArgs e)
- {
- //TODO: Need to adjust the styling of the panel based on the new
- //width and height(e.NewSize). The adjustment needs to run on the
- //Native Modules thread off the react context(this.Context.RunOnNativeModulesThread)
- throw new NotImplementedException("Size change behavior for root view still needs to be implemented");
- }
+ //TODO: Need to adjust the styling of the panel based on the new
+ //width and height(e.NewSize). The adjustment needs to run on the
+ //Native Modules thread off the react context(this.Context.RunOnNativeModulesThread)
+ throw new NotImplementedException("Size change behavior for root view still needs to be implemented");
}
+ #endregion
}
}
diff --git a/ReactWindows/ReactNative/UIManager/UIViewOperationQueue.cs b/ReactWindows/ReactNative/UIManager/UIViewOperationQueue.cs
index 77ec05e3fb4..b958b07c90a 100644
--- a/ReactWindows/ReactNative/UIManager/UIViewOperationQueue.cs
+++ b/ReactWindows/ReactNative/UIManager/UIViewOperationQueue.cs
@@ -23,7 +23,7 @@ public class UIViewOperationQueue
private IList _operations = new List();
private readonly NativeViewHierarchyManager _nativeViewHierarchyManager;
- private readonly ReactApplicationContext _reactContext;
+ private readonly ReactContext _reactContext;
///
/// Instantiates the .
@@ -32,7 +32,7 @@ public class UIViewOperationQueue
///
/// The native view hierarchy manager.
///
- public UIViewOperationQueue(ReactApplicationContext reactContext, NativeViewHierarchyManager nativeViewHierarchyManager)
+ public UIViewOperationQueue(ReactContext reactContext, NativeViewHierarchyManager nativeViewHierarchyManager)
{
_nativeViewHierarchyManager = nativeViewHierarchyManager;
_reactContext = reactContext;