mirror of
https://github.com/bitwarden/mobile.git
synced 2024-12-02 13:13:31 +01:00
[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:
parent
216c6abcf6
commit
72e67bd6f2
@ -159,6 +159,7 @@
|
|||||||
<Compile Include="Constants.cs" />
|
<Compile Include="Constants.cs" />
|
||||||
<Compile Include="Effects\RemoveFontPaddingEffect.cs" />
|
<Compile Include="Effects\RemoveFontPaddingEffect.cs" />
|
||||||
<Compile Include="Services\WatchDeviceService.cs" />
|
<Compile Include="Services\WatchDeviceService.cs" />
|
||||||
|
<Compile Include="Renderers\CustomLabelRenderer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidAsset Include="Assets\bwi-font.ttf" />
|
<AndroidAsset Include="Assets\bwi-font.ttf" />
|
||||||
|
31
src/Android/Renderers/CustomLabelRenderer.cs
Normal file
31
src/Android/Renderers/CustomLabelRenderer.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -145,6 +145,7 @@
|
|||||||
<Folder Include="Controls\DateTime\" />
|
<Folder Include="Controls\DateTime\" />
|
||||||
<Folder Include="Controls\IconLabelButton\" />
|
<Folder Include="Controls\IconLabelButton\" />
|
||||||
<Folder Include="Controls\PasswordStrengthProgressBar\" />
|
<Folder Include="Controls\PasswordStrengthProgressBar\" />
|
||||||
|
<Folder Include="Utilities\Automation\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -440,5 +441,6 @@
|
|||||||
<None Remove="MessagePack" />
|
<None Remove="MessagePack" />
|
||||||
<None Remove="MessagePack.MSBuild.Tasks" />
|
<None Remove="MessagePack.MSBuild.Tasks" />
|
||||||
<None Remove="Controls\PasswordStrengthProgressBar\" />
|
<None Remove="Controls\PasswordStrengthProgressBar\" />
|
||||||
|
<None Remove="Utilities\Automation\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
13
src/App/Controls/CustomLabel.cs
Normal file
13
src/App/Controls/CustomLabel.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Controls
|
||||||
|
{
|
||||||
|
public class CustomLabel : Label
|
||||||
|
{
|
||||||
|
public CustomLabel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,8 +20,7 @@
|
|||||||
x:Key="regularTemplate"
|
x:Key="regularTemplate"
|
||||||
x:DataType="pages:SettingsPageListItem">
|
x:DataType="pages:SettingsPageListItem">
|
||||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
<controls:ExtendedStackLayout Orientation="Horizontal"
|
||||||
StyleClass="list-row, list-row-platform"
|
StyleClass="list-row, list-row-platform">
|
||||||
AutomationId="{Binding AutomationId}">
|
|
||||||
<Frame
|
<Frame
|
||||||
IsVisible="{Binding UseFrame}"
|
IsVisible="{Binding UseFrame}"
|
||||||
Padding="10"
|
Padding="10"
|
||||||
@ -33,21 +32,21 @@
|
|||||||
StyleClass="text-muted, text-sm, text-bold"
|
StyleClass="text-muted, text-sm, text-bold"
|
||||||
HorizontalTextAlignment="Center" />
|
HorizontalTextAlignment="Center" />
|
||||||
</Frame>
|
</Frame>
|
||||||
<Label IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
|
<controls:CustomLabel IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
|
||||||
Text="{Binding Name, Mode=OneWay}"
|
Text="{Binding Name, Mode=OneWay}"
|
||||||
LineBreakMode="{Binding LineBreakMode}"
|
LineBreakMode="{Binding LineBreakMode}"
|
||||||
HorizontalOptions="StartAndExpand"
|
HorizontalOptions="StartAndExpand"
|
||||||
VerticalOptions="CenterAndExpand"
|
VerticalOptions="CenterAndExpand"
|
||||||
StyleClass="list-title"
|
StyleClass="list-title"
|
||||||
AutomationId="SettingTitleLabel" />
|
AutomationId="{Binding AutomationIdSettingName}" />
|
||||||
<Label Text="{Binding SubLabel, Mode=OneWay}"
|
<controls:CustomLabel Text="{Binding SubLabel, Mode=OneWay}"
|
||||||
IsVisible="{Binding ShowSubLabel}"
|
IsVisible="{Binding ShowSubLabel}"
|
||||||
HorizontalOptions="End"
|
HorizontalOptions="End"
|
||||||
HorizontalTextAlignment="End"
|
HorizontalTextAlignment="End"
|
||||||
VerticalOptions="CenterAndExpand"
|
VerticalOptions="CenterAndExpand"
|
||||||
TextColor="{Binding SubLabelColor}"
|
TextColor="{Binding SubLabelColor}"
|
||||||
StyleClass="list-sub"
|
StyleClass="list-sub"
|
||||||
AutomationId="SettingStatusLabel" />
|
AutomationId="{Binding AutomationIdSettingStatus}" />
|
||||||
</controls:ExtendedStackLayout>
|
</controls:ExtendedStackLayout>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
<DataTemplate
|
<DataTemplate
|
||||||
|
@ -3,6 +3,7 @@ using System.Globalization;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
using Bit.App.Utilities.Automation;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
@ -23,23 +24,28 @@ namespace Bit.App.Pages
|
|||||||
public Color SubLabelColor => SubLabelTextEnabled ?
|
public Color SubLabelColor => SubLabelTextEnabled ?
|
||||||
ThemeManager.GetResourceColor("SuccessColor") :
|
ThemeManager.GetResourceColor("SuccessColor") :
|
||||||
ThemeManager.GetResourceColor("MutedColor");
|
ThemeManager.GetResourceColor("MutedColor");
|
||||||
public string AutomationId
|
|
||||||
|
public string AutomationIdSettingName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!UseFrame)
|
return AutomationIdsHelper.AddSuffixFor(
|
||||||
|
UseFrame ? "EnabledPolicy"
|
||||||
|
: AutomationIdsHelper.ToEnglishTitleCase(Name)
|
||||||
|
, SuffixType.Cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string AutomationIdSettingStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (UseFrame)
|
||||||
{
|
{
|
||||||
var idText = new CultureInfo("en-US", false)
|
return null;
|
||||||
.TextInfo
|
|
||||||
.ToTitleCase(Name)
|
|
||||||
.Replace(" ", String.Empty)
|
|
||||||
.Replace("-", String.Empty);
|
|
||||||
return $"{idText}Cell";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "EnabledPolicyCell";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Name), SuffixType.SettingValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,7 @@
|
|||||||
<StackLayout StyleClass="box" AutomationId="ItemInformationSection">
|
<StackLayout StyleClass="box" AutomationId="ItemInformationSection">
|
||||||
<StackLayout StyleClass="box-row-header">
|
<StackLayout StyleClass="box-row-header">
|
||||||
<Label Text="{u:I18n ItemInformation, Header=True}"
|
<Label Text="{u:I18n ItemInformation, Header=True}"
|
||||||
StyleClass="box-header, box-header-platform"
|
StyleClass="box-header, box-header-platform" />
|
||||||
AutomationId="" />
|
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout StyleClass="box-row" AutomationId="ItemRow">
|
<StackLayout StyleClass="box-row" AutomationId="ItemRow">
|
||||||
<Label
|
<Label
|
||||||
@ -196,7 +195,9 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
<BoxView StyleClass="box-row-separator"
|
<BoxView StyleClass="box-row-separator"
|
||||||
IsVisible="{Binding Cipher.Login.Password, Converter={StaticResource stringHasValue}}" />
|
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>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
|
@ -60,13 +60,14 @@
|
|||||||
<controls:AuthenticatorViewCell
|
<controls:AuthenticatorViewCell
|
||||||
Cipher="{Binding Cipher}"
|
Cipher="{Binding Cipher}"
|
||||||
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
|
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
|
||||||
TotpSec="{Binding TotpSec}"/>
|
TotpSec="{Binding TotpSec}" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="groupTemplate"
|
<DataTemplate x:Key="groupTemplate"
|
||||||
x:DataType="pages:GroupingsPageListItem">
|
x:DataType="pages:GroupingsPageListItem">
|
||||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
<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}"
|
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
|
||||||
HorizontalOptions="Start"
|
HorizontalOptions="Start"
|
||||||
VerticalOptions="Center"
|
VerticalOptions="Center"
|
||||||
@ -80,12 +81,14 @@
|
|||||||
LineBreakMode="TailTruncation"
|
LineBreakMode="TailTruncation"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
VerticalOptions="CenterAndExpand"
|
VerticalOptions="CenterAndExpand"
|
||||||
StyleClass="list-title"/>
|
StyleClass="list-title"
|
||||||
|
AutomationId="ItemNameLabel" />
|
||||||
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
||||||
HorizontalOptions="End"
|
HorizontalOptions="End"
|
||||||
VerticalOptions="CenterAndExpand"
|
VerticalOptions="CenterAndExpand"
|
||||||
HorizontalTextAlignment="End"
|
HorizontalTextAlignment="End"
|
||||||
StyleClass="list-sub"/>
|
StyleClass="list-sub"
|
||||||
|
AutomationId="ItemCountLabel" />
|
||||||
</controls:ExtendedStackLayout>
|
</controls:ExtendedStackLayout>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
@ -96,7 +99,8 @@
|
|||||||
Spacing="0"
|
Spacing="0"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
VerticalOptions="FillAndExpand"
|
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
|
<BoxView
|
||||||
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
|
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
|
||||||
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
||||||
@ -105,7 +109,8 @@
|
|||||||
StyleClass="list-header, list-header-platform" />
|
StyleClass="list-header, list-header-platform" />
|
||||||
<Label
|
<Label
|
||||||
Text="{Binding ItemCount}"
|
Text="{Binding ItemCount}"
|
||||||
StyleClass="list-header-sub" />
|
StyleClass="list-header-sub"
|
||||||
|
AutomationId="SectionItemCount" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
@ -148,7 +153,8 @@
|
|||||||
IsVisible="{Binding ShowNoData}">
|
IsVisible="{Binding ShowNoData}">
|
||||||
<Label
|
<Label
|
||||||
Text="{Binding NoDataText}"
|
Text="{Binding NoDataText}"
|
||||||
HorizontalTextAlignment="Center"></Label>
|
HorizontalTextAlignment="Center"
|
||||||
|
AutomationId="NoDataDisplayed"></Label>
|
||||||
<Button
|
<Button
|
||||||
Text="{u:I18n AddAnItem}"
|
Text="{u:I18n AddAnItem}"
|
||||||
Clicked="AddButton_Clicked"
|
Clicked="AddButton_Clicked"
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace Bit.App.Pages
|
using Bit.App.Utilities.Automation;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class GroupingsPageHeaderListItem : IGroupingsPageListItem
|
public class GroupingsPageHeaderListItem : IGroupingsPageListItem
|
||||||
{
|
{
|
||||||
@ -10,5 +12,12 @@
|
|||||||
|
|
||||||
public string Title { get; }
|
public string Title { get; }
|
||||||
public string ItemCount { get; set; }
|
public string ItemCount { get; set; }
|
||||||
|
public string AutomationId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Title), SuffixType.Header);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Bit.App.Utilities.Automation;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@ -32,5 +33,6 @@ namespace Bit.App.Pages
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string NameShort => string.IsNullOrWhiteSpace(Name) || Name.Length == 0 ? "-" : Name[0].ToString();
|
public string NameShort => string.IsNullOrWhiteSpace(Name) || Name.Length == 0 ? "-" : Name[0].ToString();
|
||||||
public string ItemCount { get; set; }
|
public string ItemCount { get; set; }
|
||||||
|
public string AutomationId => AutomationIdsHelper.AddSuffixFor(NameShort, SuffixType.ListGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
|
using Bit.App.Utilities.Automation;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
@ -115,5 +116,38 @@ namespace Bit.App.Pages
|
|||||||
return _icon;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
src/App/Utilities/Automation/AutomationIdsHelper.cs
Normal file
23
src/App/Utilities/Automation/AutomationIdsHelper.cs
Normal 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)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
13
src/App/Utilities/Automation/SuffixType.cs
Normal file
13
src/App/Utilities/Automation/SuffixType.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Bit.App.Utilities.Automation
|
||||||
|
{
|
||||||
|
public enum SuffixType
|
||||||
|
{
|
||||||
|
Cell,
|
||||||
|
SettingValue,
|
||||||
|
Header,
|
||||||
|
ListGroup,
|
||||||
|
ListItem,
|
||||||
|
Filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,15 @@ namespace Bit.iOS.Core.Renderers
|
|||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnElementPropertyChanged(sender, 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 ||
|
if (e.PropertyName == Label.FontProperty.PropertyName ||
|
||||||
e.PropertyName == Label.TextProperty.PropertyName ||
|
e.PropertyName == Label.TextProperty.PropertyName ||
|
||||||
|
Loading…
Reference in New Issue
Block a user