Skip to content

Commit

Permalink
Update InfoBar narrator behavior (#4578)
Browse files Browse the repository at this point in the history
* Update infobar strings to be more descriptive and dependent on severity level

* Add icon and announcer severity information

* Fix bug, update wording

* Update wording

* CR feedback

* Update UIA name for icon

* Fix up indices

Co-authored-by: Tammy Paine <[email protected]>
  • Loading branch information
marcelwgn and teaP authored Apr 22, 2021
1 parent 5da0036 commit 1f7779d
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 20 deletions.
48 changes: 44 additions & 4 deletions dev/InfoBar/InfoBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "../ResourceHelper/Utils.h"

static constexpr wstring_view c_closeButtonName{ L"CloseButton"sv };
static constexpr wstring_view c_iconTextBlockName{ L"StandardIcon"sv };
static constexpr wstring_view c_contentRootName{ L"ContentRoot"sv };

InfoBar::InfoBar()
Expand Down Expand Up @@ -47,14 +48,19 @@ void InfoBar::OnApplyTemplate()
const auto closeButtonName = ResourceAccessor::GetLocalizedStringResource(SR_InfoBarCloseButtonName);
winrt::AutomationProperties::SetName(closeButton, closeButtonName);
}

// Setup the tooltip for the close button
auto tooltip = winrt::ToolTip();
const auto closeButtonTooltipText = ResourceAccessor::GetLocalizedStringResource(SR_InfoBarCloseButtonTooltip);
tooltip.Content(box_value(closeButtonTooltipText));
winrt::ToolTipService::SetToolTip(closeButton, tooltip);
}

if (const auto iconTextblock = GetTemplateChildT<winrt::FrameworkElement>(c_iconTextBlockName, controlProtected))
{
m_standardIconTextBlock.set(iconTextblock);
winrt::AutomationProperties::SetName(iconTextblock, ResourceAccessor::GetLocalizedStringResource(GetIconSeverityLevelResourceName(Severity())));
}

if (auto&& contentRootGrid = GetTemplateChildT<winrt::Button>(c_contentRootName, controlProtected))
{
winrt::AutomationProperties::SetLocalizedLandmarkType(contentRootGrid, ResourceAccessor::GetLocalizedStringResource(SR_InfoBarCustomLandmarkName));
Expand Down Expand Up @@ -160,6 +166,7 @@ void InfoBar::UpdateVisibility(bool notify, bool force)
{
auto const notificationString = StringUtil::FormatString(
ResourceAccessor::GetLocalizedStringResource(SR_InfoBarOpenedNotification),
ResourceAccessor::GetLocalizedStringResource(GetIconSeverityLevelResourceName(Severity())).data(),
Title().data(),
Message().data());

Expand Down Expand Up @@ -193,11 +200,22 @@ void InfoBar::UpdateSeverity()

switch (Severity())
{
case winrt::InfoBarSeverity::Success: severityState = L"Success"; break;
case winrt::InfoBarSeverity::Warning: severityState = L"Warning"; break;
case winrt::InfoBarSeverity::Error: severityState = L"Error"; break;
case winrt::InfoBarSeverity::Success:
severityState = L"Success";
break;
case winrt::InfoBarSeverity::Warning:
severityState = L"Warning";
break;
case winrt::InfoBarSeverity::Error:
severityState = L"Error";
break;
};

if (const auto iconTextblock = m_standardIconTextBlock.get())
{
winrt::AutomationProperties::SetName(iconTextblock, ResourceAccessor::GetLocalizedStringResource(GetIconSeverityLevelResourceName(Severity())));
}

winrt::VisualStateManager::GoToState(*this, severityState, false);
}

Expand Down Expand Up @@ -234,3 +252,25 @@ void InfoBar::UpdateForeground()
// If Foreground is set, then change Title and Message Foreground to match.
winrt::VisualStateManager::GoToState(*this, ReadLocalValue(winrt::Control::ForegroundProperty()) == winrt::DependencyProperty::UnsetValue() ? L"ForegroundNotSet" : L"ForegroundSet", false);
}

const winrt::hstring InfoBar::GetSeverityLevelResourceName(winrt::InfoBarSeverity severity)
{
switch (severity)
{
case winrt::InfoBarSeverity::Success: return SR_InfoBarSeveritySuccessName;
case winrt::InfoBarSeverity::Warning: return SR_InfoBarSeverityWarningName;
case winrt::InfoBarSeverity::Error: return SR_InfoBarSeverityErrorName;
};
return SR_InfoBarSeverityInformationalName;
}

const winrt::hstring InfoBar::GetIconSeverityLevelResourceName(winrt::InfoBarSeverity severity)
{
switch (severity)
{
case winrt::InfoBarSeverity::Success: return SR_InfoBarIconSeveritySuccessName;
case winrt::InfoBarSeverity::Warning: return SR_InfoBarIconSeverityWarningName;
case winrt::InfoBarSeverity::Error: return SR_InfoBarIconSeverityErrorName;
};
return SR_InfoBarIconSeverityInformationalName;
}
5 changes: 5 additions & 0 deletions dev/InfoBar/InfoBar.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,16 @@ class InfoBar :
void UpdateCloseButton();
void UpdateForeground();

