Rivista UI

This commit is contained in:
2025-06-12 12:57:34 +02:00
parent 79fb383961
commit 0032648e76
22 changed files with 437 additions and 297 deletions

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Template.Maui"
xmlns:android="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific;assembly=Microsoft.Maui.Controls"
android:Application.WindowSoftInputModeAdjust="Resize"
x:Class="Template.Maui.App">
<Application.Resources>
<ResourceDictionary>

View File

@@ -3,6 +3,7 @@ using IntegryApiClient.MAUI;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.Logging;
using MudBlazor.Services;
using MudExtensions.Services;
using Template.Maui.Core.Services;
using Template.Shared;
using Template.Shared.Core.Helpers;
@@ -32,6 +33,7 @@ namespace Template.Maui
builder.Services.AddMauiBlazorWebView();
builder.Services.AddMudServices();
builder.Services.AddMudExtensions();
builder.Services.AddAutoMapper(typeof(MappingProfile));

View File

@@ -13,6 +13,7 @@
<link href="_content/Template.Shared/css/bootstrap/bootstrap.min.css" rel="stylesheet">
<link href="_content/Template.Shared/css/bootstrap/bootstrap-icons.min.css" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<link href="_content/CodeBeam.MudBlazor.Extensions/MudExtensions.min.css" rel="stylesheet" />
<link rel="stylesheet" href="_content/Template.Shared/css/remixicon/remixicon.css" />
<link rel="stylesheet" href="_content/Template.Shared/css/app.css" />
@@ -42,6 +43,7 @@
<!-- Add sortable.js reference if SortableList component is used in your application. -->
<!--<script src="_content/Template.Shared/js/bootstrap/Sortable.min.js"></script>-->
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script src="_content/CodeBeam.MudBlazor.Extensions/MudExtensions.min.js"></script>
<script src="_content/Template.Shared/js/main.js"></script>
<script src="_content/Template.Shared/js/calendar.js"></script>

View File

@@ -1,6 +1,6 @@
@inject IJSRuntime JS
<div class="header">
<div class="container header">
<div class="header-content @(Back ? "with-back" : "no-back")">
@if (Back)
{
@@ -26,7 +26,7 @@
}
@if (ShowNotifications)
{
<MudIconButton Icon="@Icons.Material.Filled.Notifications" Color="Color.Dark"/>
@* <MudIconButton Icon="@Icons.Material.Filled.Notifications" Color="Color.Dark"/> *@
}
@if (ShowCalendarToggle)
{
@@ -54,6 +54,7 @@
[Parameter] public string BackTo { get; set; } = "";
[Parameter] public bool Cancel { get; set; }
[Parameter] public EventCallback OnCancel { get; set; }
[Parameter] public string? LabelSave { get; set; }
[Parameter] public EventCallback OnSave { get; set; }
@@ -68,7 +69,14 @@
private async Task GoBack()
{
if (Cancel)
{
await OnCancel.InvokeAsync();
return;
}
await JS.InvokeVoidAsync("goBack");
}
}

View File

@@ -12,7 +12,7 @@
<NavMenu />
<main>
<article class="container">
<article>
@Body
</article>
</main>

View File

@@ -1,14 +1,16 @@
@inject IDialogService Dialog
@if (IsVisible)
{
<nav class="navbar navbar-expand justify-content-center">
<div class="container-fluid">
<ul class="navbar-nav nav-justified w-100 text-center">
<div class="container-navbar">
<ul class="navbar-nav nav-justified align-items-center w-100 text-center">
<li class="nav-item">
<NavLink class="nav-link" href="Users" Match="NavLinkMatch.All">
<div class="d-flex flex-column">
<i class="ri-group-line"></i>
<span>Contatti</span>
@* <span>Contatti</span> *@
</div>
</NavLink>
</li>
@@ -16,7 +18,28 @@
<NavLink class="nav-link" href="Calendar" Match="NavLinkMatch.All">
<div class="d-flex flex-column">
<i class="ri-calendar-todo-line"></i>
<span>Agenda</span>
@* <span>Agenda</span> *@
</div>
</NavLink>
</li>
<li class="nav-item plus-button">
<MudMenu PopoverClass="custom_popover" AnchorOrigin="Origin.TopCenter" TransformOrigin="Origin.BottomCenter">
<ActivatorContent>
<MudFab Class="custom-plus-button" Color="Color.Primary" Size="Size.Medium" IconSize="Size.Medium" StartIcon="@Icons.Material.Filled.Add"/>
</ActivatorContent>
<ChildContent>
<MudMenuItem Disabled="true">Nuovo contatto</MudMenuItem>
<MudMenuItem OnClick="() => ModalHelpers.OpenActivityForm(Dialog)">Nuova attivit<69></MudMenuItem>
</ChildContent>
</MudMenu>
</li>
<li class="nav-item">
<NavLink class="nav-link" href="Notification" Match="NavLinkMatch.All">
<div class="d-flex flex-column">
<i class="ri-notification-4-line"></i>
</div>
</NavLink>
</li>
@@ -24,7 +47,7 @@
<NavLink class="nav-link" href="PersonalInfo" Match="NavLinkMatch.All">
<div class="d-flex flex-column">
<i class="ri-user-line"></i>
<span>Profilo</span>
@* <span>Profilo</span> *@
</div>
</NavLink>
</li>

View File

@@ -1,21 +1,43 @@
.navbar {
background: var(--mud-palette-surface);
background: transparent;
position: fixed;
bottom: 0;
width: 100%;
z-index: 1001;
border-top: 1px solid var(--card-border-color);
padding-bottom: 1rem;
padding-top: 0 !important;
}
.navbar-expand { padding: 0 !important; }
.container-navbar {
background: var(--mud-palette-surface);
border-radius: 15px;
box-shadow: var(--custom-box-shadow);
}
.nav-item { font-size: 0.9rem; }
.nav-item.plus-button {
position: relative;
bottom: 15px;
}
.nav-item ::deep .custom-plus-button .mud-icon-root {
transition: .513s;
transform: rotate(0);
font-size: 2rem;
}
.nav-item ::deep .custom-plus-button:focus .mud-icon-root {
transform: rotate(225deg);
}
.nav-item ::deep a {
display: flex;
align-items: center;
line-height: 1.2;
justify-content: center;
padding-top: .5rem !important;
padding-bottom: .5rem !important;
}
.nav-item ::deep a > div {
@@ -24,7 +46,7 @@
min-width: 60px;
}
.nav-item ::deep a.active > div { color: var(--mud-palette-secondary-darken); }
.nav-item ::deep a.active > div { color: var(--mud-palette-primary); }
.nav-item ::deep a.active > div > i {
/*background-color: color-mix(in srgb, var(--mud-palette-primary) 20%, transparent);*/
@@ -33,9 +55,11 @@
.nav-item ::deep a.active > div > span { font-weight: 800; }
.nav-item ::deep a:not(.active) > div { color: var(--mud-palette-drawer-icon); }
.nav-item ::deep a:not(.active) > div {
color: var(--mud-palette-text-primary);
}
.nav-item ::deep a i { font-size: 1.5rem; }
.nav-item ::deep a i { font-size: 1.65rem; }
.nav-item ::deep a span {
font-size: 0.8rem;

View File

@@ -1,12 +1,11 @@
@page "/activity"
@page "/activity/{Id}"
@using Template.Shared.Core.Dto
@using Template.Shared.Core.Dto
@using Template.Shared.Components.Layout
@using Template.Shared.Core.Interface
@inject NavigationManager NavigationManager
@inject IManageDataService manageData
<HeaderLayout Cancel="true" LabelSave="@LabelSave" ShowNotifications="false" Title="@(IsNew ? "Nuova" : $"{ActivityModel.ActivityId}")"/>
<MudDialog Class="customDialog-form">
<DialogContent>
<HeaderLayout Cancel="true" OnCancel="() => MudDialog.Cancel()" LabelSave="@LabelSave" ShowNotifications="false" Title="@(IsNew ? "Nuova" : $"{ActivityModel.ActivityId}")" />
<div class="content">
<div class="input-card">
@@ -86,17 +85,13 @@
<div class="input-card">
<MudTextField T="string?" Placeholder="Note" Variant="Variant.Text" Lines="4" @bind-Value="ActivityModel.Note" @bind-Value:after="OnAfterChangeValue" />
</div>
<MudOverlay @bind-Visible="_selectEstimatedTime" DarkBackground="true" AutoClose="true">
<MudDatePicker @bind-Date:after="CloseDatePicker" @bind-Date="ActivityModel.EstimatedTime" PickerVariant="PickerVariant.Static"/>
</MudOverlay>
<MudOverlay @bind-Visible="_selectEstimatedEndTime" DarkBackground="true" AutoClose="true">
<MudDatePicker @bind-Date:after="CloseDatePicker" @bind-Date="ActivityModel.EstimatedEndtime" PickerVariant="PickerVariant.Static"/>
</MudOverlay>
</div>
</DialogContent>
</MudDialog>
@code {
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; }
[Parameter] public string? Id { get; set; }
private ActivityDTO OriginalModel { get; set; } = new();
@@ -125,18 +120,6 @@
OriginalModel = ActivityModel.Clone();
}
private async Task HandleValidSubmit()
{
// Salva su database (qui simulato)
await Task.Delay(200);
NavigationManager.NavigateTo("/attivita");
}
private void Annulla()
{
NavigationManager.NavigateTo("/attivita");
}
private void OnAfterChangeValue()
{
if (OriginalModel.Equals(ActivityModel))
@@ -145,13 +128,4 @@
StateHasChanged();
}
private async Task CloseDatePicker()
{
await Task.Delay(150);
_selectEstimatedTime = false;
_selectEstimatedEndTime = false;
StateHasChanged();
}
}

View File

@@ -1,3 +1,14 @@
.customDialog-form .content ::deep {
height: calc(100vh - (.6rem + 40px));
overflow: auto;
-ms-overflow-style: none;
scrollbar-width: none;
}
.customDialog-form .content::-webkit-scrollbar {
display: none;
}
.input-card {
width: 100%;
background: var(--mud-palette-background-gray);

View File

@@ -5,6 +5,7 @@
@using Template.Shared.Components.SingleElements
@using Template.Shared.Components.Layout.Spinner
@inject IManageDataService manageData
@inject IDialogService Dialog
@inject IJSRuntime JS
<HeaderLayout Title="@CurrentMonth.ToString("MMMM yyyy", new System.Globalization.CultureInfo("it-IT")).FirstCharToUpper()"
@@ -12,7 +13,7 @@
ShowCalendarToggle="true"
OnCalendarToggle="ToggleExpanded"/>
<div @ref="weekSliderRef" class="week-slider @(Expanded ? "expanded" : "") @(SliderAnimation)">
<div @ref="weekSliderRef" class="container week-slider @(Expanded ? "expanded" : "") @(SliderAnimation)">
@if (Expanded)
{
<!-- Vista mensile -->
@@ -83,17 +84,16 @@
}
</div>
<div class="appointments">
<div class="container appointments">
@if (IsLoading)
{
<SpinnerLayout FullScreen="false"/>
}
else if (FilteredActivities is { Count: > 0 })
{
@foreach (var activity in FilteredActivities)
{
<Virtualize Items="FilteredActivities" Context="activity">
<ActivityCard Activity="activity" />
}
</Virtualize>
}
else
{
@@ -176,6 +176,20 @@
}
}
[JSInvokable]
public async Task OnSwipeDown()
{
if (!Expanded)
ToggleExpanded();
}
[JSInvokable]
public async Task OnSwipeUp()
{
if (Expanded)
ToggleExpanded();
}
// Cambio periodo mese/settimana
private async Task CambiaPeriodo(int direzione)
{
@@ -292,5 +306,4 @@
{
dotNetHelper?.Dispose();
}
}

View File

@@ -20,7 +20,8 @@
justify-content: center;
align-items: flex-start;
gap: 0.6rem;
padding: 1rem 0.3rem;
padding-top: 1rem;
padding-bottom: 1rem;
overflow-x: hidden;
overflow-y: visible;
}
@@ -106,8 +107,8 @@
}
.day.selected {
background: var(--mud-palette-primary);
border: 1px solid var(--mud-palette-primary);
background: var(--mud-palette-secondary);
border: 1px solid var(--mud-palette-secondary);
color: white;
}
@@ -118,9 +119,10 @@
gap: 1rem;
overflow-y: auto;
flex-direction: column;
height: 70vh;
height: 75vh;
-ms-overflow-style: none;
scrollbar-width: none;
padding-bottom: 45px;
}
.appointments::-webkit-scrollbar { display: none; }
@@ -141,10 +143,6 @@
cursor: pointer;
}
.day.selected > .event-dot-container {
display: none;
}
.event-dot-container {
display: flex;
gap: 5px;

View File

@@ -4,17 +4,17 @@
@using Template.Shared.Core.Authorization.Enum
@using Template.Shared.Core.Interface
@using Template.Shared.Core.Services
@using Template.Shared.Core.Utility
@inject AppAuthenticationStateProvider AuthenticationStateProvider
@inject INetworkService NetworkService
@inject IFormFactor FormFactor
<HeaderLayout Title="Profilo"/>
<div class="content">
<div class="container content">
<div class="container-primary-info">
<div class="section-primary-info">
<MudAvatar Style="height:85px; width:85px; font-size:2rem;">
<MudImage Src="@($"https://ui-avatars.com/api/?name={UserSession.User.Username}&size=80&background={UtilityColor.CalcHexColor(UserSession.User.Username)}&bold=true")"></MudImage>
<MudAvatar Style="height: 70px; width: 70px; font-size: 2rem; font-weight: bold" Color="Color.Secondary">
@UtilityString.ExtractInitials(UserSession.User.Fullname)
</MudAvatar>
<div class="personal-info">
@@ -26,6 +26,8 @@
</div>
</div>
<div class="divider"></div>
<div class="section-info">
<div class="section-personal-info">
<div>
@@ -73,22 +75,40 @@
</div>
</div>
</div>
</div>
<MudButton Class="user-button"
<div class="container-button">
<MudButton Class="button-settings green-icon"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
StartIcon="@Icons.Material.Outlined.Settings"
OnClick="OpenSettings"
Variant="Variant.Outlined">Impostazioni</MudButton>
OnClick="() => UpdateDb(true)"
Variant="Variant.Outlined">
Sincronizza
</MudButton>
<div class="divider"></div>
<MudButton FullWidth="true"
StartIcon="@Icons.Material.Outlined.Logout"
<MudButton Class="button-settings red-icon"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
OnClick="() => UpdateDb()"
Variant="Variant.Outlined">
Ripristina dati
</MudButton>
</div>
<div class="container-button">
<MudButton Class="button-settings exit"
FullWidth="true"
Color="Color.Error"
Size="Size.Medium"
OnClick="Logout"
Variant="Variant.Outlined">Esci</MudButton>
Variant="Variant.Outlined">
Esci
</MudButton>
</div>
</div>
@code {
@@ -117,4 +137,19 @@
private void Logout() =>
AuthenticationStateProvider.SignOut();
private void UpdateDb(bool withData = false)
{
var absoluteUri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);
var pathAndQuery = absoluteUri.Segments.Length > 1 ? absoluteUri.PathAndQuery : null;
string path;
if (withData)
path = pathAndQuery == null ? $"/sync/{DateTime.Today:yyyy-MM-dd}" : $"/sync/{DateTime.Today:yyyy-MM-dd}?path=" + System.Web.HttpUtility.UrlEncode(pathAndQuery);
else
path = pathAndQuery == null ? "/sync" : "/sync?path=" + System.Web.HttpUtility.UrlEncode(pathAndQuery);
NavigationManager.NavigateTo(path, replace: true);
}
}

