From 1ebfc895276304221f50876ad03f20e3aeb2e128 Mon Sep 17 00:00:00 2001 From: Shawn Cicoria Date: Tue, 5 Jan 2016 09:31:50 -0500 Subject: [PATCH] adding ToastModule with tests --- .../Modules/Toast/ToastNotificationTests.cs | 62 +++++++++++++++++++ .../ReactNative.Tests.csproj | 1 + .../ReactNative/Modules/Toast/ToastHelper.cs | 60 ++++++++++++++++++ .../ReactNative/Modules/Toast/ToastModule.cs | 52 ++++++++++++++++ ReactWindows/ReactNative/ReactNative.csproj | 2 + 5 files changed, 177 insertions(+) create mode 100644 ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs create mode 100644 ReactWindows/ReactNative/Modules/Toast/ToastHelper.cs create mode 100644 ReactWindows/ReactNative/Modules/Toast/ToastModule.cs diff --git a/ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs b/ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs new file mode 100644 index 00000000000..1e3bc6125da --- /dev/null +++ b/ReactWindows/ReactNative.Tests/Modules/Toast/ToastNotificationTests.cs @@ -0,0 +1,62 @@ +using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; +using ReactNative.Bridge; +using ReactNative.Modules.Toast; +using System; + +namespace ReactNative.Tests.Modules.Toast +{ + [TestClass] + public class ToastNotificationTests + { + const string TEST_CATEGORY = "Modules"; + + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void ToastModule_Null_ArgumentsTest() + { + AssertEx.Throws( + () => new ToastModule(null), + ex => Assert.AreEqual("reactContext", ex.ParamName)); + + + var context = new ReactApplicationContext(); + var module = new ToastModule(context); + Assert.AreSame(context, module.Context); + + } + + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void Send_Toast_Invalid_Duration() + { + var context = new ReactApplicationContext(); + var module = new ToastModule(context); + + AssertEx.Throws( + () => module.show("Invalid Toast", -1), + ex => Assert.AreEqual("duration", ex.ParamName)); + } + + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void Send_Basic_Toast() + { + var context = new ReactApplicationContext(); + var module = new ToastModule(context); + + module.show("SHORT TOAST", 0); + } + + [TestMethod] + [TestCategory(TEST_CATEGORY)] + public void Send_Long_Toast() + { + var context = new ReactApplicationContext(); + var module = new ToastModule(context); + + module.show("LONG TOAST container", 1); + } + + + } +} diff --git a/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj b/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj index 050eaf91469..fa259b55c9e 100644 --- a/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj +++ b/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj @@ -118,6 +118,7 @@ + diff --git a/ReactWindows/ReactNative/Modules/Toast/ToastHelper.cs b/ReactWindows/ReactNative/Modules/Toast/ToastHelper.cs new file mode 100644 index 00000000000..2c35d64bbf5 --- /dev/null +++ b/ReactWindows/ReactNative/Modules/Toast/ToastHelper.cs @@ -0,0 +1,60 @@ +using System.IO; +using System.Threading.Tasks; +using Windows.Data.Xml.Dom; +using Windows.UI.Notifications; + +namespace ReactNative.Modules.Toast +{ + class ToastHelper + { + internal static void SendToast(string message, string duration = "short") + { + var doc = MakeDoc(message).Result; + var notification = new ToastNotification(doc); + + // Get the toast notification manager for the current app. + ToastNotificationManager.CreateToastNotifier().Show(notification); + } + + static async Task MakeDoc(string content, Durations duration = Durations.@short) + { + /// TODO: alt templates: https://msdn.microsoft.com/en-us/library/windows/apps/hh761494.aspx + using (var stream = new MemoryStream()) + using (var reader = new StreamReader(stream)) + { + await BuildNotificationXml(stream, content, duration); + stream.Position = 0; + var xml = await reader.ReadToEndAsync(); + var doc = new XmlDocument(); + doc.LoadXml(xml); + return doc; + } + } + + static async Task BuildNotificationXml(Stream stream, string content, Durations duration = Durations.@short) + { + System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings(); + settings.OmitXmlDeclaration = true; + settings.Async = true; + + using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(stream, settings)) + { + await writer.WriteStartElementAsync(null, "toast", null); + await writer.WriteAttributeStringAsync(null, "activationType", null, "foreground"); + await writer.WriteAttributeStringAsync(null, "duration", null, duration.ToString()); + + await writer.WriteStartElementAsync(null, "visual", null); + await writer.WriteStartElementAsync(null, "binding", null); + await writer.WriteAttributeStringAsync(null, "template", null, "ToastText01"); + + await writer.WriteStartElementAsync(null, "text", null); + await writer.WriteAttributeStringAsync(null, "id", null, "1"); + await writer.WriteStringAsync(content); + await writer.WriteEndElementAsync(); + + await writer.WriteEndElementAsync(); + await writer.FlushAsync(); + } + } + } +} diff --git a/ReactWindows/ReactNative/Modules/Toast/ToastModule.cs b/ReactWindows/ReactNative/Modules/Toast/ToastModule.cs new file mode 100644 index 00000000000..0b962575936 --- /dev/null +++ b/ReactWindows/ReactNative/Modules/Toast/ToastModule.cs @@ -0,0 +1,52 @@ +using ReactNative.Bridge; +using System; +using System.Collections.Generic; + +namespace ReactNative.Modules.Toast +{ + enum Durations : int { @short, @long } + + public sealed class ToastModule : ReactContextNativeModuleBase + { + const string DURATION_SHORT_KEY = "SHORT"; + const string DURATION_LONG_KEY = "LONG"; + + public ToastModule(ReactApplicationContext reactContext) + : base(reactContext) + { } + + public override string Name + { + get + { + return "ToastModule"; + } + } + + public override IReadOnlyDictionary Constants + { + get + { + return new Dictionary + { + { DURATION_SHORT_KEY, DURATION_SHORT_KEY }, + { DURATION_LONG_KEY, DURATION_LONG_KEY }, + }; + } + } + + [ReactMethod] + public void show(string message, int duration) + { + if (Enum.IsDefined(typeof(Durations), duration)) + { + var durationToUse = (Durations)duration; + ToastHelper.SendToast(message, durationToUse.ToString()); + } + else + { + throw new ArgumentException("invalid duration for Toast", "duration"); + } + } + } +} diff --git a/ReactWindows/ReactNative/ReactNative.csproj b/ReactWindows/ReactNative/ReactNative.csproj index aaf733d21e8..65bc908bb29 100644 --- a/ReactWindows/ReactNative/ReactNative.csproj +++ b/ReactWindows/ReactNative/ReactNative.csproj @@ -159,6 +159,8 @@ + +