const winrt::hstring GetCloseButtonResourceName(winrt::InfoBarSeverity severity);
const winrt::hstring GetSeverityLevelResourceName(winrt::InfoBarSeverity severity);
const winrt::hstring GetIconSeverityLevelResourceName(winrt::InfoBarSeverity severity);

void OnForegroundChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args);

winrt::InfoBarCloseReason m_lastCloseReason{ winrt::InfoBarCloseReason::Programmatic };

winrt::Button::Click_revoker m_closeButtonClickRevoker{};
tracker_ref<winrt::FrameworkElement> m_standardIconTextBlock{ this };

bool m_applyTemplateCalled{ false };
bool m_notifyOpen{ false };
Expand Down
4 changes: 2 additions & 2 deletions dev/InfoBar/InfoBar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="CloseButtonStyle" Value="{StaticResource InfoBarCloseButtonStyle}" />
<Setter Property="Background" Value="Transparent" />
<contract7Present:Setter Property="AutomationProperties.IsDialog" Value="True"/>
<contract7Present:Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
Expand Down Expand Up @@ -141,8 +142,7 @@
FontSize="{StaticResource InfoBarIconFontSize}"
Text="{StaticResource InfoBarInformationalIconGlyph}"
Foreground="{ThemeResource InfoBarInformationalSeverityIconForeground}"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
AutomationProperties.AccessibilityView="Raw" />
FontFamily="{ThemeResource SymbolThemeFontFamily}"/>
</Grid>

<Viewbox x:Name="UserIconBox"
Expand Down
2 changes: 1 addition & 1 deletion dev/InfoBar/InfoBar_v1.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
Glyph="{StaticResource InfoBarInformationalIconGlyph}"
Foreground="{ThemeResource InfoBarInformationalSeverityIconForeground}"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
AutomationProperties.AccessibilityView="Raw" />
AutomationProperties.AccessibilityView="Content" />

<Border x:Name="UserIconBorder"
Grid.Column="0"
Expand Down
23 changes: 12 additions & 11 deletions dev/InfoBar/InteractionTests/InfoBarTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,14 @@ public void LayoutTest()
StatusBar infoBar = FindElement.ByName<StatusBar>("TestInfoBar");
CheckBox customContent = FindElement.ByName<CheckBox>("CustomContentCheckBox");

// 0: icon; 1: title; 2: message; 3: action button
Log.Comment("Verify that title, message, and action button layout is left-to-right");
Verify.IsGreaterThan(infoBar.Children[1].BoundingRectangle.X, infoBar.Children[0].BoundingRectangle.X, "Expect Message to be on the right of Title");
Verify.IsGreaterThan(infoBar.Children[2].BoundingRectangle.X, infoBar.Children[1].BoundingRectangle.X, "Expect action button to be on the right of Message");
VerifyIsPrettyClose(infoBar.Children[1].BoundingRectangle.Y, infoBar.Children[0].BoundingRectangle.Y, "Expect Message to be top-aligned with Title");
Verify.IsGreaterThan(infoBar.Children[2].BoundingRectangle.X, infoBar.Children[1].BoundingRectangle.X, "Expect Message to be on the right of Title");
Verify.IsGreaterThan(infoBar.Children[3].BoundingRectangle.X, infoBar.Children[2].BoundingRectangle.X, "Expect action button to be on the right of Message");
VerifyIsPrettyClose(infoBar.Children[2].BoundingRectangle.Y, infoBar.Children[1].BoundingRectangle.Y, "Expect Message to be top-aligned with Title");

Verify.IsGreaterThan(customContent.BoundingRectangle.Y, infoBar.Children[0].BoundingRectangle.Y, "Expect custom content to be on under all other things");
VerifyIsPrettyClose(customContent.BoundingRectangle.X, infoBar.Children[0].BoundingRectangle.X, "Expect custom content to be left-aligned with title");
Verify.IsGreaterThan(customContent.BoundingRectangle.Y, infoBar.Children[1].BoundingRectangle.Y, "Expect custom content to be on under all other things");
VerifyIsPrettyClose(customContent.BoundingRectangle.X, infoBar.Children[1].BoundingRectangle.X, "Expect custom content to be left-aligned with title");

Log.Comment("Change title and message to long strings");
Edit editTitle = FindElement.ByName<Edit>("TitleTextBox");
Expand All @@ -160,13 +161,13 @@ public void LayoutTest()
editMessage.SetValueAndWait("Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent vehicula mauris eu libero pretium ullamcorper.");

