From 1f7779d0b6e6ba3326cfd917c71bab550143148e Mon Sep 17 00:00:00 2001 From: Marcel Wagner Date: Thu, 22 Apr 2021 17:45:09 +0200 Subject: [PATCH] Update InfoBar narrator behavior (#4578) * 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 <30241445+teaP@users.noreply.github.com> --- dev/InfoBar/InfoBar.cpp | 48 ++++++++++++++++++-- dev/InfoBar/InfoBar.h | 5 ++ dev/InfoBar/InfoBar.xaml | 4 +- dev/InfoBar/InfoBar_v1.xaml | 2 +- dev/InfoBar/InteractionTests/InfoBarTests.cs | 23 +++++----- dev/InfoBar/Strings/en-us/Resources.resw | 36 ++++++++++++++- dev/ResourceHelper/ResourceAccessor.h | 8 ++++ 7 files changed, 106 insertions(+), 20 deletions(-) diff --git a/dev/InfoBar/InfoBar.cpp b/dev/InfoBar/InfoBar.cpp index c9cbd8ad61..75f538de69 100644 --- a/dev/InfoBar/InfoBar.cpp +++ b/dev/InfoBar/InfoBar.cpp @@ -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() @@ -47,7 +48,6 @@ 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); @@ -55,6 +55,12 @@ void InfoBar::OnApplyTemplate() winrt::ToolTipService::SetToolTip(closeButton, tooltip); } + if (const auto iconTextblock = GetTemplateChildT(c_iconTextBlockName, controlProtected)) + { + m_standardIconTextBlock.set(iconTextblock); + winrt::AutomationProperties::SetName(iconTextblock, ResourceAccessor::GetLocalizedStringResource(GetIconSeverityLevelResourceName(Severity()))); + } + if (auto&& contentRootGrid = GetTemplateChildT(c_contentRootName, controlProtected)) { winrt::AutomationProperties::SetLocalizedLandmarkType(contentRootGrid, ResourceAccessor::GetLocalizedStringResource(SR_InfoBarCustomLandmarkName)); @@ -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()); @@ -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); } @@ -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; +} diff --git a/dev/InfoBar/InfoBar.h b/dev/InfoBar/InfoBar.h index 1581c34983..6f37491d21 100644 --- a/dev/InfoBar/InfoBar.h +++ b/dev/InfoBar/InfoBar.h @@ -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 m_standardIconTextBlock{ this }; bool m_applyTemplateCalled{ false }; bool m_notifyOpen{ false }; diff --git a/dev/InfoBar/InfoBar.xaml b/dev/InfoBar/InfoBar.xaml index c63cf18e81..a172b21d86 100644 --- a/dev/InfoBar/InfoBar.xaml +++ b/dev/InfoBar/InfoBar.xaml @@ -10,6 +10,7 @@ + @@ -141,8 +142,7 @@ FontSize="{StaticResource InfoBarIconFontSize}" Text="{StaticResource InfoBarInformationalIconGlyph}" Foreground="{ThemeResource InfoBarInformationalSeverityIconForeground}" - FontFamily="{ThemeResource SymbolThemeFontFamily}" - AutomationProperties.AccessibilityView="Raw" /> + FontFamily="{ThemeResource SymbolThemeFontFamily}"/> + AutomationProperties.AccessibilityView="Content" /> ("TestInfoBar"); CheckBox customContent = FindElement.ByName("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("TitleTextBox"); @@ -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"); } } diff --git a/dev/InfoBar/Strings/en-us/Resources.resw b/dev/InfoBar/Strings/en-us/Resources.resw index b869a68c43..e8b55610db 100644 --- a/dev/InfoBar/Strings/en-us/Resources.resw +++ b/dev/InfoBar/Strings/en-us/Resources.resw @@ -133,8 +133,40 @@ InfoBar This is the custom landmark used to denote an InfoBar to narrator. + + Error icon + Automation name used to announce the severity error icon. + + + Informational icon + Automation name used to announce the severity informational icon. + + + Success icon + Automation name used to announce the severity success icon. + + + Warning icon + Automation name used to announce the severity warning icon. + - %1!s! %2!s! - The formatted string read by narrator when the InfoBar opens: "{Title} {Message}" + %1!s! %2!s! %3!s! + The formatted string read by narrator when the InfoBar opens: "{Severity level}, {Title} {Message}" + + + Info message, severity error + Name used to announce severity error to users. + + + Info message, severity informational + Name used to announce severity informational to users. + + + Info message, severity success + Name used to announce severity success to users. + + + Info message, severity warning + Name used to announce severity warning to users. \ No newline at end of file diff --git a/dev/ResourceHelper/ResourceAccessor.h b/dev/ResourceHelper/ResourceAccessor.h index e51d0e5d22..08ebebb51a 100755 --- a/dev/ResourceHelper/ResourceAccessor.h +++ b/dev/ResourceHelper/ResourceAccessor.h @@ -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"