Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Implement SafeFireAndForgetExtensions #1054

Merged
merged 2 commits into from
Mar 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading;
using System.Threading.Tasks;
using Xamarin.CommunityToolkit.Extensions;
using Xamarin.CommunityToolkit.Helpers;
using Xamarin.Forms;
using static System.Math;

Expand All @@ -27,7 +28,7 @@ sealed class GestureManager

TouchState animationState;

internal async Task HandleTouch(TouchEffect sender, TouchStatus status)
internal void HandleTouch(TouchEffect sender, TouchStatus status)
{
if (sender.IsDisabled)
return;
Expand Down Expand Up @@ -58,11 +59,11 @@ internal async Task HandleTouch(TouchEffect sender, TouchStatus status)
? 1 - animationProgress
: animationProgress;

await UpdateStatusAndState(sender, status, state);
UpdateStatusAndState(sender, status, state);

if (status == TouchStatus.Canceled)
{
await sender.ForceUpdateState(false);
sender.ForceUpdateState(false);
return;
}

Expand All @@ -76,7 +77,7 @@ internal async Task HandleTouch(TouchEffect sender, TouchStatus status)
: TouchState.Pressed;
}

await UpdateStatusAndState(sender, status, state);
UpdateStatusAndState(sender, status, state);
}

if (status == TouchStatus.Completed)
Expand All @@ -92,7 +93,7 @@ internal void HandleUserInteraction(TouchEffect sender, TouchInteractionStatus i
}
}

internal async ValueTask HandleHover(TouchEffect sender, HoverStatus status)
internal void HandleHover(TouchEffect sender, HoverStatus status)
{
if (!sender.Element?.IsEnabled ?? true)
return;
Expand All @@ -104,7 +105,7 @@ internal async ValueTask HandleHover(TouchEffect sender, HoverStatus status)
if (sender.HoverState != hoverState)
{
sender.HoverState = hoverState;
await sender.RaiseHoverStateChanged();
sender.RaiseHoverStateChanged();
}

if (sender.HoverStatus != status)
Expand Down Expand Up @@ -140,15 +141,15 @@ internal async Task ChangeStateAsync(TouchEffect sender, bool animated)
var durationMultiplier = this.durationMultiplier;
this.durationMultiplier = null;

await GetAnimationTask(sender, state, hoverState, animationTokenSource.Token, durationMultiplier.GetValueOrDefault()).ConfigureAwait(false);
await RunAnimationTask(sender, state, hoverState, animationTokenSource.Token, durationMultiplier.GetValueOrDefault()).ConfigureAwait(false);
return;
}

var pulseCount = sender.PulseCount;

if (pulseCount == 0 || (state == TouchState.Normal && !isToggled.HasValue))
{
await GetAnimationTask(sender, state, hoverState, animationTokenSource.Token).ConfigureAwait(false);
await RunAnimationTask(sender, state, hoverState, animationTokenSource.Token).ConfigureAwait(false);
return;
}
do
Expand All @@ -157,15 +158,15 @@ internal async Task ChangeStateAsync(TouchEffect sender, bool animated)
? TouchState.Normal
: TouchState.Pressed;

await GetAnimationTask(sender, rippleState, hoverState, animationTokenSource.Token);
await RunAnimationTask(sender, rippleState, hoverState, animationTokenSource.Token);
if (token.IsCancellationRequested)
return;

rippleState = isToggled.HasValue && isToggled.Value
? TouchState.Pressed
: TouchState.Normal;

await GetAnimationTask(sender, rippleState, hoverState, animationTokenSource.Token);
await RunAnimationTask(sender, rippleState, hoverState, animationTokenSource.Token);
if (token.IsCancellationRequested)
return;
}
Expand Down Expand Up @@ -269,12 +270,12 @@ internal void AbortAnimations(TouchEffect sender)
element.AbortAnimations();
}

async ValueTask UpdateStatusAndState(TouchEffect sender, TouchStatus status, TouchState state)
void UpdateStatusAndState(TouchEffect sender, TouchStatus status, TouchState state)
{
if (sender.State != state || status != TouchStatus.Canceled)
{
sender.State = state;
await sender.RaiseStateChanged();
sender.RaiseStateChanged();
}

sender.Status = status;
Expand Down Expand Up @@ -586,7 +587,7 @@ Color GetBackgroundColor(Color color)
? color
: defaultBackgroundColor;

Task GetAnimationTask(TouchEffect sender, TouchState touchState, HoverState hoverState, CancellationToken token, double? durationMultiplier = null)
Task RunAnimationTask(TouchEffect sender, TouchState touchState, HoverState hoverState, CancellationToken token, double? durationMultiplier = null)
{
if (sender.Element == null)
return Task.FromResult(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Android.Content;
using Android.Content.Res;
using Android.Graphics.Drawables;
Expand All @@ -12,7 +11,6 @@
using Xamarin.CommunityToolkit.Effects;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using AndroidOS = Android.OS;
using AView = Android.Views.View;
using Color = Android.Graphics.Color;

Expand Down Expand Up @@ -161,7 +159,7 @@ void UpdateClickHandler()
}
}

async void OnTouch(object? sender, AView.TouchEventArgs e)
void OnTouch(object? sender, AView.TouchEventArgs e)
{
e.Handled = false;

Expand All @@ -174,47 +172,51 @@ async void OnTouch(object? sender, AView.TouchEventArgs e)
switch (e.Event?.ActionMasked)
{
case MotionEventActions.Down:
await OnTouchDown(e);
OnTouchDown(e);
break;
case MotionEventActions.Up:
await OnTouchUp();
OnTouchUp();
break;
case MotionEventActions.Cancel:
await OnTouchCancel();
OnTouchCancel();
break;
case MotionEventActions.Move:
await OnTouchMove(sender, e);
OnTouchMove(sender, e);
break;
case MotionEventActions.HoverEnter:
await OnHoverEnter();
OnHoverEnter();
break;
case MotionEventActions.HoverExit:
await OnHoverExit();
OnHoverExit();
break;
}
}

async Task OnTouchDown(AView.TouchEventArgs e)
void OnTouchDown(AView.TouchEventArgs e)
{
_ = e.Event ?? throw new NullReferenceException();

IsCanceled = false;

startX = e.Event.GetX();
startY = e.Event.GetY();

effect?.HandleUserInteraction(TouchInteractionStatus.Started);
await (effect?.HandleTouch(TouchStatus.Started) ?? Task.CompletedTask);
effect?.HandleTouch(TouchStatus.Started);

StartRipple(e.Event.GetX(), e.Event.GetY());

if (effect?.DisallowTouchThreshold > 0)
Group?.Parent?.RequestDisallowInterceptTouchEvent(true);
}

Task OnTouchUp()
void OnTouchUp()
=> HandleEnd(effect?.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled);

Task OnTouchCancel()
void OnTouchCancel()
=> HandleEnd(TouchStatus.Canceled);

async Task OnTouchMove(object? sender, AView.TouchEventArgs e)
void OnTouchMove(object? sender, AView.TouchEventArgs e)
{
if (IsCanceled || e.Event == null)
return;
Expand All @@ -226,7 +228,7 @@ async Task OnTouchMove(object? sender, AView.TouchEventArgs e)
var disallowTouchThreshold = effect?.DisallowTouchThreshold;
if (disallowTouchThreshold > 0 && maxDiff > disallowTouchThreshold)
{
await HandleEnd(TouchStatus.Canceled);
HandleEnd(TouchStatus.Canceled);
return;
}

Expand All @@ -239,11 +241,11 @@ async Task OnTouchMove(object? sender, AView.TouchEventArgs e)

if (isHoverSupported && ((status == TouchStatus.Canceled && effect?.HoverStatus == HoverStatus.Entered)
|| (status == TouchStatus.Started && effect?.HoverStatus == HoverStatus.Exited)))
await effect.HandleHover(status == TouchStatus.Started ? HoverStatus.Entered : HoverStatus.Exited);
effect.HandleHover(status == TouchStatus.Started ? HoverStatus.Entered : HoverStatus.Exited);

if (effect?.Status != status)
{
await (effect?.HandleTouch(status) ?? Task.CompletedTask);
effect?.HandleTouch(status);

if (status == TouchStatus.Started)
StartRipple(e.Event.GetX(), e.Event.GetY());
Expand All @@ -252,23 +254,23 @@ async Task OnTouchMove(object? sender, AView.TouchEventArgs e)
}
}

async ValueTask OnHoverEnter()
void OnHoverEnter()
{
isHoverSupported = true;

if (effect != null)
await effect.HandleHover(HoverStatus.Entered);
effect.HandleHover(HoverStatus.Entered);
}

async ValueTask OnHoverExit()
void OnHoverExit()
{
isHoverSupported = true;

if (effect != null)
await effect.HandleHover(HoverStatus.Exited);
effect.HandleHover(HoverStatus.Exited);
}

async void OnClick(object? sender, EventArgs args)
void OnClick(object? sender, EventArgs args)
{
if (effect?.IsDisabled ?? true)
return;
Expand All @@ -277,10 +279,10 @@ async void OnClick(object? sender, EventArgs args)
return;

IsCanceled = false;
await HandleEnd(TouchStatus.Completed);
HandleEnd(TouchStatus.Completed);
}

async Task HandleEnd(TouchStatus status)
void HandleEnd(TouchStatus status)
{
if (IsCanceled)
return;
Expand All @@ -289,7 +291,7 @@ async Task HandleEnd(TouchStatus status)
if (effect?.DisallowTouchThreshold > 0)
Group?.Parent?.RequestDisallowInterceptTouchEvent(false);

await (effect?.HandleTouch(status) ?? Task.CompletedTask);
effect?.HandleTouch(status);

effect?.HandleUserInteraction(TouchInteractionStatus.Completed);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected override void OnAttached()

if (XCT.IsiOS13OrNewer)
{
hoverGesture = new UIHoverGestureRecognizer(async () => await OnHover());
hoverGesture = new UIHoverGestureRecognizer(OnHover);
View.AddGestureRecognizer(hoverGesture);
}

Expand Down Expand Up @@ -79,7 +79,7 @@ protected override void OnDetached()
effect = null;
}

async ValueTask OnHover()
void OnHover()
{
if (effect == null || effect.IsDisabled)
return;
Expand All @@ -88,10 +88,10 @@ async ValueTask OnHover()
{
case UIGestureRecognizerState.Began:
case UIGestureRecognizerState.Changed:
await effect.HandleHover(HoverStatus.Entered);
effect.HandleHover(HoverStatus.Entered);
break;
case UIGestureRecognizerState.Ended:
await effect.HandleHover(HoverStatus.Exited);
effect.HandleHover(HoverStatus.Exited);
break;
}
}
Expand Down Expand Up @@ -126,38 +126,44 @@ public TouchUITapGestureRecognizer(TouchEffect effect)

UIView? Renderer => (UIView?)effect?.Element.GetRenderer();

public override async void TouchesBegan(NSSet touches, UIEvent evt)
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
if (effect?.IsDisabled ?? true)
return;

IsCanceled = false;
startPoint = GetTouchPoint(touches);
await HandleTouch(TouchStatus.Started, TouchInteractionStatus.Started);

HandleTouch(TouchStatus.Started, TouchInteractionStatus.Started).SafeFireAndForget();

base.TouchesBegan(touches, evt);
}

