Skip to content

Commit

Permalink
Fix iOS long press not firing
Browse files Browse the repository at this point in the history
I was lazily using the oncontextmenu event to do long press, however this does not fire on iOS.

This commit switches to using a custom long press based on timers and pointer events (similar to what we do elsewhere).

As part of this I noticed that the dialog will be cancelled immediately on long press in iOS due to it firing some pointer events when the user hasn't moved enough.  To fix this, I just disabled scrim cancellation in those dialogs which are triggered by long press.

Fixes #263
  • Loading branch information
LiamMorrow committed Sep 7, 2024
1 parent 9d8f973 commit 51e019c
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 18 deletions.
4 changes: 2 additions & 2 deletions LiftLog.Ui/Pages/History/HistoryPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ else
OnDateSelect=CreateSessionAtDate
OnSessionLongPress=@((session)=>{_selectedSession = session; _deleteDialog?.Open();}) />
</Card>
<CardList CardType=Card.CardType.Outlined Items="filteredToMonthSessions" TItem="Session" OnClick="HandleSessionClick" OnContextMenu=@((item)=>{_selectedSession = item; _deleteDialog?.Open();}) >
<CardList CardType=Card.CardType.Outlined Items="filteredToMonthSessions" TItem="Session" OnClick="HandleSessionClick" OnLongPress=@((item)=>{_selectedSession = item; _deleteDialog?.Open();}) >
<SplitCardControl>
<TitleContent>
<SessionSummaryTitle IsFilled="true" Session="context" ></SessionSummaryTitle>
Expand All @@ -56,7 +56,7 @@ else
}
}

<ConfirmationDialog @ref="_deleteDialog" OkText="Delete" OnOk=DeleteSession>
<ConfirmationDialog @ref="_deleteDialog" OkText="Delete" OnOk=DeleteSession PreventCancel=true >
<Headline>Delete Session?</Headline>
<TextContent>
The session named <span class="font-bold text-primary">@_selectedSession.Blueprint.Name</span>,
Expand Down
55 changes: 49 additions & 6 deletions LiftLog.Ui/Shared/Presentation/Card.razor
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
@inject IJSRuntime JsRuntime
@inject IHapticFeedbackService HapticFeedback

<div
class="@(AdditionalAttributes?.GetValueOrDefault("class")) @(HasPadding ?"p-5":"") relative @Style rounded-card text-on-surface card"
@onclick="HandleOnClick"
@oncontextmenu=OnContextMenu @oncontextmenu:preventDefault=@(OnContextMenu.HasDelegate)
@onpointercancel=OnPointerLeave
@onpointerdown="OnPointerDown"
@onpointerleave="OnPointerLeave"
@onclick="OnPointerUp"
@oncontextmenu:preventDefault=true
>

@if (OnClick != null)
Expand All @@ -21,9 +25,9 @@
[Parameter] public RenderFragment ChildContent { get; set; } = null!;
[Parameter] public Action<MouseEventArgs>? OnClick { get; set; }
[Parameter] public Action? OnClick { get; set; }
[Parameter] public EventCallback OnContextMenu { get; set; }
[Parameter] public EventCallback OnLongPress { get; set; }
[Parameter] public bool IsHighlighted { get; set; }
Expand All @@ -40,9 +44,12 @@
_ => "",
};

private void HandleOnClick(MouseEventArgs args)
private DateTime? _lastPointerDownTime;
private DateTime? _holdTime;

private async Task HandleOnClick()
{
OnClick?.Invoke(args);
OnClick?.Invoke();
}

public enum CardType
Expand All @@ -52,4 +59,40 @@
Elevated
}


async Task HandleLongPress()
{
await HapticFeedback.PerformAsync(HapticFeedbackType.LongPress);
await OnLongPress.InvokeAsync();
}

private async void OnPointerDown(PointerEventArgs args)
{
_lastPointerDownTime = DateTime.Now;
await Task.Delay(400);
if (_lastPointerDownTime is null || _lastPointerDownTime.Value.AddMilliseconds(400) > DateTime.Now) return;
_holdTime = DateTime.Now;
_lastPointerDownTime = null;
await HandleLongPress();
_holdTime = null;
}


private void OnPointerLeave(PointerEventArgs args)
{
_holdTime = null;
_lastPointerDownTime = null;
}

private async void OnPointerUp(MouseEventArgs args)
{
// On desktop holding down opens a right click menu - so this does not fire
// This results in needing to click the repcount twice after cycling. Not an issue on mobile
if (_holdTime is null)
{
await HandleOnClick();
}
_holdTime = null;
_lastPointerDownTime = null;
}
}
7 changes: 4 additions & 3 deletions LiftLog.Ui/Shared/Presentation/CardList.razor
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
@typeparam TItem

