Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AppNotificationBuilder - ProgressBar #2780

Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
7119200
First iteration
pmpurifoy Jun 20, 2022
4765ea2
Fix formatting issues
pmpurifoy Jun 20, 2022
30a4376
Remove all references to toast
pmpurifoy Jun 20, 2022
40bd764
Add ProgressBar
pmpurifoy Jun 21, 2022
8668d3a
Remove getters and other nits
pmpurifoy Jun 21, 2022
1545006
Add XML outputs for all examples
pmpurifoy Jun 21, 2022
e470027
Update examples and fix missing png
pmpurifoy Jun 21, 2022
422eae8
Add limitations
pmpurifoy Jun 22, 2022
f55aad3
Add ArgumentSerializer and rename APIs
pmpurifoy Jun 24, 2022
aa7ed04
Fix some nits
pmpurifoy Jun 28, 2022
e0b2847
Fix audio ctors
pmpurifoy Jun 28, 2022
15b477c
Add Deserializer functions and example
pmpurifoy Jun 28, 2022
903956a
Apply review changes
pmpurifoy Jun 29, 2022
bbe8a26
Update AppNotificationBuilder-spec.md
pmpurifoy Jun 29, 2022
f5a745f
Initial commit
pmpurifoy Jun 29, 2022
435a152
Working on it
pmpurifoy Jun 30, 2022
238684d
Add AppNotificationContent
pmpurifoy Jun 30, 2022
5423935
Current impl
pmpurifoy Jul 7, 2022
d427450
Working on unit tests
pmpurifoy Jul 13, 2022
5dc491a
Added unit tests
pmpurifoy Jul 14, 2022
2b24c69
Add Audio tests
pmpurifoy Jul 15, 2022
33a4b1b
Update APITests.cpp
pmpurifoy Jul 15, 2022
5bd1f9e
Remove spec from PR
pmpurifoy Jul 15, 2022
51fabe4
Merge branch 'user/purifoypaul/BuilderCoreFeatures' into user/erlangl…
Jul 25, 2022
41a699e
Rename AppNotification Builder API to match specs (#2766)
loneursid Jul 25, 2022
97226a5
Initial implementation
Jul 25, 2022
a1634f8
Merge branch 'user/purifoypaul/BuilderCoreFeatures' into user/erlangl…
Jul 26, 2022
51a3312
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/use…
loneursid Jul 26, 2022
5ea7ddd
Update the spec with BuildNotification
pmpurifoy Jul 26, 2022
ab89042
Merge branch 'user/purifoypaul/BuilderCoreFeatures' into user/erlangl…
Jul 26, 2022
019077a
Remove unused files
pmpurifoy Jul 26, 2022
f8b850e
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 26, 2022
6b28335
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/use…
Jul 26, 2022
f45fb7a
Add copyright to all files
pmpurifoy Jul 27, 2022
f81258e
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/purifoypaul…
loneursid Jul 28, 2022
8851cae
Update AppNotificationBuilder.idl
loneursid Jul 28, 2022
224877f
Update pch.cpp
loneursid Jul 28, 2022
861014d
Update WindowsAppRuntime_DLL.vcxproj
loneursid Jul 28, 2022
a934566
Update packages.config
loneursid Jul 28, 2022
19d0cd4
Update AppNotificationBuilder.cpp
loneursid Jul 28, 2022
ab271d6
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 28, 2022
24e7669
Fixing build break
Jul 28, 2022
9c6bb22
Addressing comments
pmpurifoy Jul 29, 2022
8f51b89
Update error codes with messages
pmpurifoy Jul 29, 2022
f8ed6ca
Add helper file
pmpurifoy Jul 29, 2022
49c02bb
Add SetTimestamp impl
pmpurifoy Jul 29, 2022
3b3b08c
Add AppNotificationAudioLooping
pmpurifoy Jul 29, 2022
a2212e2
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 29, 2022
14a6e6c
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 29, 2022
604a24f
Add IsSupported to attributes
pmpurifoy Jul 29, 2022
b2fafbf
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 29, 2022
f58cd45
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/use…
Jul 29, 2022
cccfba6
Don't mix binding and value states
Jul 31, 2022
057071a
Code cleanup
Jul 31, 2022
b56536a
Using printf as it is the norm for the builder
Aug 1, 2022
5d5a50f
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/use…
Aug 2, 2022
29c561a
look proper
Aug 3, 2022
7be9f9c
spacing
Aug 3, 2022
232632e
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/use…
Aug 3, 2022
e2f9e57
Reorder functions in idl to help github track changes properly
Aug 3, 2022
13fea1b
Keeping all progressBar tests together
Aug 3, 2022
703c0a9
PR feedback
Aug 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,13 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddProgressBar(AppNotificationProgressBar const& value)
{
m_progressBarList.push_back(value);

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddTextBox(hstring id)
{
ThrowIfMaxInputItemsExceeded();
Expand Down Expand Up @@ -347,6 +354,17 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
return m_useButtonStyle ? L" useButtonStyle='true'" : L"";
}

std::wstring AppNotificationBuilder::GetProgressBars()
{
std::wstring result{};
for (auto progressBar : m_progressBarList)
{
result.append(progressBar.as<winrt::Windows::Foundation::IStringable>().ToString());
loneursid marked this conversation as resolved.
Show resolved Hide resolved
}

return result;
}

winrt::Microsoft::Windows::AppNotifications::AppNotification AppNotificationBuilder::BuildNotification()
{
std::wstring xmlResult{};
Expand All @@ -365,6 +383,7 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
xmlResult.append(GetText());
xmlResult.append(m_attributionText);
xmlResult.append(GetImages());
xmlResult.append(GetProgressBars());
loneursid marked this conversation as resolved.
Show resolved Hide resolved
xmlResult.append(L"</binding></visual>");
xmlResult.append(m_audio.c_str());
xmlResult.append(actions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
// Adds a button to the AppNotificationBuilder
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AddButton(AppNotificationButton const& value);

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AddProgressBar(AppNotificationProgressBar const& value);

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AddComboBox(AppNotificationComboBox const& value);

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder SetTag(winrt::hstring const& value);
Expand All @@ -72,6 +74,7 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
std::wstring GetText();
std::wstring GetImages();
std::wstring GetActions();
std::wstring GetProgressBars();

std::wstring m_timeStamp{};
AppNotificationDuration m_duration{ AppNotificationDuration::Default };
Expand All @@ -85,6 +88,7 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
winrt::hstring m_audio{};
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> m_arguments{ winrt::single_threaded_map<winrt::hstring, winrt::hstring>() };
std::vector<AppNotificationButton> m_buttonList{};
std::vector<AppNotificationProgressBar> m_progressBarList{};
std::vector<std::wstring> m_textBoxList{};
std::vector<AppNotificationComboBox> m_comboBoxList{};
winrt::hstring m_tag{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Microsoft.Windows.AppNotifications.Builder
AppNotificationTextProperties SetLanguage(String value);
AppNotificationTextProperties SetIncomingCallAlignment();
AppNotificationTextProperties SetMaxLines(Int32 value);
}
};

enum AppNotificationButtonStyle
{
Expand Down Expand Up @@ -65,6 +65,33 @@ namespace Microsoft.Windows.AppNotifications.Builder
AppNotificationButton SetInvokeUri(Windows.Foundation.Uri protocolUri, String targetAppId);
};

runtimeclass AppNotificationProgressBar
{
// AppNotificationProgressBar binds to AppNotificationProgressData so the AppNotification will
// receive every update to the status and value. In the WinAppSDK, these binding
// values are static, so developers won't need to define these binding values
// themselves.
AppNotificationProgressBar();

// Setting these properties will remove the data binding with a static value
String Title;
String Status;
Double Value;
String ValueStringOverride;

AppNotificationProgressBar SetTitle(String value);
AppNotificationProgressBar BindTitle();

AppNotificationProgressBar SetStatus(String value);
AppNotificationProgressBar BindStatus();

AppNotificationProgressBar SetValue(Double value);
AppNotificationProgressBar BindValue();

AppNotificationProgressBar SetValueStringOverride(String value);
AppNotificationProgressBar BindValueStringOverride();
};

runtimeclass AppNotificationComboBox
{
AppNotificationComboBox(String id);
Expand Down Expand Up @@ -193,6 +220,8 @@ namespace Microsoft.Windows.AppNotifications.Builder

AppNotificationBuilder AddComboBox(AppNotificationComboBox value);

AppNotificationBuilder AddProgressBar(AppNotificationProgressBar value);

// Constructs a WindowsAppSDK AppNotification object with the XML payload
Microsoft.Windows.AppNotifications.AppNotification BuildNotification();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationBuilder.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationButton.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationProgressBar.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationComboBox.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationTextProperties.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationBuilder.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationBuilderUtility.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationButton.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationProgressBar.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationComboBox.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationTextProperties.h" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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 "AppNotificationProgressBar.h"
#include "Microsoft.Windows.AppNotifications.Builder.AppNotificationProgressBar.g.cpp"

namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
{
AppNotificationProgressBar::AppNotificationProgressBar()
:m_titleStatus{ BindMode::NotSet },
m_statusStatus{ BindMode::NotSet },
m_valueStatus{ BindMode::NotSet },
m_valueStringOverrideStatus{ BindMode::NotSet }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove the BindMode::Enum and the member *Status postfix member variables.

For all Bind* functions, we can set the member variable to the constant string. For all Set* functions, we can set the member variable to the passed in param.

The default ctor should set m_status/m_value to the bind values and leave the rest empty.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about value? how would you handle that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would convert m_status from double->winrt::hstring and set the value to {progressValue}.

Copy link
Contributor Author

@loneursid loneursid Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if the user sets the title property to "title", then calls TitleBind(), then retrive the Title property, he'd get {progreeTitle} but if he does the same for value, what would he get? The value before he called bind, 0.0, -1.0? we throw?

If we return the value that was set before calling bind, how do we document that the APIs behave so disparatly?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with throwing here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should we use as the binding default double for value? @hulumane

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The toolkit sets the default to 0: https://github.com/CommunityToolkit/WindowsCommunityToolkit/blob/b21dbe71f64e86ca9bb0ba6cfb4cb4d20e93765a/Microsoft.Toolkit.Uwp.Notifications/Adaptive/AdaptiveProgressBar.cs#L39

If we do it this way, we need to track if the value was manually set to 0 by the dev since it is valid value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewleader as well for input.

Copy link
Contributor

@andrewleader andrewleader Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I fully understand the specific problem trying to be addressed here, but I'll try to give some general info.

Note that toast progress bars MUST have a value to be valid (I just tested a toast XML without any value attribute and got a "New notification" notification).

I believe XAML progress bars have a default value of 0, hence why I decided to just make the default value 0 in the Toolkit, even though technically you could argue this is a "nullable" property (but if Value doesn't have a value, you have an invalid toast). I felt just defaulting to 0 is the most intuitive and what developers would "expect", similar to how a string value typically defaults to null, and a new XAML ProgressBar "just works" without setting a value (defaults to 0).

Why would we need to track if the value was manually set to 0 by the dev? Regardless of who sets it to 0, we write it as 0, yeah? Or is this related to returning a value depending on whether BindValue() vs SetValue() was called?

Copy link
Contributor Author

@loneursid loneursid Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewleader : As I understand the specs the value element in the xml can have a value between 0 and 1 or {progressValue}. That all fine and dandy but we have a property that expose the value as a double. That property can represent a value between 0 and 1 but cannot represent {progressValue}.

There are 2 options:
1- represent {progressValue} as -1. so the double property can have a value from 0 to 1 or -1.
2- Only use 0 to 1 for the property and maintain an internal flag to indicate whether the value from the property (0 to 1) or {progressValue} should be placed in the xml.

There is no consensus yet, but we need to make a call soon.

{};

void AppNotificationProgressBar::Title(winrt::hstring const& value)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No check for empty args here or anywhere else?

Copy link
Contributor Author

@loneursid loneursid Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there's a task to handle that in a hollistic manner later. At this point we only check for empty IDs and such but not for normal values. This is the strategy used for the entirety of the builder for preview1

m_title = value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need locks here and everywhere else?

Copy link
Contributor Author

@loneursid loneursid Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No locks anywhere. Howard confirmed that we should be locking anything in this class as it isn't intended to be used in a multi-threaded situation

m_titleStatus = BindMode::Value;
}

void AppNotificationProgressBar::Status(winrt::hstring const& value)
{
m_status = value;
m_statusStatus = BindMode::Value;
}

void AppNotificationProgressBar::Value(double value)
{
THROW_HR_IF_MSG(E_INVALIDARG, value < 0.0 || value > 1.0, "You must provide a value between 0.0 and 1.0");

m_value = value; m_valueStatus = BindMode::Value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 lines please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

of course...

}

void AppNotificationProgressBar::ValueStringOverride(winrt::hstring const& value)
{
m_valueStringOverride = value;
m_valueStringOverrideStatus = BindMode::Value;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::SetTitle(winrt::hstring const& value)
{
Title(value);

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::BindTitle()
{
m_titleStatus = BindMode::Bind;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we append *BindMode to all this m_ variables?
For example m_tileBindMode, m_statusBindMode

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::SetStatus(winrt::hstring const& value)
{
Status(value);

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::BindStatus()
{
m_statusStatus = BindMode::Bind;

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::SetValue(double value)
{
Value(value);

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::BindValue()
{
m_valueStatus = BindMode::Bind;

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::SetValueStringOverride(winrt::hstring const& value)
{
ValueStringOverride(value);

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar AppNotificationProgressBar::BindValueStringOverride()
{
m_valueStringOverrideStatus = BindMode::Bind;

return *this;
}

winrt::hstring AppNotificationProgressBar::ToString()
{
return wil::str_printf<std::wstring>(L"<progress%ls%ls%ls%ls/>",
m_titleStatus == BindMode::NotSet ? L"" : wil::str_printf<std::wstring>(L" title='%ls'", m_titleStatus == BindMode::Value ? m_title.c_str() : L"{progressTitle}").c_str(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little complicated to read. Can we break this up by assigning each string first and directly passing the arguments to printf rather than doing everything here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, we expect 4 strings here as an argument. So lets initialize the 4 strings and break it up before passing it to printf

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

wil::str_printf<std::wstring>(L" status='%ls'", m_statusStatus == BindMode::Value ? m_status.c_str() : L"{progressStatus}").c_str(),
wil::str_printf<std::wstring>(L" value='%ls'", m_valueStatus == BindMode::Value ? wil::str_printf<std::wstring>(L"%g", m_value).c_str() : L"{progressValue}").c_str(),
m_valueStringOverrideStatus == BindMode::NotSet ? L"" : wil::str_printf < std::wstring>(L" valueStringOverride='%ls'", m_valueStringOverrideStatus == BindMode::Value ? m_valueStringOverride.c_str() : L"{progressValueString}").c_str()).c_str();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

#pragma once
#include "Microsoft.Windows.AppNotifications.Builder.AppNotificationProgressBar.g.h"

namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
{

struct AppNotificationProgressBar : AppNotificationProgressBarT<AppNotificationProgressBar, winrt::Windows::Foundation::IStringable>
{
AppNotificationProgressBar();

// Properties
void Title(winrt::hstring const& value);
winrt::hstring Title() { return m_title; };

void Status(winrt::hstring const& value);
winrt::hstring Status() { return m_status; };

void Value(double value);
double Value() { return m_value; };

void ValueStringOverride(winrt::hstring const& value);
winrt::hstring ValueStringOverride() { return m_valueStringOverride; };

// Fluent setters
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar SetTitle(winrt::hstring const& value);
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar BindTitle();

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar SetStatus(winrt::hstring const& value);
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar BindStatus();

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar SetValue(double value);
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar BindValue();

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar SetValueStringOverride(winrt::hstring const& value);
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationProgressBar BindValueStringOverride();

// IStringable
winrt::hstring ToString();

private:
enum class BindMode {NotSet, Bind, Value};

BindMode m_titleStatus;
winrt::hstring m_title;
BindMode m_statusStatus;
winrt::hstring m_status;
BindMode m_valueStatus;
double m_value;
BindMode m_valueStringOverrideStatus;
winrt::hstring m_valueStringOverride;
};
}
namespace winrt::Microsoft::Windows::AppNotifications::Builder::factory_implementation
{
struct AppNotificationProgressBar : AppNotificationProgressBarT<AppNotificationProgressBar, implementation::AppNotificationProgressBar>
{
};
}
80 changes: 80 additions & 0 deletions test/AppNotificationBuilderTests/APITests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,86 @@ namespace Test::AppNotification::Builder
VERIFY_ARE_EQUAL(builder.BuildNotification().Payload(), expected);
}

TEST_METHOD(AppNotificationAddProgressBar)
{
auto builder{ AppNotificationBuilder()
.AddText(L"Downloading this week's new music...")
.AddProgressBar(AppNotificationProgressBar()
.BindTitle()
.BindValueStringOverride()) };
auto expected{ L"<toast><visual><binding template='ToastGeneric'><text>Downloading this week's new music...</text><progress title='{progressTitle}' status='{progressStatus}' value='{progressValue}' valueStringOverride='{progressValueString}'/></binding></visual></toast>" };

VERIFY_ARE_EQUAL(builder.BuildNotification().Payload(), expected);
}

TEST_METHOD(AppNotificationAddMoreThanOneProgressBar)
{
auto builder{ AppNotificationBuilder()
.AddText(L"Downloading this week's new music...")
.AddProgressBar(AppNotificationProgressBar()
.BindTitle()
.BindValueStringOverride())
.AddProgressBar(AppNotificationProgressBar()
.SetValue(0.8)
.SetStatus(L"Still downloading...")) };
auto expected{ L"<toast><visual><binding template='ToastGeneric'><text>Downloading this week's new music...</text><progress title='{progressTitle}' status='{progressStatus}' value='{progressValue}' valueStringOverride='{progressValueString}'/><progress status='Still downloading...' value='0.8'/></binding></visual></toast>" };

VERIFY_ARE_EQUAL(builder.BuildNotification().Payload(), expected);
}

TEST_METHOD(AppNotificationProgressBarDefaults)
{
auto progressBar{ AppNotificationProgressBar() };
auto expected{ L"<progress status='{progressStatus}' value='{progressValue}'/>" };

VERIFY_ARE_EQUAL(progressBar.as<winrt::Windows::Foundation::IStringable>().ToString(), expected);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised this works since the object doesn't inherit IStringable in the idl, but maybe . I like the idea of processing everything through BuildNotification instead of casting to IStringable to simulate what devs would actually be doing.

}

TEST_METHOD(AppNotificationProgressBarSetSpecificValue)
{
auto progressBar{ AppNotificationProgressBar() };
progressBar.Value(0.8);
auto expected{ L"<progress status='{progressStatus}' value='0.8'/>" };

VERIFY_ARE_EQUAL(progressBar.as<winrt::Windows::Foundation::IStringable>().ToString(), expected);
}

TEST_METHOD(AppNotificationProgressBarSetValueLargerThanOne)
{
auto progressBar{ AppNotificationProgressBar() };
VERIFY_THROWS_HR(progressBar.Value(1.01), E_INVALIDARG);

VERIFY_THROWS_HR(AppNotificationProgressBar().SetValue(1.01), E_INVALIDARG);
}

TEST_METHOD(AppNotificationProgressBarSetValueSmallerThanZero)
{
auto progressBar{ AppNotificationProgressBar() };
VERIFY_THROWS_HR(progressBar.Value(-0.1), E_INVALIDARG);

VERIFY_THROWS_HR(AppNotificationProgressBar().SetValue(-0.1), E_INVALIDARG);
}

TEST_METHOD(AppNotificationProgressBarSetSpecificValueThenChangeToBind)
{
auto progressBar{ AppNotificationProgressBar() };
progressBar.Value(0.8);
progressBar.BindValue();
auto expected{ L"<progress status='{progressStatus}' value='{progressValue}'/>" };

VERIFY_ARE_EQUAL(progressBar.as<winrt::Windows::Foundation::IStringable>().ToString(), expected);
}

TEST_METHOD(AppNotificationProgressBarBindTitleThenChangeToSpecificText)
{
auto progressBar{ AppNotificationProgressBar()
.BindTitle()
.SetTitle(L"Specific title") };
auto expected{ L"<progress title='Specific title' status='{progressStatus}' value='{progressValue}'/>" };

VERIFY_ARE_EQUAL(progressBar.as<winrt::Windows::Foundation::IStringable>().ToString(), expected);
}

TEST_METHOD(AppNotificationBuilderAddTextBox)
{
auto builder{ AppNotificationBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
<ActivatableClass ActivatableClassId="Microsoft.Windows.AppNotifications.Builder.AppNotificationBuilder" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Windows.AppNotifications.Builder.AppNotificationTextProperties" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Windows.AppNotifications.Builder.AppNotificationButton" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Windows.AppNotifications.Builder.AppNotificationProgressBar" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Windows.AppNotifications.Builder.AppNotificationComboBox" ThreadingModel="both" />
</InProcessServer>
</Extension>
Expand Down