View File

@@ -1,15 +1,28 @@
.container-primary-info {
box-shadow: var(--custom-box-shadow);
width: 100%;
margin-bottom: 2rem;
border-radius: 12px;
}
.container-primary-info .divider {
margin: 0 0 0 7rem;
width: unset;
}
.section-primary-info {
display: flex;
flex-direction: column;
flex-direction: row;
align-items: center;
gap: 1.5rem;
padding: .8rem 1.2rem .4rem;
}
.personal-info {
display: flex;
flex-direction: column;
align-items: center;
align-items: flex-start;
line-height: normal;
margin: .2rem 0 1rem 0;
}
.info-nome {
@@ -25,15 +38,10 @@
}
.section-info {
width: 100%;
margin-bottom: 1.5rem;
border-radius: 12px;
display: flex;
justify-content: space-between;
flex-direction: row;
padding: .8rem 1.2rem;
border: 1px solid var(--card-border-color);
box-shadow: var(--card-shadow);
padding: .4rem 1.2rem .8rem;
}
.section-personal-info {
@@ -59,9 +67,7 @@
font-size: small;
}
.content ::deep .user-button {
border: 1px solid var(--card-border-color) !important;
}
.content ::deep .user-button { border: 1px solid var(--card-border-color) !important; }
.user-button > i { font-size: large; }
@@ -70,14 +76,50 @@
font-weight: 600;
}
.status {
font-weight: 700;
.status { font-weight: 700; }
.status.online { color: var(--mud-palette-success); }
.status.offline { color: var(--mud-palette-error); }
.container-button {
width: 100%;
box-shadow: var(--custom-box-shadow);
padding: .5rem 0;
border-radius: 12px;
margin-bottom: 2rem;
}
.status.online {
color: var(--mud-palette-success);
.container-button .divider {
margin: .5rem 0 .5rem 3rem;
width: unset;
}
.status.offline {
color: var(--mud-palette-error);
.container-button ::deep .button-settings { border: none !important; }
.container-button ::deep .button-settings .mud-icon-root {
border: 1px solid var(--mud-palette-gray-light);
border-radius: 6px;
padding: 2px;
min-width: 25px;
min-height: 25px;
box-shadow: inset 0 3px 5px rgba(200, 200, 200, 0.5);
}
.container-button ::deep .button-settings.green-icon .mud-icon-root { color: var(--mud-palette-success-darken); }
.container-button ::deep .button-settings.red-icon .mud-icon-root { color: var(--mud-palette-error); }
.container-button ::deep .button-settings .mud-button-label {
justify-content: flex-start;
text-transform: capitalize;
font-size: 1rem;
}
.container-button ::deep .button-settings.exit { padding: 0; }
.container-button ::deep .button-settings.exit .mud-button-label {
justify-content: center;
font-size: 1.1rem;
line-height: normal;
}

View File

@@ -5,43 +5,12 @@
<HeaderLayout BackTo="@BackTo" ShowNotifications="false" Back="true" Title="Impostazioni"/>
<div class="content">
<MudButton Class="button-settings"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
OnClick="() => UpdateDb(true)"
Variant="Variant.Outlined">
Sincronizza
</MudButton>
<div class="divider"></div>
<MudButton Class="button-settings"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
OnClick="() => UpdateDb()"
Variant="Variant.Outlined">
Ripristina dati
</MudButton>
</div>
@code {
[Parameter] public string BackTo { get; set; } = "";
private void UpdateDb(bool withData = false)
{
var absoluteUri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);
var pathAndQuery = absoluteUri.Segments.Length > 1 ? absoluteUri.PathAndQuery : null;
string path;
if (withData)
path = pathAndQuery == null ? $"/sync/{DateTime.Today:yyyy-MM-dd}" : $"/sync/{DateTime.Today:yyyy-MM-dd}?path=" + System.Web.HttpUtility.UrlEncode(pathAndQuery);
else
path = pathAndQuery == null ? "/sync" : "/sync?path=" + System.Web.HttpUtility.UrlEncode(pathAndQuery);
NavigationManager.NavigateTo(path, replace: true);
}
}

View File

@@ -1,7 +1,8 @@
@using Template.Shared.Core.Dto
@using Template.Shared.Core.Helpers.Enum
@inject IDialogService Dialog
<div class="activity-card @Activity.Category.ConvertToHumanReadable()" @onclick="() => OpenActivityForm(Activity.ActivityId)">
<div class="activity-card @Activity.Category.ConvertToHumanReadable()" @onclick="() => ModalHelpers.OpenActivityForm(Dialog, Activity.ActivityId)">
<div class="activity-left-section">
<div class="activity-body-section">
<div class="title-section">
@@ -74,12 +75,4 @@
_ => null
};
}
private void OpenActivityForm(string? activityId)
{
var url = "/activity";
url = !activityId.IsNullOrEmpty() ? $"{url}/{activityId}" : url;
NavigationManager.NavigateTo(url);
}
}