Log.Comment("Verify that title, message, and action button layout is top-to-bottom");
Verify.IsGreaterThan(infoBar.Children[1].BoundingRectangle.Y, infoBar.Children[0].BoundingRectangle.Y, "Expect Message to be below Title");
Verify.IsGreaterThan(infoBar.Children[2].BoundingRectangle.Y, infoBar.Children[1].BoundingRectangle.Y, "Expect action button to be below Message");
VerifyIsPrettyClose(infoBar.Children[1].BoundingRectangle.X, infoBar.Children[0].BoundingRectangle.X, "Expect Message to be left-aligned with Title");
VerifyIsPrettyClose(infoBar.Children[2].BoundingRectangle.X, infoBar.Children[1].BoundingRectangle.X, "Expect action button to be left-aligned Message");
Verify.IsGreaterThan(infoBar.Children[2].BoundingRectangle.Y, infoBar.Children[1].BoundingRectangle.Y, "Expect Message to be below Title");
Verify.IsGreaterThan(infoBar.Children[3].BoundingRectangle.Y, infoBar.Children[2].BoundingRectangle.Y, "Expect action button to be below Message");
VerifyIsPrettyClose(infoBar.Children[2].BoundingRectangle.X, infoBar.Children[1].BoundingRectangle.X, "Expect Message to be left-aligned with Title");
VerifyIsPrettyClose(infoBar.Children[3].BoundingRectangle.X, infoBar.Children[2].BoundingRectangle.X, "Expect action button to be left-aligned Message");

Verify.IsGreaterThan(customContent.BoundingRectangle.Y, infoBar.Children[2].BoundingRectangle.Y, "Expect custom content to be on under all other things");
VerifyIsPrettyClose(customContent.BoundingRectangle.X, infoBar.Children[0].BoundingRectangle.X, "Expect custom content to be left-aligned with everyone else");
Verify.IsGreaterThan(customContent.BoundingRectangle.Y, infoBar.Children[3].BoundingRectangle.Y, "Expect custom content to be on under all other things");
VerifyIsPrettyClose(customContent.BoundingRectangle.X, infoBar.Children[1].BoundingRectangle.X, "Expect custom content to be left-aligned with everyone else");
}
}

Expand Down
36 changes: 34 additions & 2 deletions dev/InfoBar/Strings/en-us/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,40 @@
<value>InfoBar</value>
<comment>This is the custom landmark used to denote an InfoBar to narrator.</comment>
</data>
<data name="InfoBarIconSeverityErrorName" xml:space="preserve">
<value>Error icon</value>
<comment>Automation name used to announce the severity error icon.</comment>
</data>
<data name="InfoBarIconSeverityInformationalName" xml:space="preserve">
<value>Informational icon</value>
<comment>Automation name used to announce the severity informational icon.</comment>
</data>
<data name="InfoBarIconSeveritySuccessName" xml:space="preserve">
<value>Success icon</value>
<comment>Automation name used to announce the severity success icon.</comment>
</data>
<data name="InfoBarIconSeverityWarningName" xml:space="preserve">
<value>Warning icon</value>
<comment>Automation name used to announce the severity warning icon.</comment>
</data>
<data name="InfoBarOpenedNotification" xml:space="preserve">
<value>%1!s! %2!s!</value>
<comment>The formatted string read by narrator when the InfoBar opens: "{Title} {Message}"</comment>
<value>%1!s! %2!s! %3!s!</value>
<comment>The formatted string read by narrator when the InfoBar opens: "{Severity level}, {Title} {Message}"</comment>
</data>
<data name="InfoBarSeverityErrorName" xml:space="preserve">
<value>Info message, severity error</value>
<comment>Name used to announce severity error to users.</comment>
</data>
<data name="InfoBarSeverityInformationalName" xml:space="preserve">
<value>Info message, severity informational</value>
<comment>Name used to announce severity informational to users.</comment>
</data>
<data name="InfoBarSeveritySuccessName" xml:space="preserve">
<value>Info message, severity success</value>
<comment>Name used to announce severity success to users.</comment>
</data>
<data name="InfoBarSeverityWarningName" xml:space="preserve">
<value>Info message, severity warning</value>
<comment>Name used to announce severity warning to users.</comment>
</data>
</root>
8 changes: 8 additions & 0 deletions dev/ResourceHelper/ResourceAccessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ class ResourceAccessor sealed
#define SR_InfoBarClosedNotification L"InfoBarClosedNotification"
#define SR_InfoBarCustomLandmarkName L"InfoBarCustomLandmarkName"
#define SR_InfoBarCloseButtonTooltip L"InfoBarCloseButtonTooltip"
#define SR_InfoBarSeverityInformationalName L"InfoBarSeverityInformationalName"
#define SR_InfoBarSeveritySuccessName L"InfoBarSeveritySuccessName"
#define SR_InfoBarSeverityWarningName L"InfoBarSeverityWarningName"
#define SR_InfoBarSeverityErrorName L"InfoBarSeverityErrorName"
#define SR_InfoBarIconSeverityInformationalName L"InfoBarIconSeverityInformationalName"
#define SR_InfoBarIconSeveritySuccessName L"InfoBarIconSeveritySuccessName"
#define SR_InfoBarIconSeverityWarningName L"InfoBarIconSeverityWarningName"
#define SR_InfoBarIconSeverityErrorName L"InfoBarIconSeverityErrorName"

#define SR_AutomationNameEllipsisBreadcrumbBarItem L"AutomationNameEllipsisBreadcrumbBarItem"

Expand Down

0 comments on commit 1f7779d

Please sign in to comment.