diff --git a/ReactWindows/Playground.Net46/App.config b/ReactWindows/Playground.Net46/App.config
new file mode 100644
index 00000000000..2d2a12d81be
--- /dev/null
+++ b/ReactWindows/Playground.Net46/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/ReactWindows/Playground.Net46/App.xaml b/ReactWindows/Playground.Net46/App.xaml
new file mode 100644
index 00000000000..9dddbb94baf
--- /dev/null
+++ b/ReactWindows/Playground.Net46/App.xaml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/ReactWindows/Playground.Net46/App.xaml.cs b/ReactWindows/Playground.Net46/App.xaml.cs
new file mode 100644
index 00000000000..41b1dd530f7
--- /dev/null
+++ b/ReactWindows/Playground.Net46/App.xaml.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Navigation;
+
+namespace Playground.Net46
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public partial class App : Application
+ {
+ private readonly AppReactPage _reactPage = new AppReactPage();
+
+ ///
+ /// 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().
+ ///
+ public App()
+ {
+ }
+
+ ///
+ /// Override method fired prior to the Startup event when the Run method of the Application object is called...
+ ///
+ ///
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ base.OnStartup(e);
+ OnCreate(e.Args);
+ }
+
+ ///
+ /// Called whenever the app is opened to initialized...
+ ///
+ ///
+ private void OnCreate(string[] arguments)
+ {
+ var shellWindow = Application.Current.MainWindow;
+
+ if (shellWindow == null)
+ {
+ shellWindow = new Window
+ {
+ ShowActivated = true,
+ ShowInTaskbar = true,
+ Title = "Playground.Net46",
+ Height = 768,
+ Width = 1024,
+ WindowStartupLocation = WindowStartupLocation.CenterScreen
+ };
+
+ Application.Current.MainWindow = shellWindow;
+ }
+
+ //Show Window if it is not already active...
+ if (!shellWindow.IsLoaded)
+ {
+ shellWindow.Show();
+ }
+
+ var rootFrame = shellWindow.Content as Frame;
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active
+ if (rootFrame == null)
+ {
+ _reactPage.OnCreate(arguments);
+
+ // Create a Frame to act as the navigation context and navigate to the first page
+ rootFrame = new Frame();
+
+ rootFrame.NavigationFailed += OnNavigationFailed;
+
+ // Place the frame in the current Window
+ shellWindow.Content = rootFrame;
+ }
+
+ if (rootFrame.Content == null)
+ {
+ // 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.Content = _reactPage;
+ }
+
+ // Ensure the current window is active
+ shellWindow.Activate();
+ }
+
+ ///
+ /// Invoked when Navigation to a certain page fails
+ ///
+ /// The Frame which failed navigation
+ /// Details about the navigation failure
+ private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ throw new Exception("Failed to load Page...");
+ }
+ }
+}
diff --git a/ReactWindows/Playground.Net46/AppReactPage.cs b/ReactWindows/Playground.Net46/AppReactPage.cs
new file mode 100644
index 00000000000..16e8c22acb1
--- /dev/null
+++ b/ReactWindows/Playground.Net46/AppReactPage.cs
@@ -0,0 +1,41 @@
+using ReactNative;
+using ReactNative.Modules.Core;
+using ReactNative.Shell;
+using System.Collections.Generic;
+
+namespace Playground.Net46
+{
+ internal class AppReactPage : ReactPage
+ {
+ public override string MainComponentName => "Playground.Net46";
+
+ public override string JavaScriptMainModuleName => "ReactWindows/Playground.Net46/index.windows";
+
+#if BUNDLE
+ public override string JavaScriptBundleFile
+ {
+ get
+ {
+ return "ms-appx:///ReactAssets/index.windows.bundle";
+ }
+ }
+#endif
+
+ public override List Packages => new List
+ {
+ new MainReactPackage(),
+ };
+
+ public override bool UseDeveloperSupport
+ {
+ get
+ {
+#if !BUNDLE || DEBUG
+ return true;
+#else
+ return false;
+#endif
+ }
+ }
+ }
+}
diff --git a/ReactWindows/Playground.Net46/Playground.Net46.csproj b/ReactWindows/Playground.Net46/Playground.Net46.csproj
new file mode 100644
index 00000000000..c1090542750
--- /dev/null
+++ b/ReactWindows/Playground.Net46/Playground.Net46.csproj
@@ -0,0 +1,126 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}
+ WinExe
+ Properties
+ Playground.Net46
+ Playground.Net46
+ v4.6
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+
+
+
+ true
+ bin\x86\Debug\
+ TRACE;DEBUG;NET46
+ full
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+ false
+
+
+ bin\x86\Release\
+ TRACE;NET46
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ ARM
+ bin\ARM\Debug\
+ DEBUG
+
+
+ ARM
+ bin\ARM\Release\
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+
+
+
+ Code
+
+
+
+
+
+
+
+
+ {22cbff9c-fe36-43e8-a246-266c7635e662}
+ ReactNative.Net46
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReactWindows/Playground.Net46/Properties/AssemblyInfo.cs b/ReactWindows/Playground.Net46/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000000..9f6451f4896
--- /dev/null
+++ b/ReactWindows/Playground.Net46/Properties/AssemblyInfo.cs
@@ -0,0 +1,53 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Playground.Net46")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Playground.Net46")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/ReactWindows/Playground.Net46/index.windows.js b/ReactWindows/Playground.Net46/index.windows.js
new file mode 100644
index 00000000000..22df388f5b0
--- /dev/null
+++ b/ReactWindows/Playground.Net46/index.windows.js
@@ -0,0 +1,56 @@
+/**
+ * Sample React Native App
+ * https://github.com/facebook/react-native
+ */
+
+import React, { Component } from 'react';
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+
+class Playground extends Component {
+ render() {
+ return (
+
+
+ Welcome to React Native!
+
+
+ To get started, edit index.windows.js
+
+
+ Press Ctrl+R to reload
+
+
+ Press Ctrl+D or Ctrl+M for dev menu
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+ welcome: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ width: 500
+ },
+ instructions: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
+ width: 500
+ },
+});
+
+AppRegistry.registerComponent('Playground.Net46', () => Playground);
diff --git a/ReactWindows/Playground.Net46/packages.config b/ReactWindows/Playground.Net46/packages.config
new file mode 100644
index 00000000000..b45aef647cd
--- /dev/null
+++ b/ReactWindows/Playground.Net46/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/ReactWindows/ReactNative.Net46.Tests/Internal/DispatcherHelpers.cs b/ReactWindows/ReactNative.Net46.Tests/Internal/DispatcherHelpers.cs
index b9afe563a01..f5b617424b8 100644
--- a/ReactWindows/ReactNative.Net46.Tests/Internal/DispatcherHelpers.cs
+++ b/ReactWindows/ReactNative.Net46.Tests/Internal/DispatcherHelpers.cs
@@ -1,9 +1,9 @@
-using System;
+using NUnit.Framework;
+using System;
using System.Threading;
using System.Threading.Tasks;
-using System.Windows.Threading;
using System.Windows;
-using NUnit.Framework;
+using System.Windows.Threading;
namespace ReactNative.Tests
{
@@ -14,7 +14,7 @@ public static async Task RunOnDispatcherAsync(Action action)
Dispatcher dispatcher = Application.Current != null
? Application.Current.Dispatcher
: Dispatcher.CurrentDispatcher;
- if (Thread.CurrentThread == Dispatcher.CurrentDispatcher.Thread)
+ if (dispatcher.CheckAccess())
{
dispatcher.Invoke(action);
}
diff --git a/ReactWindows/ReactNative.Net46.Tests/Modules/NetInfo/NetInfoModuleTests.cs b/ReactWindows/ReactNative.Net46.Tests/Modules/NetInfo/NetInfoModuleTests.cs
index 19748e37c11..23090d4ef32 100644
--- a/ReactWindows/ReactNative.Net46.Tests/Modules/NetInfo/NetInfoModuleTests.cs
+++ b/ReactWindows/ReactNative.Net46.Tests/Modules/NetInfo/NetInfoModuleTests.cs
@@ -1,13 +1,12 @@
-using NMock;
+using Newtonsoft.Json.Linq;
using NUnit.Framework;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using ReactNative.Bridge;
using ReactNative.Modules.Core;
using ReactNative.Modules.NetInfo;
using System;
using System.Net.NetworkInformation;
using System.Threading;
+using System.Windows.Threading;
namespace ReactNative.Tests.Modules.NetInfo
{
@@ -34,8 +33,11 @@ public void NetInfoModule_JsonResponse()
}
[Test]
+ [Apartment(ApartmentState.STA)]
public void NetInfoModule_Event()
{
+ SetDispatcherForTest();
+
var networkInterface = new MockNetworkInterface("None");
var networkInfo = new MockNetworkInformation(networkInterface);
@@ -61,8 +63,11 @@ public void NetInfoModule_Event()
}
[Test]
+ [Apartment(ApartmentState.STA)]
public void NetInfoModule_LifecycleChecks()
{
+ SetDispatcherForTest();
+
var started = new AutoResetEvent(false);
var stopped = new AutoResetEvent(false);
@@ -105,6 +110,11 @@ private static ReactContext CreateReactContext(IInvocationHandler handler)
return context;
}
+ private static void SetDispatcherForTest()
+ {
+ ReactNative.Bridge.DispatcherHelpers.CurrentDispatcher = Dispatcher.CurrentDispatcher;
+ }
+
class TestReactInstance : MockReactInstance
{
private readonly object _eventEmitter;
diff --git a/ReactWindows/ReactNative.Net46/Bridge/DispatcherHelpers.cs b/ReactWindows/ReactNative.Net46/Bridge/DispatcherHelpers.cs
index b700b756bd1..deef2ff870e 100644
--- a/ReactWindows/ReactNative.Net46/Bridge/DispatcherHelpers.cs
+++ b/ReactWindows/ReactNative.Net46/Bridge/DispatcherHelpers.cs
@@ -7,6 +7,38 @@ namespace ReactNative.Bridge
{
static class DispatcherHelpers
{
+ private static Dispatcher _dispatcher;
+
+ internal static Dispatcher CurrentDispatcher
+ {
+ get
+ {
+ AssertDispatcherSet();
+
+ return _dispatcher;
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ if (value.Thread.GetApartmentState() != ApartmentState.STA)
+ {
+ throw new ArgumentException("Dispatcher must be an STA thread");
+ }
+
+ _dispatcher = value;
+ }
+ }
+
+ public static bool IsDispatcherSet()
+ {
+ return _dispatcher != null;
+ }
+
public static void AssertOnDispatcher()
{
if (!IsOnDispatcher())
@@ -17,12 +49,16 @@ public static void AssertOnDispatcher()
public static bool IsOnDispatcher()
{
- return Thread.CurrentThread == Dispatcher.CurrentDispatcher.Thread;
+ AssertDispatcherSet();
+
+ return CurrentDispatcher.CheckAccess();
}
public static async void RunOnDispatcher(Action action)
{
- await Dispatcher.CurrentDispatcher.InvokeAsync(action).Task.ConfigureAwait(false);
+ AssertDispatcherSet();
+
+ await CurrentDispatcher.InvokeAsync(action).Task.ConfigureAwait(false);
}
public static Task CallOnDispatcher(Func func)
@@ -40,5 +76,13 @@ public static Task CallOnDispatcher(Func func)
return taskCompletionSource.Task;
}
+
+ private static void AssertDispatcherSet()
+ {
+ if (_dispatcher == null)
+ {
+ throw new InvalidOperationException("Dispatcher has not been set");
+ }
+ }
}
}
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/Controls/LoadingIndicator.cs b/ReactWindows/ReactNative.Net46/DevSupport/Controls/LoadingIndicator.cs
new file mode 100644
index 00000000000..57857eb7781
--- /dev/null
+++ b/ReactWindows/ReactNative.Net46/DevSupport/Controls/LoadingIndicator.cs
@@ -0,0 +1,140 @@
+using System.Windows;
+using System.Windows.Controls;
+
+namespace ReactNative.DevSupport.Controls
+{
+ ///
+ /// A control featuring a range of loading indicating animations.
+ ///
+ [TemplatePart(Name = "Border", Type = typeof(Border))]
+ public class LoadingIndicator : Control
+ {
+ ///
+ /// Property used to set the speed of the animation...
+ ///
+ public static readonly DependencyProperty SpeedRatioProperty =
+ DependencyProperty.Register("SpeedRatio", typeof(double), typeof(LoadingIndicator), new PropertyMetadata(1d, (o, e) =>
+ {
+ var li = (LoadingIndicator)o;
+
+ if (li.PART_Border == null || li.IsActive == false)
+ {
+ return;
+ }
+
+ foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(li.PART_Border))
+ {
+ if (group.Name == "ActiveStates")
+ {
+ foreach (VisualState state in group.States)
+ {
+ if (state.Name == "Active")
+ {
+ state.Storyboard.SetSpeedRatio(li.PART_Border, (double)e.NewValue);
+ }
+ }
+ }
+ }
+ }));
+
+ ///
+ /// Property used to indicate whether the animation should be made active...
+ ///
+ public static readonly DependencyProperty IsActiveProperty =
+ DependencyProperty.Register("IsActive", typeof(bool), typeof(LoadingIndicator), new PropertyMetadata(true, (o, e) =>
+ {
+ var li = (LoadingIndicator)o;
+
+ if (li.PART_Border == null)
+ {
+ return;
+ }
+
+ if ((bool)e.NewValue == false)
+ {
+ VisualStateManager.GoToElementState(li.PART_Border, "Inactive", false);
+ li.PART_Border.Visibility = Visibility.Collapsed;
+ }
+ else
+ {
+ VisualStateManager.GoToElementState(li.PART_Border, "Active", false);
+ li.PART_Border.Visibility = Visibility.Visible;
+
+ foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(li.PART_Border))
+ {
+ if (group.Name == "ActiveStates")
+ {
+ foreach (VisualState state in group.States)
+ {
+ if (state.Name == "Active")
+ {
+ state.Storyboard.SetSpeedRatio(li.PART_Border, li.SpeedRatio);
+ }
+ }
+ }
+ }
+ }
+ }));
+
+ ///
+ /// Border Template Part Accessor
+ ///
+ protected Border PART_Border;
+
+ ///
+ /// Get/set the speed ratio of the animation.
+ ///
+ public double SpeedRatio
+ {
+ get { return (double)GetValue(SpeedRatioProperty); }
+ set { SetValue(SpeedRatioProperty, value); }
+ }
+
+ ///
+ /// Get/set whether the loading indicator is active.
+ ///
+ public bool IsActive
+ {
+ get { return (bool)GetValue(IsActiveProperty); }
+ set { SetValue(IsActiveProperty, value); }
+ }
+
+ ///
+ /// When overridden in a derived class, is invoked whenever application code
+ /// or internal processes call System.Windows.FrameworkElement.ApplyTemplate().
+ ///
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ PART_Border = (Border)GetTemplateChild("PART_Border");
+
+ if (PART_Border != null)
+ {
+ VisualStateManager.GoToElementState(PART_Border, (this.IsActive ? "Active" : "Inactive"), false);
+ foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(PART_Border))
+ {
+ if (group.Name == "ActiveStates")
+ {
+ foreach (VisualState state in group.States)
+ {
+ if (state.Name == "Active")
+ {
+ state.Storyboard.SetSpeedRatio(PART_Border, this.SpeedRatio);
+ }
+ }
+ }
+ }
+
+ PART_Border.Visibility = (this.IsActive ? Visibility.Visible : Visibility.Collapsed);
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public LoadingIndicator()
+ {
+ }
+ }
+}
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml b/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml
index 2b090394fb9..3352aaa75e8 100644
--- a/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml
+++ b/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml
@@ -1,17 +1,58 @@
-
-
-
-
-
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:local="clr-namespace:ReactNative.DevSupport"
+ mc:Ignorable="d"
+ Style="{DynamicResource ContentDialogStyle}"
+ WindowStartupLocation="CenterOwner">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml.cs b/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml.cs
index dd50994a090..5a166732db2 100644
--- a/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml.cs
+++ b/ReactWindows/ReactNative.Net46/DevSupport/DevOptionDialog.xaml.cs
@@ -1,15 +1,25 @@
using System;
+using System.Windows;
using System.Windows.Controls;
namespace ReactNative.DevSupport
{
sealed partial class DevOptionDialog
{
+ #region Constructor(s)
+
+ ///
+ /// Initializes the DevOptionsDialog
+ ///
public DevOptionDialog()
{
InitializeComponent();
}
+ #endregion
+
+ #region Public Methods
+
///
/// Add button to dialog
///
@@ -17,14 +27,28 @@ public DevOptionDialog()
/// Action when button is pressed
public void Add(string name, Action onSelect)
{
- var button = new Button
+ if (this.OptionsStackPanel != null)
{
- Content = name,
- };
+ var button = new Button
+ {
+ Content = name,
+ };
- button.Click += (sender, args) => onSelect();
+ button.Click += (sender, args) => onSelect();
- OptionsStackPanel.Children.Add(button);
+ this.OptionsStackPanel.Children.Add(button);
+ }
}
+
+ #endregion
+
+ #region Event Handlers
+
+ private void OnCancelButtonClicked(object sender, RoutedEventArgs e)
+ {
+ this.Close();
+ }
+
+ #endregion
}
}
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml b/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml
index 11c3104a132..1aa04bdf720 100644
--- a/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml
+++ b/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml
@@ -2,26 +2,61 @@
x:Class="ReactNative.DevSupport.ProgressDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="using:ReactNative.DevSupport"
+ xmlns:local="clr-namespace:ReactNative.DevSupport"
+ xmlns:controls="clr-namespace:ReactNative.DevSupport.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- Title="{Binding Path=Heading, Mode=OneTime}" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" Topmost="True">
-
-
-
-
-
-
-
-
-
+ Title="{Binding Path=Heading, Mode=OneTime}"
+ Style="{DynamicResource ContentDialogStyle}"
+ WindowStartupLocation="CenterOwner"
+ mc:Ignorable="d" d:DesignHeight="125" d:DesignWidth="240">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml.cs b/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml.cs
index 3aa7b206619..629f1e82811 100644
--- a/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml.cs
+++ b/ReactWindows/ReactNative.Net46/DevSupport/ProgressDialog.xaml.cs
@@ -1,5 +1,7 @@
-using System.Reactive.Disposables;
+using System;
+using System.Reactive.Disposables;
using System.Threading;
+using System.Windows;
namespace ReactNative.DevSupport
{
@@ -9,24 +11,15 @@ namespace ReactNative.DevSupport
///
/// This is used when awaiting the regeneration of the JavaScript bundle.
///
- sealed partial class ProgressDialog
+ sealed partial class ProgressDialog : Window, IDisposable
{
- private readonly CancellationDisposable _cancellationDisposable;
+ #region Private Fields
- ///
- /// Instantiates the .
- ///
- /// The title.
- /// The message.
- public ProgressDialog(string title, string message)
- {
- InitializeComponent();
+ private readonly CancellationDisposable _cancellationDisposable;
- Heading = title;
- Message = message;
+ #endregion
- _cancellationDisposable = new CancellationDisposable();
- }
+ #region Properties
///
/// The title of the dialog.
@@ -41,14 +34,42 @@ public ProgressDialog(string title, string message)
///
/// The cancellation token cancelled upon dialog dismissal.
///
- public CancellationToken Token
+ public CancellationToken Token => _cancellationDisposable.Token;
+
+ #endregion
+
+ #region Constructor(s)
+
+ ///
+ /// Instantiates the .
+ ///
+ /// The title.
+ /// The message.
+ public ProgressDialog(string title, string message)
{
- get
- {
- return _cancellationDisposable.Token;
- }
+ Heading = title;
+ Message = message;
+
+ InitializeComponent();
+
+ DataContext = this;
+
+ _cancellationDisposable = new CancellationDisposable();
}
+ #endregion
+
+ #region Event Handlers
+
+ private void OnDismissButtonClicked(object sender, RoutedEventArgs e)
+ {
+ _cancellationDisposable.Dispose();
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
///
/// Disposes the .
///
@@ -56,5 +77,7 @@ public void Dispose()
{
_cancellationDisposable.Dispose();
}
+
+ #endregion
}
}
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml b/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml
index f154588a443..ebc6f7a04a5 100644
--- a/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml
+++ b/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml
@@ -1,51 +1,104 @@
+ Style="{DynamicResource ContentDialogStyle}"
+ WindowStartupLocation="CenterOwner"
+ mc:Ignorable="d" d:DesignHeight="756" d:DesignWidth="548">
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml.cs b/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml.cs
index 5eed8de0af6..49f40ecbb2d 100644
--- a/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml.cs
+++ b/ReactWindows/ReactNative.Net46/DevSupport/RedBoxDialog.xaml.cs
@@ -1,23 +1,40 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
-using System.Runtime.CompilerServices;
using System.Windows;
-using System.Windows.Controls;
-
-// The Content Dialog item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace ReactNative.DevSupport
{
///
/// The content dialog for red box exception display.
///
- sealed partial class RedBoxDialog : Window, INotifyPropertyChanged
+ sealed partial class RedBoxDialog : Window
{
+ #region Private Fields
+
private readonly Action _onClick;
- private string _message;
- private IList _stackTrace;
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The error cookie.
+ ///
+ public int ErrorCookie { get; set; }
+
+ ///
+ /// The message.
+ ///
+ public string Message { get; set; }
+
+ ///
+ /// The stack trace.
+ ///
+ public IList StackTrace { get; set; } = new List();
+
+ #endregion
+
+ #region Constructor(s)
///
/// Instantiates the .
@@ -29,58 +46,32 @@ public RedBoxDialog(Action onClick)
{
InitializeComponent();
+ this.DataContext = this;
+
_onClick = onClick;
}
- ///
- /// Notifies the event subscriber when properties change.
- ///
- public event PropertyChangedEventHandler PropertyChanged;
+ #endregion
- ///
- /// The error cookie.
- ///
- public int ErrorCookie
- {
- get;
- set;
- }
+ #region Event Handlers
- ///
- /// The exception message.
- ///
- public string Message
+ private void OnReloadButtonClicked(object sender, RoutedEventArgs e)
{
- get
+ if (_onClick != null)
{
- return _message;
+ _onClick();
}
- set
+ else
{
- _message = value;
- OnNotifyPropertyChanged();
+ this.Close();
}
}
- ///
- /// The stack trace.
- ///
- public IList StackTrace
+ private void OnCloseButtonClicked(object sender, RoutedEventArgs e)
{
- get
- {
- return _stackTrace;
- }
- set
- {
- _stackTrace = value;
- OnNotifyPropertyChanged();
- }
+ this.Close();
}
- private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = null)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
+ #endregion
}
}
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/Resources/Styles.xaml b/ReactWindows/ReactNative.Net46/DevSupport/Resources/Styles.xaml
new file mode 100644
index 00000000000..4a662b4100a
--- /dev/null
+++ b/ReactWindows/ReactNative.Net46/DevSupport/Resources/Styles.xaml
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReactWindows/ReactNative.Net46/DevSupport/WebSocketJavaScriptExecutor.cs b/ReactWindows/ReactNative.Net46/DevSupport/WebSocketJavaScriptExecutor.cs
index af916947c27..b4b642febf8 100644
--- a/ReactWindows/ReactNative.Net46/DevSupport/WebSocketJavaScriptExecutor.cs
+++ b/ReactWindows/ReactNative.Net46/DevSupport/WebSocketJavaScriptExecutor.cs
@@ -9,6 +9,7 @@
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
+using WebSocketSharp;
namespace ReactNative.DevSupport
{
@@ -17,7 +18,7 @@ class WebSocketJavaScriptExecutor : IJavaScriptExecutor
private const int ConnectTimeoutMilliseconds = 5000;
private const int ConnectRetryCount = 3;
- private TcpClient _webSocket;
+ private WebSocket _webSocket;
private readonly JObject _injectedObjects;
private readonly IDictionary> _callbacks;
@@ -166,8 +167,12 @@ private async Task ConnectCoreAsync(Uri uri, CancellationToken token)
{
if (!_connected)
{
- _webSocket = TcpClient.Connect(IPAddress.Parse(uri.Host), uri.Port);
- _webSocket.ReceivedMessage += OnMessageReceived;
+ _webSocket = new WebSocket(uri.AbsoluteUri);
+
+ _webSocket.OnMessage += OnMessageReceived;
+
+ _webSocket.ConnectAsync();
+
_connected = true;
}
@@ -219,9 +224,9 @@ private void SendMessage(int requestId, string message)
}
}
- private void OnMessageReceived(object sender, EventArgs args)
+ private void OnMessageReceived(object sender, MessageEventArgs args)
{
- var response = args.ToString();
+ var response = args.Data;
var json = JObject.Parse(response);
if (json.ContainsKey("replyID"))
diff --git a/ReactWindows/ReactNative.Net46/Modules/WebSocket/WebSocketModule.cs b/ReactWindows/ReactNative.Net46/Modules/WebSocket/WebSocketModule.cs
new file mode 100644
index 00000000000..43a4c715ae2
--- /dev/null
+++ b/ReactWindows/ReactNative.Net46/Modules/WebSocket/WebSocketModule.cs
@@ -0,0 +1,199 @@
+using Newtonsoft.Json.Linq;
+using ReactNative.Bridge;
+using ReactNative.Collections;
+using ReactNative.Common;
+using ReactNative.Modules.Core;
+using ReactNative.Tracing;
+using System;
+using System.Collections.Generic;
+using WebSocketSharp;
+using static System.FormattableString;
+
+namespace ReactNative.Modules.WebSocket
+{
+ class WebSocketModule : ReactContextNativeModuleBase
+ {
+ private readonly IDictionary _webSocketConnections = new Dictionary();
+
+ #region Constructor(s)
+
+ public WebSocketModule(ReactContext reactContext)
+ : base(reactContext)
+ {
+ }
+
+ #endregion
+
+ #region NativeModuleBase Overrides
+
+ public override string Name
+ {
+ get
+ {
+ return "WebSocketModule";
+ }
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ [ReactMethod]
+ public void connect(string url, string[] protocols, JObject options, int id)
+ {
+ if (options != null && options.ContainsKey("origin"))
+ {
+ throw new NotImplementedException(/* TODO: (#253) */);
+ }
+
+ var webSocket = new WebSocketSharp.WebSocket(url);
+
+ webSocket.OnMessage += (sender, args) =>
+ {
+ OnMessageReceived(id, sender, args);
+ };
+
+ webSocket.OnOpen += (sender, args) =>
+ {
+ OnOpen(id, webSocket, args);
+ };
+
+ webSocket.OnError += (sender, args) =>
+ {
+ OnError(id, args);
+ };
+
+ webSocket.OnClose += (sender, args) =>
+ {
+ OnClosed(id, sender, args);
+ };
+
+ InitializeInBackground(id, url, webSocket);
+ }
+
+ [ReactMethod]
+ public void close(ushort code, string reason, int id)
+ {
+ WebSocketSharp.WebSocket webSocket;
+
+ if (!_webSocketConnections.TryGetValue(id, out webSocket))
+ {
+ Tracer.Write(
+ ReactConstants.Tag,
+ Invariant($"Cannot close WebSocket. Unknown WebSocket id {id}."));
+
+ return;
+ }
+
+ try
+ {
+ webSocket.Close(code, reason);
+ }
+ catch (Exception ex)
+ {
+ if (_webSocketConnections.ContainsKey(id))
+ {
+ _webSocketConnections.Remove(id);
+ }
+
+ Tracer.Error(
+ ReactConstants.Tag,
+ Invariant($"Could not close WebSocket connection for id '{id}'."),
+ ex);
+ }
+ }
+
+ [ReactMethod]
+ public void send(string message, int id)
+ {
+ SendMessageInBackground(id, message);
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ private void OnOpen(int id, WebSocketSharp.WebSocket webSocket, EventArgs args)
+ {
+ if (webSocket != null)
+ {
+ _webSocketConnections.Add(id, webSocket);
+
+ SendEvent("websocketOpen", new JObject
+ {
+ {"id", id},
+ });
+ }
+ }
+
+ private void OnClosed(int id, object webSocket, CloseEventArgs args)
+ {
+ if (_webSocketConnections.ContainsKey(id))
+ {
+ _webSocketConnections.Remove(id);
+
+ SendEvent("websocketClosed", new JObject
+ {
+ {"id", id},
+ {"code", args.Code},
+ {"reason", args.Reason},
+ });
+ }
+ else
+ {
+ SendEvent("websocketFailed", new JObject
+ {
+ { "id", id },
+ {"code", args.Code},
+ { "message", args.Reason },
+ });
+ }
+ }
+
+ private void OnError(int id, WebSocketSharp.ErrorEventArgs args)
+ {
+ if (_webSocketConnections.ContainsKey(id))
+ {
+ _webSocketConnections.Remove(id);
+ }
+
+ SendEvent("websocketFailed", new JObject
+ {
+ { "id", id },
+ { "message", args.Message },
+ });
+ }
+
+ private void OnMessageReceived(int id, object sender, MessageEventArgs args)
+ {
+ var message = args.Data;
+ SendEvent("websocketMessage", new JObject
+ {
+ { "id", id },
+ { "data", message },
+ });
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private void InitializeInBackground(int id, string url, WebSocketSharp.WebSocket webSocket)
+ {
+ webSocket?.Connect();
+ }
+
+ private void SendMessageInBackground(int id, string message)
+ {
+ _webSocketConnections[id].SendAsync(message, null);
+ }
+
+ private void SendEvent(string eventName, JObject parameters)
+ {
+ Context.GetJavaScriptModule()
+ .emit(eventName, parameters);
+ }
+
+ #endregion
+ }
+}
diff --git a/ReactWindows/ReactNative.Net46/ReactNative.Net46.csproj b/ReactWindows/ReactNative.Net46/ReactNative.Net46.csproj
index 5c437038af2..e481f5d8726 100644
--- a/ReactWindows/ReactNative.Net46/ReactNative.Net46.csproj
+++ b/ReactWindows/ReactNative.Net46/ReactNative.Net46.csproj
@@ -17,7 +17,9 @@
bin\x86\Debug\
DEBUG;NET46
bin\x86\Debug\ReactNative.Net46.XML
- none
+ pdbonly
+ 1
+ true
x86
@@ -31,6 +33,7 @@
bin\x64\Debug\
bin\x64\Debug\ReactNative.Net46.XML
DEBUG
+ pdbonly
x64
@@ -44,6 +47,7 @@
bin\ARM\Debug\
bin\ARM\Debug\ReactNative.Net46.XML
DEBUG
+ pdbonly
ARM
@@ -99,6 +103,7 @@
True
+
@@ -106,6 +111,10 @@
+
+ ..\packages\WebSocketSharp.1.0.3-rc11\lib\websocket-sharp.dll
+ True
+
..\packages\WindowsBase.4.6.1055.0\lib\WindowsBase.dll
True
@@ -116,6 +125,7 @@
DevOptionDialog.xaml
+
ProgressDialog.xaml
@@ -131,8 +141,10 @@
+
+
@@ -159,6 +171,10 @@
+
+ Designer
+ MSBuild:Compile
+
Designer
diff --git a/ReactWindows/ReactNative.Net46/ReactPage.cs b/ReactWindows/ReactNative.Net46/ReactPage.cs
index 0c0a1601cbf..815da65b2fb 100644
--- a/ReactWindows/ReactNative.Net46/ReactPage.cs
+++ b/ReactWindows/ReactNative.Net46/ReactPage.cs
@@ -1,12 +1,11 @@
-using ReactNative.Bridge;
-using ReactNative.Modules.Core;
-using System;
+using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
-using System.Windows.Media;
+using ReactNative.Bridge;
+using ReactNative.Modules.Core;
namespace ReactNative
{
@@ -15,21 +14,35 @@ namespace ReactNative
///
public abstract class ReactPage : Page, IAsyncDisposable
{
- private readonly IReactInstanceManager _reactInstanceManager;
-
- private bool _isShiftKeyDown;
- private bool _isControlKeyDown;
+ private readonly Lazy _reactInstanceManager;
+ private readonly Lazy _rootView;
///
/// Instantiates the .
///
protected ReactPage()
{
- _reactInstanceManager = CreateReactInstanceManager();
- RootView = CreateRootView();
- Content = RootView;
+ _reactInstanceManager = new Lazy(() =>
+ {
+ DispatcherHelpers.CurrentDispatcher = base.Dispatcher;
+
+ var reactInstanceManager = CreateReactInstanceManager();
+
+ return reactInstanceManager;
+ });
+
+ _rootView = new Lazy(() =>
+ {
+ var rootview = CreateRootView();
+
+ base.Content = rootview;
+
+ return rootview;
+ });
}
+ private IReactInstanceManager ReactInstanceManager => _reactInstanceManager.Value;
+
///
/// The custom path of the bundle file.
///
@@ -79,20 +92,22 @@ public virtual string JavaScriptMainModuleName
///
/// The root view managed by the page.
///
- public ReactRootView RootView { get; }
+ public ReactRootView RootView => _rootView.Value;
///
/// Called when the application is first initialized.
///
/// The launch arguments.
- public void OnCreate(string arguments)
+ public void OnCreate(string[] arguments)
{
- RootView.Background = (Brush)Application.Current.Resources["ApplicationPageBackgroundThemeBrush"];
-
ApplyArguments(arguments);
- RootView.StartReactApplication(_reactInstanceManager, MainComponentName);
+ RootView.StartReactApplication(ReactInstanceManager, MainComponentName);
RootView.AddHandler(Keyboard.KeyDownEvent, (KeyEventHandler)OnAcceleratorKeyActivated);
+
+ RootView.Focusable = true;
+ RootView.Focus();
+ RootView.FocusVisualStyle = null;
}
///
@@ -100,7 +115,7 @@ public void OnCreate(string arguments)
///
public void OnSuspend()
{
- _reactInstanceManager.OnSuspend();
+ ReactInstanceManager.OnSuspend();
}
///
@@ -111,17 +126,20 @@ public void OnSuspend()
///
public void OnResume(Action onBackPressed)
{
- _reactInstanceManager.OnResume(onBackPressed);
+ ReactInstanceManager.OnResume(onBackPressed);
}
///
/// Called before the application shuts down.
///
- public Task DisposeAsync()
+ public async Task DisposeAsync()
{
- RootView.RemoveHandler(Keyboard.KeyDownEvent, (KeyEventHandler)OnAcceleratorKeyActivated);
+ RootView?.RemoveHandler(Keyboard.KeyDownEvent, (KeyEventHandler) OnAcceleratorKeyActivated);
- return _reactInstanceManager.DisposeAsync();
+ if (_reactInstanceManager.IsValueCreated)
+ {
+ await ReactInstanceManager.DisposeAsync().ConfigureAwait(false);
+ }
}
///
@@ -144,24 +162,27 @@ protected virtual ReactRootView CreateRootView()
///
private void OnAcceleratorKeyActivated(object sender, KeyEventArgs e)
{
- if (_reactInstanceManager.DevSupportManager.IsEnabled)
+ if (ReactInstanceManager.DevSupportManager.IsEnabled)
{
- // Shift+F10 or Shift+Menu
- if ((e.Key == Key.F10 || e.Key == Key.Apps) &&
- (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
+ var isCtrlKeyDown = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
+
+ //Ctrl+D or Ctrl+M
+ if (isCtrlKeyDown && (e.Key == Key.D || e.Key == Key.M))
{
- _reactInstanceManager.DevSupportManager.ShowDevOptionsDialog();
+ ReactInstanceManager.DevSupportManager.ShowDevOptionsDialog();
}
+
// Ctrl+R
- if (e.Key == Key.R && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
+ if (isCtrlKeyDown && e.Key == Key.R)
{
- _reactInstanceManager.DevSupportManager.HandleReloadJavaScript();
+ ReactInstanceManager.DevSupportManager.HandleReloadJavaScript();
}
}
+
// Back button
if (e.Key == Key.Back || e.Key == Key.BrowserBack)
{
- _reactInstanceManager.OnBackPressed();
+ ReactInstanceManager.OnBackPressed();
}
}
@@ -179,22 +200,28 @@ private IReactInstanceManager CreateReactInstanceManager()
return builder.Build();
}
- private void ApplyArguments(string arguments)
+ private void ApplyArguments(string[] arguments)
{
- if (!string.IsNullOrEmpty(arguments))
+ if (arguments == null)
{
- var args = arguments.Split(',');
- if (args.Length % 2 != 0)
- {
- throw new ArgumentException("Expected even number of arguments.", nameof(arguments));
- }
+ return;
+ }
- var index = Array.IndexOf(args, "remoteDebugging");
- var isRemoteDebuggingEnabled = default(bool);
- if (index % 2 == 0 && bool.TryParse(args[index + 1], out isRemoteDebuggingEnabled))
- {
- _reactInstanceManager.DevSupportManager.IsRemoteDebuggingEnabled = isRemoteDebuggingEnabled;
- }
+ if (arguments.Length == 0)
+ {
+ return;
+ }
+
+ if (arguments.Length % 2 != 0)
+ {
+ throw new ArgumentException("Expected even number of arguments.", nameof(arguments));
+ }
+
+ var index = Array.IndexOf(arguments, "remoteDebugging");
+ var isRemoteDebuggingEnabled = default(bool);
+ if (index % 2 == 0 && bool.TryParse(arguments[index + 1], out isRemoteDebuggingEnabled))
+ {
+ ReactInstanceManager.DevSupportManager.IsRemoteDebuggingEnabled = isRemoteDebuggingEnabled;
}
}
}
diff --git a/ReactWindows/ReactNative.Net46/Shell/MainReactPackage.cs b/ReactWindows/ReactNative.Net46/Shell/MainReactPackage.cs
new file mode 100644
index 00000000000..58caff6a041
--- /dev/null
+++ b/ReactWindows/ReactNative.Net46/Shell/MainReactPackage.cs
@@ -0,0 +1,94 @@
+using ReactNative.Bridge;
+using ReactNative.Modules.AppState;
+using ReactNative.Modules.Clipboard;
+using ReactNative.Modules.Core;
+using ReactNative.Modules.Dialog;
+using ReactNative.Modules.I18N;
+using ReactNative.Modules.NetInfo;
+using ReactNative.Modules.Network;
+using ReactNative.Modules.Storage;
+using ReactNative.Modules.WebSocket;
+using ReactNative.UIManager;
+using ReactNative.Views.Text;
+using ReactNative.Views.View;
+using System;
+using System.Collections.Generic;
+
+namespace ReactNative.Shell
+{
+ ///
+ /// Package defining basic modules and view managers.
+ ///
+ public class MainReactPackage : IReactPackage
+ {
+ ///
+ /// Creates the list of native modules to register with the react
+ /// instance.
+ ///
+ /// The React application context.
+ /// The list of native modules.
+ public IReadOnlyList CreateNativeModules(ReactContext reactContext)
+ {
+ return new List
+ {
+ new AppStateModule(reactContext),
+ new AsyncStorageModule(),
+ //new CameraRollManager(reactContext),
+ new ClipboardModule(),
+ new DialogModule(reactContext),
+ //new ImageLoaderModule(),
+ new I18NModule(),
+ //new LauncherModule(reactContext),
+ //new LocationModule(reactContext),
+ //new NativeAnimatedModule(reactContext),
+ new NetworkingModule(reactContext),
+ new NetInfoModule(reactContext),
+ //new StatusBarModule(),
+ //new VibrationModule(),
+ new WebSocketModule(reactContext),
+ };
+ }
+
+ ///
+ /// Creates the list of JavaScript modules to register with the
+ /// React instance.
+ ///
+ /// The list of JavaScript modules.
+ public IReadOnlyList CreateJavaScriptModulesConfig()
+ {
+ return new List(0);
+ }
+
+ ///
+ /// Creates the list of view managers that should be registered with
+ /// the .
+ ///
+ /// The React application context.
+ /// The list of view managers.
+ public IReadOnlyList CreateViewManagers(
+ ReactContext reactContext)
+ {
+ return new List
+ {
+ //new ReactFlipViewManager(),
+ //new ReactImageManager(),
+ //new ReactProgressBarViewManager(),
+ //new ReactProgressRingViewManager(),
+ //new ReactPickerManager(),
+ new ReactRunManager(),
+ ////new RecyclerViewBackedScrollViewManager(),
+ //new ReactScrollViewManager(),
+ //new ReactSliderManager(),
+ //new ReactSplitViewManager(),
+ //new ReactSwitchManager(),
+ //new ReactPasswordBoxManager(),
+ //new ReactTextInputManager(),
+ new ReactTextViewManager(),
+ new ReactViewManager(),
+ new ReactSpanViewManager(),
+ ////new SwipeRefreshLayoutManager(),
+ //new ReactWebViewManager(),
+ };
+ }
+ }
+}
diff --git a/ReactWindows/ReactNative.Net46/Touch/TouchHandler.cs b/ReactWindows/ReactNative.Net46/Touch/TouchHandler.cs
index 63d64e03812..99be79e1b42 100644
--- a/ReactWindows/ReactNative.Net46/Touch/TouchHandler.cs
+++ b/ReactWindows/ReactNative.Net46/Touch/TouchHandler.cs
@@ -98,23 +98,21 @@ private void OnMouseDown(object sender, MouseButtonEventArgs e)
private void OnTouchMoved(object sender, TouchEventArgs e)
{
- var pointerIndex = 1;
- if (pointerIndex != -1)
+ if (_pointers != null && _pointers.Count > 0)
{
- var pointer = _pointers[pointerIndex];
+ var pointer = _pointers[0];
UpdatePointerForEvent(pointer, e);
- DispatchTouchEvent(TouchEventType.Move, _pointers, pointerIndex);
+ DispatchTouchEvent(TouchEventType.Move, _pointers, 0);
}
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
- var pointerIndex = 1;
- if (pointerIndex != -1)
+ if (_pointers != null && _pointers.Count > 0)
{
- var pointer = _pointers[pointerIndex];
+ var pointer = _pointers[0];
UpdatePointerForEvent(pointer, e);
- DispatchTouchEvent(TouchEventType.Move, _pointers, pointerIndex);
+ DispatchTouchEvent(TouchEventType.Move, _pointers, 0);
}
}
@@ -130,14 +128,13 @@ private void OnMouseUp(object sender, MouseButtonEventArgs e)
private void OnTouchConcluded(TouchEventType touchEventType, TouchEventArgs e)
{
- var pointerIndex = 1;
- if (pointerIndex != -1)
+ if (_pointers != null && _pointers.Count > 0)
{
- var pointer = _pointers[pointerIndex];
+ var pointer = _pointers[0];
UpdatePointerForEvent(pointer, e);
- DispatchTouchEvent(touchEventType, _pointers, pointerIndex);
+ DispatchTouchEvent(touchEventType, _pointers, 0);
- _pointers.RemoveAt(pointerIndex);
+ _pointers.RemoveAt(0);
if (_pointers.Count == 0)
{
@@ -150,14 +147,13 @@ private void OnTouchConcluded(TouchEventType touchEventType, TouchEventArgs e)
private void OnPointerConcluded(TouchEventType touchEventType, MouseButtonEventArgs e)
{
- var pointerIndex = 1;
- if (pointerIndex != -1)
+ if (_pointers != null && _pointers.Count > 0)
{
- var pointer = _pointers[pointerIndex];
+ var pointer = _pointers[0];
UpdatePointerForEvent(pointer, e);
- DispatchTouchEvent(touchEventType, _pointers, pointerIndex);
+ DispatchTouchEvent(touchEventType, _pointers, 0);
- _pointers.RemoveAt(pointerIndex);
+ _pointers.RemoveAt(0);
if (_pointers.Count == 0)
{
diff --git a/ReactWindows/ReactNative.Net46/UIManager/UIManagerModule.cs b/ReactWindows/ReactNative.Net46/UIManager/UIManagerModule.cs
index 7cd5e88ab81..2a6baa660b9 100644
--- a/ReactWindows/ReactNative.Net46/UIManager/UIManagerModule.cs
+++ b/ReactWindows/ReactNative.Net46/UIManager/UIManagerModule.cs
@@ -42,6 +42,8 @@ public UIManagerModule(
throw new ArgumentNullException(nameof(viewManagers));
if (uiImplementation == null)
throw new ArgumentNullException(nameof(uiImplementation));
+ if (window == null)
+ throw new ArgumentNullException(nameof(window));
_window = window;
_eventDispatcher = new EventDispatcher(reactContext);
diff --git a/ReactWindows/ReactNative.Net46/Views/Text/ReactTextCompoundView.cs b/ReactWindows/ReactNative.Net46/Views/Text/ReactTextCompoundView.cs
index 4c9af10d3e7..2d890490e58 100644
--- a/ReactWindows/ReactNative.Net46/Views/Text/ReactTextCompoundView.cs
+++ b/ReactWindows/ReactNative.Net46/Views/Text/ReactTextCompoundView.cs
@@ -8,7 +8,7 @@ class ReactTextCompoundView : IReactCompoundView
{
public int GetReactTagAtPoint(UIElement reactView, Point point)
{
- var richTextBlock = reactView.As();
+ var richTextBlock = reactView.As();
var textPointer = richTextBlock.GetPositionFromPoint(point, true);
return textPointer.Parent.GetTag();
}
diff --git a/ReactWindows/ReactNative.Net46/Views/Text/ReactTextShadowNode.cs b/ReactWindows/ReactNative.Net46/Views/Text/ReactTextShadowNode.cs
index 03ee349d84e..8c62bf015d3 100644
--- a/ReactWindows/ReactNative.Net46/Views/Text/ReactTextShadowNode.cs
+++ b/ReactWindows/ReactNative.Net46/Views/Text/ReactTextShadowNode.cs
@@ -23,7 +23,7 @@ public class ReactTextShadowNode : LayoutShadowNode
private FontStyle? _fontStyle;
private FontWeight? _fontWeight;
- private HorizontalAlignment _textAlignment = HorizontalAlignment.Left;
+ private TextAlignment _textAlignment = TextAlignment.Left;
private string _fontFamily;
@@ -147,8 +147,8 @@ public virtual void SetNumberOfLines(int numberOfLines)
public void SetTextAlign(string textAlign)
{
var textAlignment = textAlign == "auto" || textAlign == null ?
- HorizontalAlignment.Left :
- EnumHelpers.Parse(textAlign);
+ TextAlignment.Left :
+ EnumHelpers.Parse(textAlign);
if (_textAlignment != textAlignment)
{
@@ -192,21 +192,19 @@ private static MeasureOutput MeasureText(CSSNode node, float width, CSSMeasureMo
// TODO: determine another way to measure text elements.
var task = DispatcherHelpers.CallOnDispatcher(() =>
{
- var textBlock = new RichTextBox
+ var textBlock = new TextBlock
{
- HorizontalContentAlignment = HorizontalAlignment.Left,
- // TextTrimming = TextTrimming.CharacterEllipsis,
+ TextAlignment = TextAlignment.Left,
+ TextTrimming = TextTrimming.CharacterEllipsis,
};
var textNode = (ReactTextShadowNode)node;
textNode.UpdateTextBlockCore(textBlock, true);
- var block = new Paragraph();
foreach (var child in textNode.Children)
{
- block.Inlines.Add(ReactInlineShadowNodeVisitor.Apply(child));
+ textBlock.Inlines.Add(ReactInlineShadowNodeVisitor.Apply(child));
}
- textBlock.Document.Blocks.Add(block);
var normalizedWidth = CSSConstants.IsUndefined(width) ? double.PositiveInfinity : width;
var normalizedHeight = CSSConstants.IsUndefined(height) ? double.PositiveInfinity : height;
@@ -220,21 +218,20 @@ private static MeasureOutput MeasureText(CSSNode node, float width, CSSMeasureMo
}
///
- /// Updates the properties of a view.
+ /// Updates the properties of a view.
///
/// The view.
- public void UpdateTextBlock(RichTextBox textBlock)
+ public void UpdateTextBlock(TextBlock textBlock)
{
UpdateTextBlockCore(textBlock, false);
}
- private void UpdateTextBlockCore(RichTextBox textBlock, bool measureOnly)
+ private void UpdateTextBlockCore(TextBlock textBlock, bool measureOnly)
{
//textBlock.CharacterSpacing = _letterSpacing;
//textBlock.MaxLines = _numberOfLines;
- textBlock.Document = new FlowDocument();
- textBlock.Document.LineHeight = _lineHeight;
- textBlock.HorizontalContentAlignment = _textAlignment;
+ textBlock.LineHeight = _lineHeight != 0 ? _lineHeight : double.NaN;
+ textBlock.TextAlignment = _textAlignment;
textBlock.FontFamily = _fontFamily != null ? new FontFamily(_fontFamily) : new FontFamily();
textBlock.FontSize = _fontSize ?? 15;
textBlock.FontStyle = _fontStyle ?? new FontStyle();
diff --git a/ReactWindows/ReactNative.Net46/Views/Text/ReactTextViewManager.cs b/ReactWindows/ReactNative.Net46/Views/Text/ReactTextViewManager.cs
index 9be8c875fd2..68611b34b62 100644
--- a/ReactWindows/ReactNative.Net46/Views/Text/ReactTextViewManager.cs
+++ b/ReactWindows/ReactNative.Net46/Views/Text/ReactTextViewManager.cs
@@ -1,4 +1,5 @@
-using ReactNative.UIManager;
+using System;
+using ReactNative.UIManager;
using ReactNative.UIManager.Annotations;
using System.Collections;
using System.Linq;
@@ -12,7 +13,7 @@ namespace ReactNative.Views.Text
///
/// The view manager for text views.
///
- public class ReactTextViewManager : ViewParentManager
+ public class ReactTextViewManager : ViewParentManager
{
private static readonly IReactCompoundView s_compoundView = new ReactTextCompoundView();
@@ -33,7 +34,7 @@ public override string Name
/// The view.
/// The masked color value.
[ReactProp(ViewProps.Color, CustomType = "Color")]
- public void SetColor(RichTextBox view, uint? color)
+ public void SetColor(TextBlock view, uint? color)
{
view.Foreground = color.HasValue
? new SolidColorBrush(ColorHelpers.Parse(color.Value))
@@ -46,9 +47,9 @@ public void SetColor(RichTextBox view, uint? color)
/// The view.
/// A flag indicating whether or not the text is selectable.
[ReactProp("selectable")]
- public void SetSelectable(RichTextBox view, bool selectable)
+ public void SetSelectable(TextBlock view, bool selectable)
{
- // ToDo: Manually control selectable
+ throw new NotImplementedException();
}
///
@@ -57,7 +58,7 @@ public void SetSelectable(RichTextBox view, bool selectable)
/// The parent view.
/// The child view.
/// The index.
- public override void AddView(RichTextBox parent, DependencyObject child, int index)
+ public override void AddView(TextBlock parent, DependencyObject child, int index)
{
var inlineChild = child as Inline;
if (inlineChild == null)
@@ -68,7 +69,7 @@ public override void AddView(RichTextBox parent, DependencyObject child, int ind
};
}
- ((IList)parent.Document.Blocks.OfType().First().Inlines).Insert(index, inlineChild);
+ ((IList)parent.Inlines).Insert(index, inlineChild);
}
///
@@ -86,9 +87,9 @@ public override ReactTextShadowNode CreateShadowNodeInstance()
/// The parent view.
/// The index.
/// The child view.
- public override DependencyObject GetChildAt(RichTextBox parent, int index)
+ public override DependencyObject GetChildAt(TextBlock parent, int index)
{
- var child = ((IList)parent.Document.Blocks.OfType().First().Inlines)[index];
+ var child = ((IList)parent.Inlines)[index];
var childInlineContainer = child as InlineUIContainer;
if (childInlineContainer != null)
{
@@ -105,18 +106,18 @@ public override DependencyObject GetChildAt(RichTextBox parent, int index)
///
/// The view parent.
/// The number of children.
- public override int GetChildCount(RichTextBox parent)
+ public override int GetChildCount(TextBlock parent)
{
- return ((IList)parent.Document.Blocks.OfType().First().Inlines).Count;
+ return ((IList)parent.Inlines).Count;
}
///
/// Removes all children from the view parent.
///
/// The view parent.
- public override void RemoveAllChildren(RichTextBox parent)
+ public override void RemoveAllChildren(TextBlock parent)
{
- var inlines = parent.Document.Blocks.OfType().First().Inlines;
+ var inlines = parent.Inlines;
inlines.Clear();
}
@@ -125,9 +126,9 @@ public override void RemoveAllChildren(RichTextBox parent)
///
/// The view parent.
/// The index.
- public override void RemoveChildAt(RichTextBox parent, int index)
+ public override void RemoveChildAt(TextBlock parent, int index)
{
- var inlines = ((IList)parent.Document.Blocks.OfType().First().Inlines);
+ var inlines = (IList)parent.Inlines;
inlines.RemoveAt(index);
}
@@ -136,7 +137,7 @@ public override void RemoveChildAt(RichTextBox parent, int index)
///
/// The root view.
/// The extra data.
- public override void UpdateExtraData(RichTextBox root, object extraData)
+ public override void UpdateExtraData(TextBlock root, object extraData)
{
base.UpdateExtraData(root, extraData);
@@ -152,20 +153,17 @@ public override void UpdateExtraData(RichTextBox root, object extraData)
///
/// The React context.
/// The view instance.
- protected override RichTextBox CreateViewInstance(ThemedReactContext reactContext)
+ protected override TextBlock CreateViewInstance(ThemedReactContext reactContext)
{
- var richTextBlock = new RichTextBox
+ var textBlock = new TextBlock
{
- //IsTextSelectionEnabled = false,
- HorizontalContentAlignment = HorizontalAlignment.Left,
- //TextTrimming = TextTrimming.CharacterEllipsis,
+ TextAlignment = TextAlignment.Left,
+ TextTrimming = TextTrimming.CharacterEllipsis,
};
- richTextBlock.Document = new FlowDocument();
- richTextBlock.Document.Blocks.Add(new Paragraph());
- richTextBlock.SetReactCompoundView(s_compoundView);
+ textBlock.SetReactCompoundView(s_compoundView);
- return richTextBlock;
+ return textBlock;
}
}
}
diff --git a/ReactWindows/ReactNative.Net46/packages.config b/ReactWindows/ReactNative.Net46/packages.config
index 83f9959b311..d53a9ce4c5a 100644
--- a/ReactWindows/ReactNative.Net46/packages.config
+++ b/ReactWindows/ReactNative.Net46/packages.config
@@ -11,5 +11,6 @@
+
\ No newline at end of file
diff --git a/ReactWindows/ReactNative.Tests/Modules/WebSocket/WebSocketModuleTests.cs b/ReactWindows/ReactNative.Shared.Tests/Modules/WebSocket/WebSocketModuleTests.cs
similarity index 80%
rename from ReactWindows/ReactNative.Tests/Modules/WebSocket/WebSocketModuleTests.cs
rename to ReactWindows/ReactNative.Shared.Tests/Modules/WebSocket/WebSocketModuleTests.cs
index 0f01387234f..21920098734 100644
--- a/ReactWindows/ReactNative.Tests/Modules/WebSocket/WebSocketModuleTests.cs
+++ b/ReactWindows/ReactNative.Shared.Tests/Modules/WebSocket/WebSocketModuleTests.cs
@@ -1,5 +1,5 @@
-using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
-using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Linq;
+using NUnit.Framework;
using ReactNative.Bridge;
using ReactNative.Modules.Core;
using ReactNative.Modules.WebSocket;
@@ -7,11 +7,13 @@
namespace ReactNative.Tests.Modules.WebSocket
{
- [TestClass]
+ [TestFixture]
public class WebSocketModuleTests
{
- [TestMethod]
- [TestCategory("Network")]
+ private const int WaitTimeoutInMs = 5000;
+
+ [Test]
+ [Category("Network")]
public void WebSocketModule_OpenClosedEvent()
{
var waitHandle = new AutoResetEvent(false);
@@ -45,16 +47,17 @@ public void WebSocketModule_OpenClosedEvent()
finally
{
module.close(1000, "None", 1);
- Assert.IsTrue(waitHandle.WaitOne());
+ Assert.IsTrue(waitHandle.WaitOne(WaitTimeoutInMs));
+ waitHandle.Dispose();
}
- Assert.AreEqual(1, openParams["id"]);
- Assert.AreEqual(1, closeParams["id"]);
- Assert.AreEqual(1000, closeParams["code"]);
- Assert.AreEqual("None", closeParams["reason"]);
+ Assert.AreEqual(1, openParams["id"].Value());
+ Assert.AreEqual(1, closeParams["id"].Value());
+ Assert.AreEqual(1000, closeParams["code"].Value());
+ Assert.AreEqual("None", closeParams["reason"].Value());
}
- [TestMethod]
+ [Test]
public void WebSocketModule_FailedEvent()
{
var waitHandle = new AutoResetEvent(false);
@@ -78,18 +81,18 @@ public void WebSocketModule_FailedEvent()
try
{
module.connect("ws://invalid.websocket.address", null, null, 1);
- Assert.IsTrue(waitHandle.WaitOne());
+ Assert.IsTrue(waitHandle.WaitOne(WaitTimeoutInMs));
}
finally
{
module.close(1000, "None", 1);
}
- Assert.AreEqual(1, json["id"]);
+ Assert.AreEqual(1, json["id"].Value());
}
- [TestMethod]
- [TestCategory("Network")]
+ [Test]
+ [Category("Network")]
public void WebSocketModule_DataEvent()
{
var waitHandle = new AutoResetEvent(false);
@@ -116,18 +119,20 @@ public void WebSocketModule_DataEvent()
try
{
module.connect("ws://echo.websocket.org", null, null, 1);
- Assert.IsTrue(waitHandle.WaitOne());
+ Assert.IsTrue(waitHandle.WaitOne(WaitTimeoutInMs));
module.send("FooBarBaz", 1);
- Assert.IsTrue(waitHandle.WaitOne());
+ Assert.IsTrue(waitHandle.WaitOne(WaitTimeoutInMs));
}
finally
{
module.close(1000, "None", 1);
- Assert.IsTrue(waitHandle.WaitOne());
+ Assert.IsTrue(waitHandle.WaitOne(WaitTimeoutInMs));
+
+ waitHandle.Dispose();
}
- Assert.AreEqual(1, json["id"]);
- Assert.AreEqual("FooBarBaz", json["data"]);
+ Assert.AreEqual(1, json["id"].Value());
+ Assert.AreEqual("FooBarBaz", json["data"].Value());
}
private ReactContext CreateReactContext(IInvocationHandler handler)
diff --git a/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.projitems b/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.projitems
index ae6099c48a6..48d0f1fd834 100644
--- a/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.projitems
+++ b/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.projitems
@@ -15,5 +15,6 @@
+
\ No newline at end of file
diff --git a/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.shproj b/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.shproj
index ba13c8b4cf8..0332428f785 100644
--- a/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.shproj
+++ b/ReactWindows/ReactNative.Shared.Tests/ReactNative.Shared.Tests.shproj
@@ -8,6 +8,9 @@
+
+
+
-
+
\ No newline at end of file
diff --git a/ReactWindows/ReactNative.Shared/DevSupport/DevInternalSettings.cs b/ReactWindows/ReactNative.Shared/DevSupport/DevInternalSettings.cs
index a345e829d49..25c5adcb555 100644
--- a/ReactWindows/ReactNative.Shared/DevSupport/DevInternalSettings.cs
+++ b/ReactWindows/ReactNative.Shared/DevSupport/DevInternalSettings.cs
@@ -30,6 +30,10 @@ class DevInternalSettings : IDeveloperSettings
private readonly IDevSupportManager _debugManager;
+#if !WINDOWS_UWP
+ private readonly IDictionary _localSettings = new Dictionary();
+#endif
+
public DevInternalSettings(IDevSupportManager debugManager)
{
_debugManager = debugManager;
@@ -125,6 +129,8 @@ public bool IsReloadOnJavaScriptChangeEnabled
}
}
+
+ //TODO: Git Issue #878
private T GetSetting(string key, T defaultValue)
{
#if WINDOWS_UWP
@@ -140,16 +146,21 @@ private T GetSetting(string key, T defaultValue)
return defaultValue;
#else
- if (typeof(T) == typeof(bool))
- {
- var result = default(bool);
- var parsed = bool.TryParse(ConfigurationManager.AppSettings[key], out result);
- return (T)(object)(parsed && result);
- }
- else
+ if (_localSettings.ContainsKey(key))
{
- throw new NotSupportedException(Invariant($"Configuration values of type '{typeof(T)}' are not supported."));
+ var data = _localSettings[key];
+
+ if (data is T)
+ {
+ return (T)data;
+ }
+ else
+ {
+ throw new NotSupportedException(Invariant($"Configuration values of type '{typeof(T)}' are not supported."));
+ }
}
+
+ return defaultValue;
#endif
}
@@ -159,15 +170,7 @@ private void SetSetting(string key, T value)
var values = ApplicationData.Current.LocalSettings.Values;
values[key] = value;
#else
- var values = ConfigurationManager.AppSettings;
- if (values[key] == null)
- {
- values.Add(key, value.ToString());
- }
- else
- {
- values[key] = value.ToString();
- }
+ _localSettings[key] = value;
#endif
if (s_triggerReload.Contains(key))
diff --git a/ReactWindows/ReactNative.Shared/DevSupport/DevSupportManager.cs b/ReactWindows/ReactNative.Shared/DevSupport/DevSupportManager.cs
index 179ac54e98a..33ab94bd602 100644
--- a/ReactWindows/ReactNative.Shared/DevSupport/DevSupportManager.cs
+++ b/ReactWindows/ReactNative.Shared/DevSupport/DevSupportManager.cs
@@ -15,6 +15,7 @@
#else
using PCLStorage;
using System.Reflection;
+using System.Windows;
#endif
namespace ReactNative.DevSupport
@@ -297,11 +298,22 @@ public void ShowDevOptionsDialog()
option.HideDialog = _dismissDevOptionsDialog;
}
#else
- var asyncInfo = _devOptionsDialog.ShowDialog();
+ if (Application.Current != null && Application.Current.MainWindow != null && Application.Current.MainWindow.IsLoaded)
+ {
+ _devOptionsDialog.Owner = Application.Current.MainWindow;
+ }
+ else
+ {
+ _devOptionsDialog.Topmost = true;
+ _devOptionsDialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+ }
+
+ _dismissDevOptionsDialog = _devOptionsDialog.Close;
+ _devOptionsDialog.Show();
foreach (var option in options)
{
- option.HideDialog = _devOptionsDialog.Hide;
+ option.HideDialog = _dismissDevOptionsDialog;
}
#endif
});
@@ -350,8 +362,18 @@ public async void HandleReloadJavaScript()
var dialogOperation = progressDialog.ShowAsync();
Action cancel = dialogOperation.Cancel;
#else
- progressDialog.ShowDialog();
- Action cancel = progressDialog.Hide;
+ if (Application.Current != null && Application.Current.MainWindow != null && Application.Current.MainWindow.IsLoaded)
+ {
+ progressDialog.Owner = Application.Current.MainWindow;
+ }
+ else
+ {
+ progressDialog.Topmost = true;
+ progressDialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+ }
+
+ Action cancel = progressDialog.Close;
+ progressDialog.Show();
#endif
if (IsRemoteDebuggingEnabled)
{
@@ -455,8 +477,18 @@ private void ShowNewError(string message, IStackFrame[] stack, int errorCookie)
var asyncInfo = _redBoxDialog.ShowAsync();
_dismissRedBoxDialog = asyncInfo.Cancel;
#else
- var asyncInfo = _redBoxDialog.ShowDialog();
- _dismissRedBoxDialog = _redBoxDialog.Hide;
+ if (Application.Current != null && Application.Current.MainWindow != null && Application.Current.MainWindow.IsLoaded)
+ {
+ _redBoxDialog.Owner = Application.Current.MainWindow;
+ }
+ else
+ {
+ _redBoxDialog.Topmost = true;
+ _redBoxDialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+ }
+
+ _dismissRedBoxDialog = _redBoxDialog.Close;
+ _redBoxDialog.ShowDialog();
#endif
});
}
@@ -530,18 +562,19 @@ private async Task ReloadJavaScriptFromServerAsync(Action dismissProgress, Cance
}
}
#else
- var localStorage = FileSystem.Current.LocalStorage;
- var temporaryFolder = await localStorage.CreateFolderAsync("temp", CreationCollisionOption.GenerateUniqueName);
- var temporaryFile = await temporaryFolder.CreateFileAsync(JSBundleFileName, CreationCollisionOption.GenerateUniqueName);
+ var temporaryFilePath = Path.GetTempPath() + JSBundleFileName;
try
{
- using (var stream = new MemoryStream())
+ using (var stream = new FileStream(temporaryFilePath, FileMode.Create))
{
await _devServerHelper.DownloadBundleFromUrlAsync(_jsAppBundleName, stream, token);
- await temporaryFile.WriteAllTextAsync(stream.ToString());
}
- string newPath = PortablePath.Combine(localStorage.ToString(), JSBundleFileName);
- await temporaryFile.MoveAsync(newPath, NameCollisionOption.ReplaceExisting);
+
+ var temporaryFile = await FileSystem.Current.GetFileFromPathAsync(temporaryFilePath, token);
+ var localStorage = FileSystem.Current.LocalStorage;
+ string newPath = PortablePath.Combine(localStorage.Path, JSBundleFileName);
+
+ await temporaryFile.MoveAsync(newPath, NameCollisionOption.ReplaceExisting, token);
moved = true;
dismissProgress();
@@ -564,7 +597,12 @@ private async Task ReloadJavaScriptFromServerAsync(Action dismissProgress, Cance
{
if (!moved)
{
- await temporaryFile.DeleteAsync();
+ var temporaryFile = await FileSystem.Current.GetFileFromPathAsync(temporaryFilePath, token).ConfigureAwait(false);
+
+ if (temporaryFile != null)
+ {
+ await temporaryFile.DeleteAsync(token).ConfigureAwait(false);
+ }
}
}
#endif
diff --git a/ReactWindows/ReactNative.Shared/Modules/I18N/I18NUtil.cs b/ReactWindows/ReactNative.Shared/Modules/I18N/I18NUtil.cs
index 87e050abe8d..0def8cefdc2 100644
--- a/ReactWindows/ReactNative.Shared/Modules/I18N/I18NUtil.cs
+++ b/ReactWindows/ReactNative.Shared/Modules/I18N/I18NUtil.cs
@@ -2,8 +2,11 @@
using Windows.ApplicationModel.Resources.Core;
using Windows.Storage;
#else
+using System;
+using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
+using static System.FormattableString;
#endif
namespace ReactNative.Modules.I18N
@@ -16,6 +19,9 @@ static class I18NUtil
private const string AllowRTL = "RCTI18nUtil_allowRTL";
private const string ForceRTL = "RCTI18nUtil_forceRTL";
+#if !WINDOWS_UWP
+ private static IDictionary _localSettings = new Dictionary();
+#endif
///
/// Check if the system is using Right to Left. This only happens when the app:
@@ -40,9 +46,7 @@ public static bool IsRightToLeftAllowed
#if WINDOWS_UWP
return (bool?)ApplicationData.Current.LocalSettings.Values[AllowRTL] ?? false;
#else
- var result = default(bool);
- var parsed = bool.TryParse(ConfigurationManager.AppSettings[AllowRTL], out result);
- return (bool)(object)(parsed && result);
+ return GetSetting(AllowRTL, false);
#endif
}
set
@@ -50,7 +54,7 @@ public static bool IsRightToLeftAllowed
#if WINDOWS_UWP
ApplicationData.Current.LocalSettings.Values[AllowRTL] = value;
#else
- ConfigurationManager.AppSettings[AllowRTL] = value.ToString();
+ SetSetting(AllowRTL, value);
#endif
}
}
@@ -65,18 +69,12 @@ public static bool IsRightToLeftForced
#if WINDOWS_UWP
return (bool?)ApplicationData.Current.LocalSettings.Values[ForceRTL] ?? false;
#else
- var result = default(bool);
- var parsed = bool.TryParse(ConfigurationManager.AppSettings[ForceRTL], out result);
- return (bool)(object)(parsed && result);
+ return GetSetting(ForceRTL, false);
#endif
}
set
{
-#if WINDOWS_UWP
- ApplicationData.Current.LocalSettings.Values[ForceRTL] = value;
-#else
- ConfigurationManager.AppSettings[AllowRTL] = value.ToString();
-#endif
+ SetSetting(ForceRTL, value);
}
}
@@ -91,5 +89,49 @@ private static bool IsDeviceRightToLeft
#endif
}
}
+
+ //TODO: Git Issue #878
+ private static T GetSetting(string key, T defaultValue)
+ {
+#if WINDOWS_UWP
+ var values = ApplicationData.Current.LocalSettings.Values;
+ if (values.ContainsKey(key))
+ {
+ var data = values[key];
+ if (data is T)
+ {
+ return (T)data;
+ }
+ }
+
+ return defaultValue;
+#else
+ if (_localSettings.ContainsKey(key))
+ {
+ var data = _localSettings[key];
+
+ if (data is T)
+ {
+ return (T)data;
+ }
+ else
+ {
+ throw new NotSupportedException(Invariant($"Configuration values of type '{typeof(T)}' are not supported."));
+ }
+ }
+
+ return defaultValue;
+#endif
+ }
+
+ private static void SetSetting(string key, T value)
+ {
+#if WINDOWS_UWP
+ var values = ApplicationData.Current.LocalSettings.Values;
+ values[key] = value;
+#else
+ _localSettings[key] = value;
+#endif
+ }
}
}
diff --git a/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj b/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj
index 623b3d4f17d..e01dc6130fb 100644
--- a/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj
+++ b/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj
@@ -123,7 +123,6 @@
-
diff --git a/ReactWindows/ReactNative.sln b/ReactWindows/ReactNative.sln
index 72511cd71b9..37c001c5a88 100644
--- a/ReactWindows/ReactNative.sln
+++ b/ReactWindows/ReactNative.sln
@@ -23,6 +23,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactNative.Net46.Tests", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChakraCore", "ChakraCore\ChakraCore.vcxproj", "{E02ED054-4FB2-4EEB-8835-36A5E542E368}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Playground.Net46", "Playground.Net46\Playground.Net46.csproj", "{7AB3A24A-D5D9-479F-8E12-22213DD40D3F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E02ED054-4FB2-4EEB-8835-36A5E542E368} = {E02ED054-4FB2-4EEB-8835-36A5E542E368}
+ EndProjectSection
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
ReactNative.Shared\ReactNative.Shared.projitems*{22cbff9c-fe36-43e8-a246-266c7635e662}*SharedItemsImports = 4
@@ -227,6 +232,29 @@ Global
{E02ED054-4FB2-4EEB-8835-36A5E542E368}.ReleaseBundle|x64.Build.0 = Release|x64
{E02ED054-4FB2-4EEB-8835-36A5E542E368}.ReleaseBundle|x86.ActiveCfg = Release|Win32
{E02ED054-4FB2-4EEB-8835-36A5E542E368}.ReleaseBundle|x86.Build.0 = Release|Win32
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Debug|ARM.ActiveCfg = Debug|ARM
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Debug|x64.ActiveCfg = Debug|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Debug|x64.Build.0 = Debug|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Debug|x86.ActiveCfg = Debug|x86
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Debug|x86.Build.0 = Debug|x86
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.DebugBundle|ARM.ActiveCfg = Debug|ARM
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.DebugBundle|ARM.Build.0 = Debug|ARM
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.DebugBundle|x64.ActiveCfg = Debug|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.DebugBundle|x64.Build.0 = Debug|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.DebugBundle|x86.ActiveCfg = Debug|x86
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.DebugBundle|x86.Build.0 = Debug|x86
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Release|ARM.ActiveCfg = Release|ARM
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Release|ARM.Build.0 = Release|ARM
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Release|x64.ActiveCfg = Release|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Release|x64.Build.0 = Release|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Release|x86.ActiveCfg = Release|x86
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.Release|x86.Build.0 = Release|x86
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.ReleaseBundle|ARM.ActiveCfg = Release|ARM
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.ReleaseBundle|ARM.Build.0 = Release|ARM
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.ReleaseBundle|x64.ActiveCfg = Release|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.ReleaseBundle|x64.Build.0 = Release|x64
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.ReleaseBundle|x86.ActiveCfg = Release|x86
+ {7AB3A24A-D5D9-479F-8E12-22213DD40D3F}.ReleaseBundle|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE