[PM-2691] Adding AutomationIDs for Vault Page sections (#2580)

* Adding IDs for Vault Page sections

* Removing extra spaces

* Adding Matt's comments

* Fixing Filters Id bug

* Adding Fede's suggestions

* Fixing Settings Ids issues

* Fixing AutomationIds issues with RecyclerViews + implementing AutomationId helper class

* Adding Fede's suggestion

* Adding latest Fede's suggestions
This commit is contained in:
ifernandezdiaz 2023-06-29 15:37:08 -03:00 committed by GitHub
parent 216c6abcf6
commit 72e67bd6f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 178 additions and 30 deletions

View file

@ -159,6 +159,7 @@
<Compile Include="Constants.cs" />
<Compile Include="Effects\RemoveFontPaddingEffect.cs" />
<Compile Include="Services\WatchDeviceService.cs" />
<Compile Include="Renderers\CustomLabelRenderer.cs" />
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\bwi-font.ttf" />

View file

@ -0,0 +1,31 @@
using System;
using Bit.App.Controls;
using System.ComponentModel;
using Xamarin.Forms.Platform.Android;
using Android.Content;
using Xamarin.Forms;
using Bit.Droid.Renderers;
[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomLabelRenderer : LabelRenderer
{
public CustomLabelRenderer(Context context)
: base(context)
{ }
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var label = sender as CustomLabel;
switch (e.PropertyName)
{
case nameof(CustomLabel.AutomationId):
Control.ContentDescription = label.AutomationId;
break;
}
base.OnElementPropertyChanged(sender, e);
}
}
}

View file

@ -145,6 +145,7 @@
<Folder Include="Controls\DateTime\" />
<Folder Include="Controls\IconLabelButton\" />
<Folder Include="Controls\PasswordStrengthProgressBar\" />
<Folder Include="Utilities\Automation\" />
</ItemGroup>
<ItemGroup>
@ -440,5 +441,6 @@
<None Remove="MessagePack" />
<None Remove="MessagePack.MSBuild.Tasks" />
<None Remove="Controls\PasswordStrengthProgressBar\" />
<None Remove="Utilities\Automation\" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,13 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class CustomLabel : Label
{
public CustomLabel()
{
}
}
}

View file

@ -20,8 +20,7 @@
x:Key="regularTemplate"
x:DataType="pages:SettingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform"
AutomationId="{Binding AutomationId}">
StyleClass="list-row, list-row-platform">
<Frame
IsVisible="{Binding UseFrame}"
Padding="10"
@ -33,21 +32,21 @@
StyleClass="text-muted, text-sm, text-bold"
HorizontalTextAlignment="Center" />
</Frame>
<Label IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
<controls:CustomLabel IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
Text="{Binding Name, Mode=OneWay}"
LineBreakMode="{Binding LineBreakMode}"
HorizontalOptions="StartAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"
AutomationId="SettingTitleLabel" />
<Label Text="{Binding SubLabel, Mode=OneWay}"
AutomationId="{Binding AutomationIdSettingName}" />
<controls:CustomLabel Text="{Binding SubLabel, Mode=OneWay}"
IsVisible="{Binding ShowSubLabel}"
HorizontalOptions="End"
HorizontalTextAlignment="End"
VerticalOptions="CenterAndExpand"
TextColor="{Binding SubLabelColor}"
StyleClass="list-sub"
AutomationId="SettingStatusLabel" />
AutomationId="{Binding AutomationIdSettingStatus}" />
</controls:ExtendedStackLayout>
</DataTemplate>
<DataTemplate

View file

@ -3,6 +3,7 @@ using System.Globalization;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.App.Utilities.Automation;
using Xamarin.Forms;
namespace Bit.App.Pages
@ -23,23 +24,28 @@ namespace Bit.App.Pages
public Color SubLabelColor => SubLabelTextEnabled ?
ThemeManager.GetResourceColor("SuccessColor") :
ThemeManager.GetResourceColor("MutedColor");
public string AutomationId
public string AutomationIdSettingName
{
get
{
if (!UseFrame)
{
var idText = new CultureInfo("en-US", false)
.TextInfo
.ToTitleCase(Name)
.Replace(" ", String.Empty)
.Replace("-", String.Empty);
return $"{idText}Cell";
return AutomationIdsHelper.AddSuffixFor(
UseFrame ? "EnabledPolicy"
: AutomationIdsHelper.ToEnglishTitleCase(Name)
, SuffixType.Cell);
}
else
{
return "EnabledPolicyCell";
}
public string AutomationIdSettingStatus
{
get
{
if (UseFrame)
{
return null;
}
return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Name), SuffixType.SettingValue);
}
}
}

View file

@ -72,8 +72,7 @@
<StackLayout StyleClass="box" AutomationId="ItemInformationSection">
<StackLayout StyleClass="box-row-header">
<Label Text="{u:I18n ItemInformation, Header=True}"
StyleClass="box-header, box-header-platform"
AutomationId="" />
StyleClass="box-header, box-header-platform" />
</StackLayout>
<StackLayout StyleClass="box-row" AutomationId="ItemRow">
<Label
@ -196,7 +195,9 @@
</Grid>
<BoxView StyleClass="box-row-separator"
IsVisible="{Binding Cipher.Login.Password, Converter={StaticResource stringHasValue}}" />
<Grid StyleClass="box-row" IsVisible="{Binding ShowTotp}" AutomationId="ItemRow">
<Grid StyleClass="box-row"
IsVisible="{Binding ShowTotp}"
AutomationId="ItemRow">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />

View file

@ -60,13 +60,14 @@
<controls:AuthenticatorViewCell
Cipher="{Binding Cipher}"
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
TotpSec="{Binding TotpSec}"/>
TotpSec="{Binding TotpSec}" />
</DataTemplate>
<DataTemplate x:Key="groupTemplate"
x:DataType="pages:GroupingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
StyleClass="list-row, list-row-platform"
AutomationId="{Binding AutomationId}">
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start"
VerticalOptions="Center"
@ -80,12 +81,14 @@
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
StyleClass="list-title"
AutomationId="ItemNameLabel" />
<Label Text="{Binding ItemCount, Mode=OneWay}"
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
StyleClass="list-sub"/>
StyleClass="list-sub"
AutomationId="ItemCountLabel" />
</controls:ExtendedStackLayout>
</DataTemplate>
@ -96,7 +99,8 @@
Spacing="0"
Padding="0"
VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
StyleClass="list-row-header-container, list-row-header-container-platform"
AutomationId="{Binding AutomationId}">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
@ -105,7 +109,8 @@
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
StyleClass="list-header-sub"
AutomationId="SectionItemCount" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
@ -148,7 +153,8 @@
IsVisible="{Binding ShowNoData}">
<Label
Text="{Binding NoDataText}"
HorizontalTextAlignment="Center"></Label>
HorizontalTextAlignment="Center"
AutomationId="NoDataDisplayed"></Label>
<Button
Text="{u:I18n AddAnItem}"
Clicked="AddButton_Clicked"

View file

@ -1,4 +1,6 @@
namespace Bit.App.Pages
using Bit.App.Utilities.Automation;
namespace Bit.App.Pages
{
public class GroupingsPageHeaderListItem : IGroupingsPageListItem
{
@ -10,5 +12,12 @@
public string Title { get; }
public string ItemCount { get; set; }
public string AutomationId
{
get
{
return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Title), SuffixType.Header);
}
}
}
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Bit.App.Utilities.Automation;
namespace Bit.App.Pages
{
@ -32,5 +33,6 @@ namespace Bit.App.Pages
public string Name { get; set; }
public string NameShort => string.IsNullOrWhiteSpace(Name) || Name.Length == 0 ? "-" : Name[0].ToString();
public string ItemCount { get; set; }
public string AutomationId => AutomationIdsHelper.AddSuffixFor(NameShort, SuffixType.ListGroup);
}
}

View file

@ -1,4 +1,5 @@
using Bit.App.Resources;
using Bit.App.Utilities.Automation;
using Bit.Core;
using Bit.Core.Enums;
using Bit.Core.Models.View;
@ -115,5 +116,38 @@ namespace Bit.App.Pages
return _icon;
}
}
public string AutomationId
{
get
{
if (Type != null)
{
return AutomationIdsHelper.AddSuffixFor(System.Enum.GetName(typeof(CipherType), Type.Value), SuffixType.Filter);
}
if (IsTrash)
{
return AutomationIdsHelper.AddSuffixFor("Trash", SuffixType.Filter);
}
if (Folder != null)
{
return AutomationIdsHelper.AddSuffixFor("Folder", SuffixType.Filter);
}
if (Collection != null)
{
return AutomationIdsHelper.AddSuffixFor("Collection", SuffixType.Filter);
}
if (IsTotpCode)
{
return AutomationIdsHelper.AddSuffixFor("TOTP", SuffixType.ListItem);
}
return null;
}
}
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Globalization;
namespace Bit.App.Utilities.Automation
{
public static class AutomationIdsHelper
{
public static string ToEnglishTitleCase(string name)
{
return new CultureInfo("en-US", false)
.TextInfo
.ToTitleCase(name)
.Replace(" ", String.Empty)
.Replace("-", String.Empty);
}
public static string AddSuffixFor(string text, SuffixType type)
{
return $"{text}{Enum.GetName(typeof(SuffixType), type)}";
}
}
}

View file

@ -0,0 +1,13 @@
namespace Bit.App.Utilities.Automation
{
public enum SuffixType
{
Cell,
SettingValue,
Header,
ListGroup,
ListItem,
Filter
}
}

View file

@ -23,6 +23,14 @@ namespace Bit.iOS.Core.Renderers
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var label = sender as CustomLabel;
switch (e.PropertyName)
{
case nameof(CustomLabel.AutomationId):
Control.AccessibilityIdentifier = label.AutomationId;
break;
}
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Label.FontProperty.PropertyName ||