-
-
Notifications
You must be signed in to change notification settings - Fork 230
Add element binding extensibility #3997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
188a44a
683ecf8
464d25b
a1a90eb
0c52fba
170cf18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| namespace Sentry.Maui; | ||
|
|
||
| /// <summary> | ||
| /// Bind to MAUI controls to generate breadcrumbs and other metrics | ||
| /// </summary> | ||
| public interface IMauiElementEventBinder | ||
| { | ||
| /// <summary> | ||
| /// Bind to an element | ||
| /// </summary> | ||
| /// <param name="element"></param> | ||
| /// <param name="addBreadcrumb"> | ||
| /// This adds a breadcrumb to the sentry hub | ||
| /// NOTE: we will override the type, timestamp, and category of the breadcrumb | ||
| /// </param> | ||
| void Bind(VisualElement element, Action<BreadcrumbEvent> addBreadcrumb); | ||
|
|
||
| /// <summary> | ||
| /// Unbind the element because MAUI is removing the page | ||
| /// </summary> | ||
| /// <param name="element"></param> | ||
| void UnBind(VisualElement element); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Breadcrumb arguments | ||
| /// </summary> | ||
| /// <param name="Sender"></param> | ||
| /// <param name="EventName"></param> | ||
| /// <param name="ExtraData"></param> | ||
| public record BreadcrumbEvent( | ||
| object? Sender, | ||
| string EventName, | ||
| params IEnumerable<(string Key, string Value)>[] ExtraData | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| namespace Sentry.Maui.Internal; | ||
|
|
||
| /// <inheritdoc /> | ||
| public class MauiButtonEventsBinder : IMauiElementEventBinder | ||
| { | ||
| private Action<BreadcrumbEvent>? addBreadcrumbCallback; | ||
|
|
||
| /// <inheritdoc /> | ||
| public void Bind(VisualElement element, Action<BreadcrumbEvent> addBreadcrumb) | ||
| { | ||
| addBreadcrumbCallback = addBreadcrumb; | ||
|
|
||
| if (element is Button button) | ||
| { | ||
| button.Clicked += OnButtonOnClicked; | ||
| button.Pressed += OnButtonOnPressed; | ||
| button.Released += OnButtonOnReleased; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public void UnBind(VisualElement element) | ||
| { | ||
| if (element is Button button) | ||
| { | ||
| button.Clicked -= OnButtonOnClicked; | ||
| button.Pressed -= OnButtonOnPressed; | ||
| button.Released -= OnButtonOnReleased; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| private void OnButtonOnClicked(object? sender, EventArgs _) | ||
| => addBreadcrumbCallback?.Invoke(new(sender, nameof(Button.Clicked))); | ||
|
|
||
| private void OnButtonOnPressed(object? sender, EventArgs _) | ||
| => addBreadcrumbCallback?.Invoke(new(sender, nameof(Button.Pressed))); | ||
|
|
||
| private void OnButtonOnReleased(object? sender, EventArgs _) | ||
| => addBreadcrumbCallback?.Invoke(new(sender, nameof(Button.Released))); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ internal class MauiEventsBinder : IMauiEventsBinder | |
| { | ||
| private readonly IHub _hub; | ||
| private readonly SentryMauiOptions _options; | ||
| private readonly IEnumerable<IMauiElementEventBinder> _elementEventBinders; | ||
|
|
||
| // https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/#breadcrumb-types | ||
| // https://github.com/getsentry/sentry/blob/master/static/app/types/breadcrumbs.tsx | ||
|
|
@@ -22,10 +23,11 @@ internal class MauiEventsBinder : IMauiEventsBinder | |
| internal const string RenderingCategory = "ui.rendering"; | ||
| internal const string UserActionCategory = "ui.useraction"; | ||
|
|
||
| public MauiEventsBinder(IHub hub, IOptions<SentryMauiOptions> options) | ||
| public MauiEventsBinder(IHub hub, IOptions<SentryMauiOptions> options, IEnumerable<IMauiElementEventBinder> elementEventBinders) | ||
| { | ||
| _hub = hub; | ||
| _options = options.Value; | ||
| _elementEventBinders = elementEventBinders; | ||
| } | ||
|
|
||
| public void HandleApplicationEvents(Application application, bool bind = true) | ||
|
|
@@ -70,7 +72,7 @@ public void HandleApplicationEvents(Application application, bool bind = true) | |
| } | ||
| } | ||
|
|
||
| private void OnApplicationOnDescendantAdded(object? _, ElementEventArgs e) | ||
| internal void OnApplicationOnDescendantAdded(object? _, ElementEventArgs e) | ||
| { | ||
| if (_options.CreateElementEventsBreadcrumbs) | ||
| { | ||
|
|
@@ -96,15 +98,30 @@ private void OnApplicationOnDescendantAdded(object? _, ElementEventArgs e) | |
| case Page page: | ||
| HandlePageEvents(page); | ||
| break; | ||
| case Button button: | ||
| HandleButtonEvents(button); | ||
| default: | ||
| if (e.Element is VisualElement ve) | ||
| { | ||
| foreach (var binder in _elementEventBinders) | ||
| { | ||
| binder.Bind(ve, OnBreadcrumbCreateCallback); | ||
| } | ||
| } | ||
| break; | ||
|
|
||
| // TODO: Attach to specific events on more control types | ||
| } | ||
| } | ||
|
|
||
| private void OnApplicationOnDescendantRemoved(object? _, ElementEventArgs e) | ||
| internal void OnBreadcrumbCreateCallback(BreadcrumbEvent breadcrumb) | ||
| { | ||
| _hub.AddBreadcrumbForEvent( | ||
| _options, | ||
| breadcrumb.Sender, | ||
| breadcrumb.EventName, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jamescrosswell I'm sorry for this late review but I just realized there's a huge bug here. What about Also I don't find the I think that this could be more convenient:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch @albyrock87 - I've added #4252 to track this: |
||
| UserType, | ||
| UserActionCategory | ||
| ); | ||
| } | ||
|
|
||
| internal void OnApplicationOnDescendantRemoved(object? _, ElementEventArgs e) | ||
| { | ||
| // All elements have a set of common events we can hook | ||
| HandleElementEvents(e.Element, bind: false); | ||
|
|
@@ -127,8 +144,14 @@ private void OnApplicationOnDescendantRemoved(object? _, ElementEventArgs e) | |
| case Page page: | ||
| HandlePageEvents(page, bind: false); | ||
| break; | ||
| case Button button: | ||
| HandleButtonEvents(button, bind: false); | ||
| default: | ||
| if (e.Element is VisualElement ve) | ||
| { | ||
| foreach (var binder in _elementEventBinders) | ||
| { | ||
| binder.UnBind(ve); | ||
| } | ||
| } | ||
| break; | ||
| } | ||
| } | ||
|
|
@@ -279,22 +302,6 @@ internal void HandlePageEvents(Page page, bool bind = true) | |
| } | ||
| } | ||
|
|
||
| internal void HandleButtonEvents(Button button, bool bind = true) | ||
| { | ||
| if (bind) | ||
| { | ||
| button.Clicked += OnButtonOnClicked; | ||
| button.Pressed += OnButtonOnPressed; | ||
| button.Released += OnButtonOnReleased; | ||
| } | ||
| else | ||
| { | ||
| button.Clicked -= OnButtonOnClicked; | ||
| button.Pressed -= OnButtonOnPressed; | ||
| button.Released -= OnButtonOnReleased; | ||
| } | ||
| } | ||
|
|
||
| // Application Events | ||
|
|
||
| private void OnApplicationOnPageAppearing(object? sender, Page page) => | ||
|
|
@@ -424,15 +431,4 @@ private void OnPageOnNavigatedTo(object? sender, NavigatedToEventArgs e) => | |
|
|
||
| private void OnPageOnLayoutChanged(object? sender, EventArgs _) => | ||
| _hub.AddBreadcrumbForEvent(_options, sender, nameof(Page.LayoutChanged), SystemType, RenderingCategory); | ||
|
|
||
| // Button Events | ||
|
|
||
| private void OnButtonOnClicked(object? sender, EventArgs _) => | ||
| _hub.AddBreadcrumbForEvent(_options, sender, nameof(Button.Clicked), UserType, UserActionCategory); | ||
|
|
||
| private void OnButtonOnPressed(object? sender, EventArgs _) => | ||
| _hub.AddBreadcrumbForEvent(_options, sender, nameof(Button.Pressed), UserType, UserActionCategory); | ||
|
|
||
| private void OnButtonOnReleased(object? sender, EventArgs _) => | ||
| _hub.AddBreadcrumbForEvent(_options, sender, nameof(Button.Released), UserType, UserActionCategory); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| namespace Sentry.Maui.Internal; | ||
|
|
||
| /// <inheritdoc /> | ||
| public class MauiImageButtonEventsBinder : IMauiElementEventBinder | ||
| { | ||
| private Action<BreadcrumbEvent>? addBreadcrumbCallback; | ||
|
|
||
| /// <inheritdoc /> | ||
| public void Bind(VisualElement element, Action<BreadcrumbEvent> addBreadcrumb) | ||
| { | ||
| addBreadcrumbCallback = addBreadcrumb; | ||
|
|
||
| if (element is ImageButton image) | ||
| { | ||
| image.Clicked += OnButtonOnClicked; | ||
| image.Pressed += OnButtonOnPressed; | ||
| image.Released += OnButtonOnReleased; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public void UnBind(VisualElement element) | ||
| { | ||
| if (element is ImageButton image) | ||
| { | ||
| image.Clicked -= OnButtonOnClicked; | ||
| image.Pressed -= OnButtonOnPressed; | ||
| image.Released -= OnButtonOnReleased; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| private void OnButtonOnClicked(object? sender, EventArgs _) | ||
| => addBreadcrumbCallback?.Invoke(new(sender, nameof(ImageButton.Clicked))); | ||
|
|
||
| private void OnButtonOnPressed(object? sender, EventArgs _) | ||
| => addBreadcrumbCallback?.Invoke(new(sender, nameof(ImageButton.Pressed))); | ||
|
|
||
| private void OnButtonOnReleased(object? sender, EventArgs _) | ||
| => addBreadcrumbCallback?.Invoke(new(sender, nameof(ImageButton.Released))); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.