View File

@@ -5,7 +5,7 @@
padding: .5rem .5rem;
border-radius: 12px;
line-height: normal;
border: 1px solid var(--card-border-color);
box-shadow: var(--custom-box-shadow);
}
.activity-card.memo { border-left: 5px solid var(--mud-palette-info-darken); }

View File

@@ -0,0 +1,22 @@
using MudBlazor;
using Template.Shared.Components.Pages;
namespace Template.Shared.Core.Helpers;
public class ModalHelpers
{
public static Task OpenActivityForm(IDialogService dialog ,string? id = null) =>
dialog.ShowAsync<ActivityForm>(
"Activity form",
new DialogParameters<ActivityForm>
{
{ x => x.Id, id}
},
new DialogOptions
{
FullScreen = true,
CloseButton = false,
NoHeader = true
}
);
}

View File

@@ -12,6 +12,7 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="14.0.0" />
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="8.2.2" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="IntegryApiClient.Core" Version="1.1.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.5" />

View File

@@ -9,6 +9,7 @@
@using Microsoft.JSInterop
@using Template.Shared.Components
@using MudBlazor
@using MudExtensions
@using MudBlazor.ThemeManager
@using Template.Shared.Core.Helpers
@using Template.Shared.Components.SingleElements.Card

View File

@@ -141,3 +141,8 @@ h1:focus { outline: none; }
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.customDialog-form .mud-dialog-content {
padding: 0 .75rem;
margin: 0;
}

