using Connected.Annotations; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; namespace Connected.Components; public partial class SwipeArea : UIComponent { internal double? _xDown, _yDown; private double? _swipeDelta; internal ElementReference _componentRef; private static readonly string[] _preventDefaultEventNames = { "touchstart", "touchend", "touchcancel" }; internal int[] _listenerIds; [Parameter] [Category(CategoryTypes.SwipeArea.Behavior)] public RenderFragment ChildContent { get; set; } [Parameter] [Category(CategoryTypes.SwipeArea.Behavior)] public Action OnSwipe { get; set; } /// /// Swipe threshold in pixels. If SwipeDelta is below Sensitivity then OnSwipe is not called. /// [Parameter] [Category(CategoryTypes.SwipeArea.Behavior)] public int Sensitivity { get; set; } = 100; /// /// Prevents default behavior of the browser when swiping. /// Usable espacially when swiping up/down - this will prevent the whole page from scrolling up/down. /// [Parameter] [Category(CategoryTypes.SwipeArea.Behavior)] public bool PreventDefault { get; set; } private bool _preventDefaultChanged; public override async Task SetParametersAsync(ParameterView parameters) { var preventDefault = parameters.GetValueOrDefault(nameof(PreventDefault)); if (preventDefault != PreventDefault) { _preventDefaultChanged = true; } await base.SetParametersAsync(parameters); } private async Task SetPreventDefaultInternal(bool value) { if (value) { _listenerIds = await _componentRef.AddDefaultPreventingHandlers(_preventDefaultEventNames); } else { if (_listenerIds != null) { await _componentRef.RemoveDefaultPreventingHandlers(_preventDefaultEventNames, _listenerIds); _listenerIds = null; } } } protected override async Task OnAfterRenderAsync(bool firstRender) { if (_preventDefaultChanged) { _preventDefaultChanged = false; await SetPreventDefaultInternal(PreventDefault); } } private void OnTouchStart(TouchEventArgs arg) { _xDown = arg.Touches[0].ClientX; _yDown = arg.Touches[0].ClientY; } internal void OnTouchEnd(TouchEventArgs arg) { if (_xDown == null || _yDown == null) return; var xDiff = _xDown.Value - arg.ChangedTouches[0].ClientX; var yDiff = _yDown.Value - arg.ChangedTouches[0].ClientY; if (Math.Abs(xDiff) < Sensitivity && Math.Abs(yDiff) < Sensitivity) { _xDown = _yDown = null; return; } if (Math.Abs(xDiff) > Math.Abs(yDiff)) { if (xDiff > 0) { InvokeAsync(() => OnSwipe(SwipeDirection.RightToLeft)); } else { InvokeAsync(() => OnSwipe(SwipeDirection.LeftToRight)); } _swipeDelta = xDiff; } else { if (yDiff > 0) { InvokeAsync(() => OnSwipe(SwipeDirection.BottomToTop)); } else { InvokeAsync(() => OnSwipe(SwipeDirection.TopToBottom)); } _swipeDelta = yDiff; } _xDown = _yDown = null; } /// /// The last successful swipe difference in pixels since the last OnSwipe invocation /// public double? GetSwipeDelta() => _swipeDelta; internal void OnTouchCancel(TouchEventArgs arg) { _xDown = _yDown = null; } }