public override async void TouchesEnded(NSSet touches, UIEvent evt)
public override void TouchesEnded(NSSet touches, UIEvent evt)
{
if (effect?.IsDisabled ?? true)
return;

await HandleTouch(effect?.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled, TouchInteractionStatus.Completed);
HandleTouch(effect?.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled, TouchInteractionStatus.Completed).SafeFireAndForget();

IsCanceled = true;

base.TouchesEnded(touches, evt);
}

public override async void TouchesCancelled(NSSet touches, UIEvent evt)
public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
if (effect?.IsDisabled ?? true)
return;

await HandleTouch(TouchStatus.Canceled, TouchInteractionStatus.Completed);
HandleTouch(TouchStatus.Canceled, TouchInteractionStatus.Completed).SafeFireAndForget();

IsCanceled = true;

base.TouchesCancelled(touches, evt);
}

public override async void TouchesMoved(NSSet touches, UIEvent evt)
public override void TouchesMoved(NSSet touches, UIEvent evt)
{
if (effect?.IsDisabled ?? true)
return;
Expand All @@ -171,7 +177,7 @@ public override async void TouchesMoved(NSSet touches, UIEvent evt)
var maxDiff = Math.Max(diffX, diffY);
if (maxDiff > disallowTouchThreshold)
{
await HandleTouch(TouchStatus.Canceled, TouchInteractionStatus.Completed);
HandleTouch(TouchStatus.Canceled, TouchInteractionStatus.Completed).SafeFireAndForget();
IsCanceled = true;
base.TouchesMoved(touches, evt);
return;
Expand All @@ -183,7 +189,7 @@ public override async void TouchesMoved(NSSet touches, UIEvent evt)
: TouchStatus.Canceled;

if (effect?.Status != status)
await HandleTouch(status);
HandleTouch(status).SafeFireAndForget();

base.TouchesMoved(touches, evt);
}
Expand Down Expand Up @@ -216,7 +222,7 @@ public async Task HandleTouch(TouchStatus status, TouchInteractionStatus? intera
interactionStatus = null;
}

await (effect?.HandleTouch(status) ?? Task.CompletedTask);
effect?.HandleTouch(status);
if (interactionStatus.HasValue)
effect?.HandleUserInteraction(interactionStatus.Value);

Expand Down
Loading