View File

@@ -4,4 +4,5 @@
--gray-for-shadow: hsl(from var(--mud-palette-gray-light) h s 95%);
/*Utility*/
--card-shadow: 5px 5px 10px 0 var(--gray-for-shadow);
--custom-box-shadow: 1px 2px 5px rgba(165, 165, 165, 0.5);
}

View File

@@ -1,41 +1,56 @@
window.calendarSwipe = {
register: function (element, dotnetHelper) {
let startX = 0;
let endX = 0;
let startX = 0, startY = 0;
let endX = 0, endY = 0;
// Touch events
element.addEventListener('touchstart', (e) => {
if (e.touches.length === 1) {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
}
});
element.addEventListener('touchend', (e) => {
if (e.changedTouches.length === 1) {
endX = e.changedTouches[0].clientX;
endY = e.changedTouches[0].clientY;
handle();
}
});
// Per desktop: mouse drag
// Mouse events
let mouseDown = false;
element.addEventListener('mousedown', (e) => {
if (e.button !== 0) return; // solo left mouse
if (e.button !== 0) return;
mouseDown = true;
startX = e.clientX;
startY = e.clientY;
});
element.addEventListener('mouseup', (e) => {
if (!mouseDown) return;
mouseDown = false;
endX = e.clientX;
endY = e.clientY;
handle();
});
function handle() {
let diff = endX - startX;
if (Math.abs(diff) > 40) {
if (diff < 0) dotnetHelper.invokeMethodAsync('OnSwipeLeft');
let diffX = endX - startX;
let diffY = endY - startY;
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > 40) {
if (diffX < 0) dotnetHelper.invokeMethodAsync('OnSwipeLeft');
else dotnetHelper.invokeMethodAsync('OnSwipeRight');
}
} else {
if (Math.abs(diffY) > 40) {
if (diffY < 0) dotnetHelper.invokeMethodAsync('OnSwipeUp');
else dotnetHelper.invokeMethodAsync('OnSwipeDown');
}
}
}
}
};