<div @attributes="AdditionalAttributes" class=" @(AdditionalAttributes?.GetValueOrDefault("class")) flex flex-col gap-2 p-2 cardlist">
@foreach (var item in Items)
{
<Card
class="@CardClass"
Type="CardType"
OnContextMenu=@(OnContextMenu.HasDelegate ? ()=>OnContextMenu.InvokeAsync(item) : default!)
OnLongPress=@(OnLongPress.HasDelegate ? ()=>OnLongPress.InvokeAsync(item) : default!)
IsHighlighted="ShouldHighlight?.Invoke(item) ?? false"
OnClick=@(OnClick != null ? _ => OnClick(item) : null)>
OnClick=@(OnClick != null ? () => OnClick(item) : null)>
@ChildContent?.Invoke(item)
</Card>
}
Expand All @@ -21,7 +22,7 @@

[Parameter] public Action<TItem>? OnClick { get; set; }

[Parameter] public EventCallback<TItem> OnContextMenu { get; set; }
[Parameter] public EventCallback<TItem> OnLongPress { get; set; }

[Parameter] public Func<TItem, bool>? ShouldHighlight { get; set; }

Expand Down
4 changes: 3 additions & 1 deletion LiftLog.Ui/Shared/Presentation/ConfirmationDialog.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

<Dialog @ref="dialog" @ondialog-cancel="OnCancel">
<Dialog @ref="dialog" @ondialog-cancel="OnCancel" type="alert" PreventCancel=@PreventCancel>
<span slot="headline">@Headline</span>
<span slot="content" class="block text-left">
@TextContent
Expand Down Expand Up @@ -32,6 +32,8 @@

[Parameter] public string SectionName { get; set; } = "Dialog";

[Parameter] public bool PreventCancel { get; set; } = false;

private Dialog? dialog;

public void Open()
Expand Down
4 changes: 3 additions & 1 deletion LiftLog.Ui/Shared/Presentation/Dialog.razor
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@

[Parameter] public string SectionName { get; set; } = "Dialog";

[Parameter] public bool PreventCancel { get; set; } = false;

public async void Open()
{
opened = true;
StateHasChanged();
await Task.Yield();
await JSRuntime.InvokeVoidAsync("AppUtils.onCloseMdPopup", dialog);
await JSRuntime.InvokeVoidAsync("AppUtils.onCloseMdPopup", dialog, PreventCancel);
await JSRuntime.InvokeVoidAsync("AppUtils.showMdPopup", dialog);
}

Expand Down
2 changes: 1 addition & 1 deletion LiftLog.Ui/Shared/Presentation/VirtualizedCardList.razor
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

private RenderFragment RenderCard(TItem item)
{
return @<Card Type=CardType IsHighlighted="ShouldHighlight?.Invoke(item) ?? false" OnClick="@(OnClick != null ? _ => OnClick(item) : null)" class="@CardClass">
return @<Card Type=CardType IsHighlighted="ShouldHighlight?.Invoke(item) ?? false" OnClick="@(OnClick != null ? () => OnClick(item) : null)" class="@CardClass">
@ChildContent?.Invoke(item)
</Card>;
}
Expand Down
2 changes: 1 addition & 1 deletion LiftLog.Ui/Shared/Smart/SessionComponent.razor
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ else
<ExerciseEditor Exercise="editingExerciseBlueprint" UpdateExercise="(ex) => {editingExerciseBlueprint = ex; StateHasChanged();}" />
</FullScreenDialog>
<Dialog @ref="setAdditionalActionsDialog">
<Dialog @ref="setAdditionalActionsDialog" PreventCancel=true>
@if(setAdditionalActions != null)
{
var exercise = Session.RecordedExercises[setAdditionalActions.Value.ExerciseIndex];
Expand Down
2 changes: 1 addition & 1 deletion LiftLog.Ui/Shared/Smart/Tips/HoldingRepCounterTip.razor
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</div>
</div>

<Dialog @ref="setAdditionalActionsDialog">
<Dialog @ref="setAdditionalActionsDialog" PreventCancel=true>
<span slot="headline" class="select-none">Select Reps</span>
<span slot="content" >
<PotentialSetAdditionalActions
Expand Down
8 changes: 6 additions & 2 deletions LiftLog.Ui/wwwroot/app-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ AppUtils.vibrate = function (ms) {
* This new event has bubbles, which allows blazor components to intercept it
* @param {HTMLElement} element
*/
AppUtils.onCloseMdPopup = function (element) {
AppUtils.onCloseMdPopup = function (element, preventCancel) {
element?.addEventListener("open", () => {
if (element?.shadowRoot) {
const scrim = element.shadowRoot.querySelector(".scrim");
Expand All @@ -36,7 +36,11 @@ AppUtils.onCloseMdPopup = function (element) {
})
);
});
element?.addEventListener("cancel", () => {
element?.addEventListener("cancel", (event) => {
if (preventCancel) {
event.preventDefault();
return;
}
element?.dispatchEvent(
new Event("dialog-cancel", {
bubbles: true,
Expand Down

0 comments on commit 51e019c

Please sign in to comment.