This repository was archived by the owner on May 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 455
Base implementations for SemanticEffect and SemanticOrderView #1240
Merged
Merged
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
0efdc5a
Base implementations for SemanticEffect and SemanticOrderView
jamesmontemagno c92d669
- uwp and iOS fix
PureWeen dfdb369
- uwp tab index
PureWeen 616359c
- hint and description
PureWeen 7c8e4b4
- fix iOS to auto set to important for accessibility
PureWeen c18f37a
Merge branch 'main' into accessibility-views-effects
jsuarezruiz 7d1193b
Add samples and fix up crashes
jamesmontemagno 980c8e6
- for UI Test reason switch to using a delegate for reading content D…
PureWeen a5b52cf
- use the delegate if the automation id is set
PureWeen 5c0b0f4
- fixes
PureWeen 86db533
- set yes less often
PureWeen edb5026
Remove IsInAccessibleTree from PancakeView
rachelkang 46d5f84
Update SemanticEffectPage.xaml
rachelkang a7239c7
Update SemanticOrderViewPage.xaml
rachelkang 6c57f52
Update SemanticOrderViewPage.xaml.cs
rachelkang aff986f
Fix Semantic Description on Android
rachelkang 83cb46f
Reword SemanticEffect about
rachelkang 09c4640
- added temporary workaround for making a screen clickable
PureWeen f5ca514
Merge branch 'accessibility-views-effects' of https://github.com/xama…
rachelkang 18ae418
Fix SemanticOrderViewPage sample
rachelkang 300d569
Fix NRE thrown on back nav from iOS SemanticOrderView page
rachelkang d200667
- fix UWP router
PureWeen c507bad
- fix null checks
PureWeen 727873e
- changed first button to button so uwp sample is interesting
PureWeen 626e09b
Clean up code - Pedro's feedback
rachelkang 36b39e4
Merge branch 'accessibility-views-effects' of https://github.com/xama…
rachelkang dfdd78a
Merge branch 'main' into accessibility-views-effects
rachelkang b34d677
Merge branch 'main' into accessibility-views-effects
jfversluis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| using Android.Content; | ||
| using Xamarin.CommunityToolkit.Sample.Droid; | ||
| using Xamarin.CommunityToolkit.Sample.Pages.Views; | ||
| using Xamarin.Forms; | ||
| using Xamarin.Forms.Platform.Android; | ||
|
|
||
| // This is a temporary fix for an issue in forms that will be fixed in a later release of 5.0 | ||
| // https://github.com/xamarin/Xamarin.Forms/pull/14089 | ||
| [assembly: ExportRenderer(typeof(SemanticOrderViewPage), typeof(AccessiblePageRenderer))] | ||
|
|
||
| namespace Xamarin.CommunityToolkit.Sample.Droid | ||
| { | ||
| public class AccessiblePageRenderer : PageRenderer | ||
| { | ||
| public AccessiblePageRenderer(Context context) | ||
| : base(context) | ||
| { | ||
| } | ||
|
|
||
| protected override void OnElementChanged(ElementChangedEventArgs<Page> e) | ||
| { | ||
| base.OnElementChanged(e); | ||
| Clickable = false; | ||
| } | ||
|
|
||
| protected override void OnAttachedToWindow() | ||
| { | ||
| base.OnAttachedToWindow(); | ||
| DisableFocusableInTouchMode(); | ||
| } | ||
|
|
||
| protected override void AttachViewToParent(global::Android.Views.View? child, int index, LayoutParams? @params) | ||
| { | ||
| base.AttachViewToParent(child, index, @params); | ||
| DisableFocusableInTouchMode(); | ||
| } | ||
|
|
||
| void DisableFocusableInTouchMode() | ||
| { | ||
| var view = Parent; | ||
| var className = $"{view?.GetType().Name}"; | ||
|
|
||
| while (!className.Contains("PlatformRenderer") && view != null) | ||
| { | ||
| view = view.Parent; | ||
| className = $"{view?.GetType().Name}"; | ||
| } | ||
|
|
||
| if (view is global::Android.Views.View androidView) | ||
| { | ||
| androidView.Focusable = false; | ||
| androidView.FocusableInTouchMode = false; | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| <?xml version="1.0" encoding="utf-8" ?> | ||
| <pages:BasePage xmlns="http://xamarin.com/schemas/2014/forms" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| x:Class="Xamarin.CommunityToolkit.Sample.Pages.Effects.SemanticEffectPage" | ||
| xmlns:pages="clr-namespace:Xamarin.CommunityToolkit.Sample.Pages" | ||
| xmlns:xct="http://xamarin.com/schemas/2020/toolkit"> | ||
| <ContentPage.Content> | ||
| <ScrollView> | ||
| <StackLayout Padding="20"> | ||
| <Label Text="I have no heading" xct:SemanticEffect.HeadingLevel="None"/> | ||
| <Label Text="I am a heading 1" xct:SemanticEffect.HeadingLevel="Level1"/> | ||
| <Label Text="I am a heading 2" xct:SemanticEffect.HeadingLevel="Level2"/> | ||
| <Label Text="I am a heading 3" xct:SemanticEffect.HeadingLevel="Level3"/> | ||
| <Label Text="I am a heading 4" xct:SemanticEffect.HeadingLevel="Level4"/> | ||
| <Label Text="I am a heading 5" xct:SemanticEffect.HeadingLevel="Level5"/> | ||
| <Label Text="I am a heading 6" xct:SemanticEffect.HeadingLevel="Level6"/> | ||
| <Label Text="I am a heading 7" xct:SemanticEffect.HeadingLevel="Level7"/> | ||
| <Label Text="I am a heading 8" xct:SemanticEffect.HeadingLevel="Level8"/> | ||
| <Label Text="I am a heading 9" xct:SemanticEffect.HeadingLevel="Level9"/> | ||
|
|
||
| <Label Text="I am a label with an automation ID" AutomationId="labelAutomationIdTest" xct:SemanticEffect.Description="This is a semantic description" /> | ||
|
|
||
| <Label Text="The button below has a semantic hint"/> | ||
| <Button | ||
| Text="Button with hint" | ||
| xct:SemanticEffect.Hint="This is a hint that describes the button. For example, 'sends a message'"/> | ||
|
|
||
| <Label Text="The image below has a semantic description"/> | ||
| <Image | ||
| Source="{xct:ImageResource Id=Xamarin.CommunityToolkit.Sample.Images.logo.png}" | ||
| xct:SemanticEffect.Description="This is a description that describes the image. For example, 'image of xamarin community toolkit logo'"/> | ||
| </StackLayout> | ||
| </ScrollView> | ||
| </ContentPage.Content> | ||
| </pages:BasePage> |
13 changes: 13 additions & 0 deletions
13
samples/XCT.Sample/Pages/Effects/SemanticEffectPage.xaml.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| | ||
| using Xamarin.Forms; | ||
|
|
||
| namespace Xamarin.CommunityToolkit.Sample.Pages.Effects | ||
| { | ||
| public partial class SemanticEffectPage : BasePage | ||
| { | ||
| public SemanticEffectPage() | ||
| { | ||
| InitializeComponent(); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <?xml version="1.0" encoding="utf-8" ?> | ||
| <pages:BasePage xmlns="http://xamarin.com/schemas/2014/forms" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| xmlns:pages="clr-namespace:Xamarin.CommunityToolkit.Sample.Pages" | ||
| x:Class="Xamarin.CommunityToolkit.Sample.Pages.Views.SemanticOrderViewPage" | ||
| xmlns:xct="http://xamarin.com/schemas/2020/toolkit"> | ||
| <ContentPage.Content> | ||
| <StackLayout Margin="20"> | ||
| <Button Text="Element outside the Semantic View"></Button> | ||
| <xct:SemanticOrderView x:Name="acv"> | ||
| <StackLayout> | ||
| <Label x:Name="second" Text="Second" Margin="0,20" /> | ||
| <Button x:Name="third" Text="Third" Margin="0,20" /> | ||
| <Label x:Name="fourth" Text="Fourth" Margin="0,20" /> | ||
| <Button x:Name="fifth" Text="Fifth and last" Margin="0,20" /> | ||
| <Button x:Name="first" Text="First" Margin="0,20" /> | ||
| </StackLayout> | ||
| </xct:SemanticOrderView> | ||
| </StackLayout> | ||
| </ContentPage.Content> | ||
| </pages:BasePage> |
15 changes: 15 additions & 0 deletions
15
samples/XCT.Sample/Pages/Views/SemanticOrderViewPage.xaml.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| using Xamarin.Forms; | ||
|
|
||
| namespace Xamarin.CommunityToolkit.Sample.Pages.Views | ||
| { | ||
| public partial class SemanticOrderViewPage : BasePage | ||
| { | ||
| public SemanticOrderViewPage() | ||
| { | ||
| InitializeComponent(); | ||
| acv.ViewOrder = new List<View> { first, second, third, fourth, fifth }; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Semantic/SemanticEffect.shared.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Text; | ||
| using Xamarin.Forms; | ||
| using Xamarin.CommunityToolkit.Effects.Semantic; | ||
|
|
||
| namespace Xamarin.CommunityToolkit.Effects | ||
| { | ||
| public static class SemanticEffect | ||
| { | ||
| public static readonly BindableProperty HeadingLevelProperty = | ||
| BindableProperty.CreateAttached("HeadingLevel", typeof(HeadingLevel), typeof(SemanticEffect), HeadingLevel.None, propertyChanged: OnPropertyChanged); | ||
|
|
||
| public static HeadingLevel GetHeadingLevel(BindableObject view) => (HeadingLevel)view.GetValue(HeadingLevelProperty); | ||
|
|
||
| public static void SetHeadingLevel(BindableObject view, HeadingLevel value) => view.SetValue(HeadingLevelProperty, value); | ||
|
|
||
|
|
||
| public static readonly BindableProperty DescriptionProperty = BindableProperty.CreateAttached("Description", typeof(string), typeof(SemanticEffect), default(string), propertyChanged: OnPropertyChanged); | ||
|
|
||
| public static string GetDescription(BindableObject bindable) => (string)bindable.GetValue(DescriptionProperty); | ||
|
|
||
| public static void SetDescription(BindableObject bindable, string value) => bindable.SetValue(DescriptionProperty, value); | ||
|
|
||
| public static readonly BindableProperty HintProperty = BindableProperty.CreateAttached("Hint", typeof(string), typeof(SemanticEffect), default(string), propertyChanged: OnPropertyChanged); | ||
|
|
||
| public static string GetHint(BindableObject bindable) => (string)bindable.GetValue(HintProperty); | ||
|
|
||
| public static void SetHint(BindableObject bindable, string value) => bindable.SetValue(HintProperty, value); | ||
|
|
||
| static void OnPropertyChanged(BindableObject bindable, object oldValue, object newValue) | ||
| { | ||
| if (bindable is not View view) | ||
| return; | ||
|
|
||
| if (view.Effects.FirstOrDefault(x => x is SemanticEffectRouter) == null) | ||
| { | ||
| view.Effects.Add(new SemanticEffectRouter()); | ||
| } | ||
| } | ||
| } | ||
| } |
96 changes: 96 additions & 0 deletions
96
...ommunityToolkit/Xamarin.CommunityToolkit/Effects/Semantic/SemanticEffectRouter.android.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| using AndroidX.Core.View; | ||
| using System.ComponentModel; | ||
| using Xamarin.Forms; | ||
| using Xamarin.CommunityToolkit.Effects; | ||
| using Effects = Xamarin.CommunityToolkit.Android.Effects; | ||
| using AndroidX.Core.View.Accessibiity; | ||
| using Android.Widget; | ||
|
|
||
| [assembly: ExportEffect(typeof(Effects.SemanticEffectRouter), nameof(SemanticEffectRouter))] | ||
|
|
||
| namespace Xamarin.CommunityToolkit.Android.Effects | ||
| { | ||
| /// <summary> | ||
| /// Android implementation of the <see cref="SemanticEffect" /> | ||
| /// </summary> | ||
| public class SemanticEffectRouter : SemanticEffectRouterBase<SemanticEffectRouter> | ||
| { | ||
| SemanticAccessibilityDelegate? semanticAccessibilityDelegate; | ||
|
|
||
| protected override void Update(global::Android.Views.View view, SemanticEffectRouter effect) | ||
| { | ||
| var isHeading = SemanticEffect.GetHeadingLevel(Element) != CommunityToolkit.Effects.Semantic.HeadingLevel.None; | ||
| ViewCompat.SetAccessibilityHeading(view, isHeading); | ||
| var desc = SemanticEffect.GetDescription(Element); | ||
| var hint = SemanticEffect.GetHint(Element); | ||
|
|
||
| if (!string.IsNullOrEmpty(hint) || !string.IsNullOrEmpty(desc)) | ||
| { | ||
| if (semanticAccessibilityDelegate == null) | ||
| { | ||
| semanticAccessibilityDelegate = new SemanticAccessibilityDelegate(Element); | ||
| ViewCompat.SetAccessibilityDelegate(view, semanticAccessibilityDelegate); | ||
| } | ||
| } | ||
| else if (semanticAccessibilityDelegate != null) | ||
| { | ||
| semanticAccessibilityDelegate = null; | ||
| ViewCompat.SetAccessibilityDelegate(view, null); | ||
| } | ||
|
|
||
| if (semanticAccessibilityDelegate != null) | ||
| semanticAccessibilityDelegate.Element = Element; | ||
|
|
||
| if (semanticAccessibilityDelegate != null) | ||
| view.ImportantForAccessibility = global::Android.Views.ImportantForAccessibility.Yes; | ||
rachelkang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| protected override void OnElementPropertyChanged(PropertyChangedEventArgs args) | ||
| { | ||
| base.OnElementPropertyChanged(args); | ||
|
|
||
| if (args.PropertyName == SemanticEffect.HeadingLevelProperty.PropertyName || | ||
| args.PropertyName == SemanticEffect.DescriptionProperty.PropertyName || | ||
| args.PropertyName == SemanticEffect.HintProperty.PropertyName) | ||
| { | ||
| Update(); | ||
| } | ||
| } | ||
|
|
||
| class SemanticAccessibilityDelegate : AccessibilityDelegateCompat | ||
| { | ||
| public Element Element { get; set; } | ||
|
|
||
| public SemanticAccessibilityDelegate(Element element) | ||
| { | ||
| Element = element; | ||
| } | ||
|
|
||
| public override void OnInitializeAccessibilityNodeInfo(global::Android.Views.View host, AccessibilityNodeInfoCompat info) | ||
| { | ||
| base.OnInitializeAccessibilityNodeInfo(host, info); | ||
|
|
||
| if (Element == null) | ||
| return; | ||
|
|
||
| if (info == null) | ||
| return; | ||
|
|
||
| var hint = SemanticEffect.GetHint(Element); | ||
| if (!string.IsNullOrEmpty(hint)) | ||
| { | ||
| info.HintText = hint; | ||
|
|
||
| if (host is EditText) | ||
| info.ShowingHintText = false; | ||
| } | ||
|
|
||
| var desc = SemanticEffect.GetDescription(Element); | ||
| if (!string.IsNullOrEmpty(desc)) | ||
| { | ||
| info.ContentDescription = desc; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.