diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index f3158a85bb..11e3a1074c 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -348,6 +348,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeploymentAgent", "dev\Depl {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppNotificationBuilder", "dev\AppNotifications\AppNotificationBuilder\AppNotificationBuilder.vcxitems", "{E49329F3-5196-4BBA-B5C4-E11CE7EFB07A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppNotificationBuilderTests", "test\AppNotificationBuilderTests\AppNotificationBuilderTests.vcxproj", "{131DE0C4-AA1E-4649-B5BC-7B43508FA93A}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.Security.AccessControl.Projection", "dev\Projections\CS\Microsoft.Windows.Security.AccessControl.Projection\Microsoft.Windows.Security.AccessControl.Projection.csproj", "{E6D59245-696F-4D13-ACF6-7ECE6E653367}" EndProject Global @@ -381,6 +385,7 @@ Global dev\Deployment\Deployment.vcxitems*{db38fb4d-d04f-4c1d-93e0-f8ae259c5fd6}*SharedItemsImports = 9 dev\EnvironmentManager\ChangeTracker\ChangeTracker.vcxitems*{e15c3465-9d45-495d-92ce-b91ef45e8623}*SharedItemsImports = 9 dev\AppLifecycle\AppLifecycle.vcxitems*{e3a522a3-6635-4a42-bded-1af46a15f63c}*SharedItemsImports = 9 + dev\AppNotifications\AppNotificationBuilder\AppNotificationBuilder.vcxitems*{e49329f3-5196-4bba-b5c4-e11ce7efb07a}*SharedItemsImports = 9 test\inc\inc.vcxitems*{e5659a29-fe68-417b-9bc5-613073dd54df}*SharedItemsImports = 4 test\inc\inc.vcxitems*{e977b1bd-00dc-4085-a105-e0a18e0183d7}*SharedItemsImports = 4 EndGlobalSection @@ -1357,6 +1362,20 @@ Global {4410D374-A90C-4ADF-8B15-AA2AAE2636BF}.Release|x64.Build.0 = Release|x64 {4410D374-A90C-4ADF-8B15-AA2AAE2636BF}.Release|x86.ActiveCfg = Release|x86 {4410D374-A90C-4ADF-8B15-AA2AAE2636BF}.Release|x86.Build.0 = Release|x86 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Debug|ARM64.Build.0 = Debug|ARM64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Debug|x64.ActiveCfg = Debug|x64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Debug|x64.Build.0 = Debug|x64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Debug|x86.ActiveCfg = Debug|Win32 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Debug|x86.Build.0 = Debug|Win32 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Release|Any CPU.ActiveCfg = Release|Win32 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Release|ARM64.ActiveCfg = Release|ARM64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Release|ARM64.Build.0 = Release|ARM64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Release|x64.ActiveCfg = Release|x64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Release|x64.Build.0 = Release|x64 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Release|x86.ActiveCfg = Release|Win32 + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A}.Release|x86.Build.0 = Release|Win32 {E6D59245-696F-4D13-ACF6-7ECE6E653367}.Debug|Any CPU.ActiveCfg = Debug|x86 {E6D59245-696F-4D13-ACF6-7ECE6E653367}.Debug|ARM64.ActiveCfg = Debug|arm64 {E6D59245-696F-4D13-ACF6-7ECE6E653367}.Debug|ARM64.Build.0 = Debug|arm64 @@ -1485,6 +1504,8 @@ Global {D9139E3C-8D21-4BD9-84E3-30A03A54D610} = {99C514E4-A6B3-4B09-B870-5511EF9D93AC} {4A74BBED-3B20-44A7-B6FF-3373160DE741} = {99C514E4-A6B3-4B09-B870-5511EF9D93AC} {4410D374-A90C-4ADF-8B15-AA2AAE2636BF} = {E378857C-D22A-4E5E-A6DA-A59C445CF22E} + {E49329F3-5196-4BBA-B5C4-E11CE7EFB07A} = {1C9A0791-2BAA-420B-84B6-C0721F22A6E8} + {131DE0C4-AA1E-4649-B5BC-7B43508FA93A} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {E6D59245-696F-4D13-ACF6-7ECE6E653367} = {716C26A0-E6B0-4981-8412-D14A4D410531} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/dev/AppNotifications/AppNotificationActivatedEventArgs.cpp b/dev/AppNotifications/AppNotificationActivatedEventArgs.cpp new file mode 100644 index 0000000000..8bceba0006 --- /dev/null +++ b/dev/AppNotifications/AppNotificationActivatedEventArgs.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include "pch.h" +#include "AppNotificationActivatedEventArgs.h" +#include "Microsoft.Windows.AppNotifications.AppNotificationActivatedEventArgs.g.cpp" +#include "AppNotificationBuilder/AppNotificationBuilderUtility.h" + +namespace winrt::Microsoft::Windows::AppNotifications::implementation +{ + winrt::Windows::Foundation::Collections::IMap AppNotificationActivatedEventArgs::DecodeArguments(std::wstring arguments) + { + auto result{ winrt::single_threaded_map() }; + + std::vector pairs{}; + size_t pos{ 0 }; + + // Separate the key/value pairs by ';' as the delimiter + while ((pos = arguments.find(L';')) != std::wstring::npos) + { + pairs.push_back(arguments.substr(0, pos)); + arguments.erase(0, pos + 1); + } + + // Need to push back final string + pairs.push_back(arguments); + + for (auto pair : pairs) + { + // Get the key/value individual values separated by '=' + pos = pair.find(L'='); + if (pos == std::wstring::npos) + { + result.Insert(Decode(pair).c_str(), L""); + } + else + { + result.Insert(Decode(pair.substr(0, pos)).c_str(), Decode(pair.substr(pos + 1)).c_str()); + } + } + return result; + } +} diff --git a/dev/AppNotifications/AppNotificationActivatedEventArgs.h b/dev/AppNotifications/AppNotificationActivatedEventArgs.h index fe109d3709..7c9d400d01 100644 --- a/dev/AppNotifications/AppNotificationActivatedEventArgs.h +++ b/dev/AppNotifications/AppNotificationActivatedEventArgs.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. #pragma once @@ -10,12 +10,17 @@ namespace winrt::Microsoft::Windows::AppNotifications::implementation { AppNotificationActivatedEventArgs() = default; - AppNotificationActivatedEventArgs(winrt::hstring const& arguments, winrt::Windows::Foundation::Collections::IMap const& userInput) : m_arguments(arguments), m_userInput(userInput) {}; - winrt::hstring Argument() { return m_arguments; }; + AppNotificationActivatedEventArgs(winrt::hstring const& argument, winrt::Windows::Foundation::Collections::IMap const& userInput) + : m_argument(argument), m_userInput(userInput), m_arguments(DecodeArguments(argument.c_str())) {}; + winrt::hstring Argument() { return m_argument; }; winrt::Windows::Foundation::Collections::IMap UserInput() { return m_userInput; }; + winrt::Windows::Foundation::Collections::IMap Arguments() { return m_arguments; }; private: - winrt::hstring m_arguments; + winrt::Windows::Foundation::Collections::IMap DecodeArguments(std::wstring arguments); + + winrt::hstring m_argument; winrt::Windows::Foundation::Collections::IMap m_userInput; + winrt::Windows::Foundation::Collections::IMap m_arguments{ nullptr }; }; } diff --git a/dev/AppNotifications/AppNotificationBuilder/AppNotificationBuilder.cpp b/dev/AppNotifications/AppNotificationBuilder/AppNotificationBuilder.cpp new file mode 100644 index 0000000000..46d2510564 --- /dev/null +++ b/dev/AppNotifications/AppNotificationBuilder/AppNotificationBuilder.cpp @@ -0,0 +1,398 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include "pch.h" +#include "AppNotificationBuilder.h" +#include +#include +#include "Microsoft.Windows.AppNotifications.Builder.AppNotificationBuilder.g.cpp" +#include "AppNotificationBuilderUtility.h" +#include +#include +#include +#include + +using namespace winrt::Windows::Globalization; +using namespace winrt::Windows::Globalization::DateTimeFormatting; + +namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation +{ + void AppNotificationBuilder::ThrowIfMaxInputItemsExceeded() + { + THROW_HR_IF_MSG(E_INVALIDARG, m_textBoxList.size() + m_comboBoxList.size() >= c_maxTextInputElements, "Maximum number of input elements added"); + } + + bool AppNotificationBuilder::IsUrgentScenarioSupported() + { + return WindowsVersion::IsWindows10_20H1OrGreater(); + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddArgument(hstring const& key, hstring const& value) + { + THROW_HR_IF_MSG(E_INVALIDARG, key.empty(), "You must provide a key when adding an argument"); + + m_arguments.Insert(EncodeArgument(key.c_str()), EncodeArgument(value.c_str())); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetTimeStamp(winrt::Windows::Foundation::DateTime const& value) + { + auto seconds{ winrt::clock::to_time_t(value) }; + struct tm buf{}; + gmtime_s(&buf, &seconds); + + std::wstringstream buffer; + buffer << std::put_time(&buf, L"%FT%T"); + + m_timeStamp = wil::str_printf(L" displayTimestamp='%lsZ'", buffer.str().c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetScenario(AppNotificationScenario const& value) + { + m_scenario = value; + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetDuration(AppNotificationDuration const& value) + { + m_duration = value; + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddText(hstring const& text) + { + THROW_HR_IF_MSG(E_INVALIDARG, m_textLines.size() >= c_maxTextElements, "Maximum number of text elements added"); + + m_textLines.push_back(wil::str_printf(L"%ls", EncodeXml(text).c_str()).c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddText(hstring const& text, AppNotificationTextProperties const& properties) + { + THROW_HR_IF_MSG(E_INVALIDARG, m_textLines.size() >= c_maxTextElements, "Maximum number of text elements added"); + + std::wstring props{ properties.as().ToString() }; + m_textLines.push_back(wil::str_printf(L"%ls%ls", props.c_str(), EncodeXml(text).c_str()).c_str()); + + if (properties.IncomingCallAlignment()) + { + m_scenario = AppNotificationScenario::IncomingCall; + } + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetAttributionText(hstring const& text) + { + m_attributionText = wil::str_printf(L"%ls", EncodeXml(text).c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetAttributionText(hstring const& text, hstring const& language) + { + THROW_HR_IF_MSG(E_INVALIDARG, language.empty(), "You must provide a language calling SetAttributionText"); + + m_attributionText = wil::str_printf(L"%ls", language.c_str(), EncodeXml(text).c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetInlineImage(winrt::Windows::Foundation::Uri const& imageUri) + { + m_inlineImage = wil::str_printf(L"", imageUri.ToString().c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetInlineImage(winrt::Windows::Foundation::Uri const& imageUri, AppNotificationImageCrop const& imageCrop) + { + if (imageCrop == AppNotificationImageCrop::Circle) + { + m_inlineImage = wil::str_printf(L"", imageUri.ToString().c_str()); + } + else + { + SetInlineImage(imageUri); + } + + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetInlineImage(winrt::Windows::Foundation::Uri const& imageUri, AppNotificationImageCrop const& imageCrop, hstring const& alternateText) + { + THROW_HR_IF_MSG(E_INVALIDARG, alternateText.empty(), "You must provide an alternate text string calling SetInlineImage"); + + std::wstring hintCrop { imageCrop == AppNotificationImageCrop::Circle ? L" hint-crop='circle'" : L"" }; + m_inlineImage = wil::str_printf(L"%ls", imageUri.ToString().c_str(), EncodeXml(alternateText).c_str(), hintCrop.c_str()); + + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetAppLogoOverride(winrt::Windows::Foundation::Uri const& imageUri) + { + m_appLogoOverride = wil::str_printf(L"", imageUri.ToString().c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetAppLogoOverride(winrt::Windows::Foundation::Uri const& imageUri, AppNotificationImageCrop const& imageCrop) + { + if (imageCrop == AppNotificationImageCrop::Circle) + { + m_appLogoOverride = wil::str_printf(L"", imageUri.ToString().c_str()); + } + else + { + SetAppLogoOverride(imageUri); + } + + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetAppLogoOverride(winrt::Windows::Foundation::Uri const& imageUri, AppNotificationImageCrop const& imageCrop, hstring const& alternateText) + { + THROW_HR_IF_MSG(E_INVALIDARG, alternateText.empty(), "You must provide an alternate text string calling SetAppLogoOverride"); + + std::wstring hintCrop{ imageCrop == AppNotificationImageCrop::Circle ? L" hint-crop='circle'" : L"" }; + m_appLogoOverride = wil::str_printf(L"%ls", imageUri.ToString().c_str(), EncodeXml(alternateText).c_str(), hintCrop.c_str()); + + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetHeroImage(winrt::Windows::Foundation::Uri const& imageUri) + { + m_heroImage = wil::str_printf(L"", imageUri.ToString().c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetHeroImage(winrt::Windows::Foundation::Uri const& imageUri, hstring const& alternateText) + { + THROW_HR_IF_MSG(E_INVALIDARG, alternateText.empty(), "You must provide an alternate text string calling SetHeroImage"); + + m_heroImage = wil::str_printf(L"%ls", imageUri.ToString().c_str(), EncodeXml(alternateText).c_str()); + return *this; + } + + winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetAudioUri(winrt::Windows::Foundation::Uri const& audioUri) + { + m_audio = wil::str_printf(L"