Compare commits
15
Commits
v1.2.2
..
v1.2.5(11)
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c57df2cbb7 | ||
|
|
e5cf4215f6 | ||
|
|
c4c624667d | ||
|
|
df827216c3 | ||
|
|
b2db0f2479 | ||
|
|
817cd606b6 | ||
|
|
495f335b72 | ||
|
|
ed7c28feac | ||
|
|
42e2403362 | ||
|
|
f59c8d3aaf | ||
|
|
249b301920 | ||
|
|
885b3cc6b6 | ||
|
|
7e1492d118 | ||
|
|
fd0c218ab5 | ||
|
|
e1ca03f646 |
No files matched your search
@@ -8,12 +8,21 @@ namespace SteUp.Maui.Core.Services;
|
|||||||
|
|
||||||
public class AttachedService(ILogger<FileManager> logger) : IAttachedService
|
public class AttachedService(ILogger<FileManager> logger) : IAttachedService
|
||||||
{
|
{
|
||||||
public async Task<AttachedDto?> SelectImageFromCamera()
|
public bool IsCameraAvailable => MediaPicker.Default.IsCaptureSupported;
|
||||||
|
|
||||||
|
public async Task<bool> RequestCameraPermissions()
|
||||||
{
|
{
|
||||||
var cameraPerm = await Permissions.RequestAsync<Permissions.Camera>();
|
var cameraPerm = await Permissions.RequestAsync<Permissions.Camera>();
|
||||||
var storagePerm = await Permissions.RequestAsync<Permissions.StorageWrite>();
|
var storagePerm = await Permissions.RequestAsync<Permissions.StorageWrite>();
|
||||||
|
|
||||||
if (cameraPerm != PermissionStatus.Granted || storagePerm != PermissionStatus.Granted)
|
return cameraPerm == PermissionStatus.Granted && storagePerm == PermissionStatus.Granted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenAppSettings() => AppInfo.Current.ShowSettingsUI();
|
||||||
|
|
||||||
|
public async Task<AttachedDto?> SelectImageFromCamera()
|
||||||
|
{
|
||||||
|
if (!await RequestCameraPermissions())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
FileResult? result;
|
FileResult? result;
|
||||||
@@ -28,7 +37,10 @@ public class AttachedService(ILogger<FileManager> logger) : IAttachedService
|
|||||||
logger.LogError(ex, ex.Message);
|
logger.LogError(ex, ex.Message);
|
||||||
Console.WriteLine($"Errore cattura foto: {ex.Message}");
|
Console.WriteLine($"Errore cattura foto: {ex.Message}");
|
||||||
SentrySdk.CaptureException(ex);
|
SentrySdk.CaptureException(ex);
|
||||||
return null;
|
|
||||||
|
// Rilancia: restituire null qui era indistinguibile da un annullamento,
|
||||||
|
// e il rilevatore toccava "Aggiungi una foto" senza vedere nulla.
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result is null ? null : await UtilityFile.ConvertToDto(result, AttachedDto.TypeAttached.Image);
|
return result is null ? null : await UtilityFile.ConvertToDto(result, AttachedDto.TypeAttached.Image);
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ public class FileManager(
|
|||||||
|
|
||||||
private async Task<AttachedDto> ConvertToDto(FileInfo file, AttachedDto.TypeAttached type, bool isFromToUpload)
|
private async Task<AttachedDto> ConvertToDto(FileInfo file, AttachedDto.TypeAttached type, bool isFromToUpload)
|
||||||
{
|
{
|
||||||
var (origUrl, thumbUrl) = await SaveAndCreateThumbAsync(
|
var bytes = await File.ReadAllBytesAsync(file.FullName);
|
||||||
await File.ReadAllBytesAsync(file.FullName),
|
var (origUrl, thumbUrl) = await SaveAndCreateThumbAsync(bytes, file.Name);
|
||||||
file.Name
|
|
||||||
);
|
|
||||||
|
|
||||||
return new AttachedDto
|
return new AttachedDto
|
||||||
{
|
{
|
||||||
Name = file.Name,
|
Name = file.Name,
|
||||||
Path = file.FullName,
|
Path = file.FullName,
|
||||||
|
// Servono per inviare le foto rimaste in /toUpload (salvate senza rete).
|
||||||
|
FileBytes = bytes,
|
||||||
TempPath = origUrl,
|
TempPath = origUrl,
|
||||||
ThumbPath = thumbUrl,
|
ThumbPath = thumbUrl,
|
||||||
Type = type,
|
Type = type,
|
||||||
@@ -101,7 +101,9 @@ public class FileManager(
|
|||||||
|
|
||||||
foreach (var file in toUploadFiles)
|
foreach (var file in toUploadFiles)
|
||||||
{
|
{
|
||||||
if (!fileNameFilter.Contains(file.Name))
|
// Scheda.ImageNames contiene il percorso completo restituito da SaveInspectionFile:
|
||||||
|
// confrontando solo il nome le foto salvate e non ancora inviate non comparivano mai.
|
||||||
|
if (!fileNameFilter.Contains(file.FullName) && !fileNameFilter.Contains(file.Name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|||||||
@@ -25,4 +25,11 @@
|
|||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
|
|
||||||
|
<!-- Android 11+: rende visibile l'app fotocamera di sistema a MediaPicker -->
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.media.action.IMAGE_CAPTURE" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
<ApplicationId>it.integry.SteUp</ApplicationId>
|
<ApplicationId>it.integry.SteUp</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>1.2.2</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>1.2.5</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>8</ApplicationVersion>
|
<ApplicationVersion>11</ApplicationVersion>
|
||||||
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
||||||
<!-- <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">-->
|
<!-- <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">-->
|
||||||
@@ -116,12 +116,12 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Maui" Version="14.1.0" />
|
<PackageReference Include="CommunityToolkit.Maui" Version="14.1.0" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageReference Include="IntegryApiClient.MAUI" Version="2.0.1" />
|
<PackageReference Include="IntegryApiClient.MAUI" Version="2.6.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.7" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.8" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.51" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.51" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="10.0.51" />
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="10.0.51" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="10.0.51" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="10.0.51" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.7" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.8" />
|
||||||
<PackageReference Include="Sentry.Maui" Version="6.4.1" />
|
<PackageReference Include="Sentry.Maui" Version="6.4.1" />
|
||||||
<PackageReference Include="SkiaSharp" Version="3.119.2" />
|
<PackageReference Include="SkiaSharp" Version="3.119.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -40,7 +40,32 @@
|
|||||||
|
|
||||||
private async Task OnCamera()
|
private async Task OnCamera()
|
||||||
{
|
{
|
||||||
var selectImageFromCamera = await AttachedService.SelectImageFromCamera();
|
if (!await AttachedService.RequestCameraPermissions())
|
||||||
|
{
|
||||||
|
Snackbar.Clear();
|
||||||
|
Snackbar.Add("Per scattare le foto serve il permesso della fotocamera", Severity.Warning, config =>
|
||||||
|
{
|
||||||
|
config.Action = "Impostazioni";
|
||||||
|
config.OnClick = _ =>
|
||||||
|
{
|
||||||
|
AttachedService.OpenAppSettings();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachedDto? selectImageFromCamera;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
selectImageFromCamera = await AttachedService.SelectImageFromCamera();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Snackbar.Clear();
|
||||||
|
Snackbar.Add("Non è stato possibile scattare la foto, riprova", Severity.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (selectImageFromCamera != null)
|
if (selectImageFromCamera != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -171,7 +171,10 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (item.p.ToUpload && !ReadOnly)
|
@* Rimovibile anche se gia' salvata o inviata. Non mentre e'
|
||||||
|
in elaborazione: l'indice della foto serve ancora al
|
||||||
|
caricamento in background. *@
|
||||||
|
@if (!ReadOnly && !item.p.ThumbPath.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
<button type="button" class="attach-item__remove"
|
<button type="button" class="attach-item__remove"
|
||||||
aria-label="@($"Rimuovi la foto {item.p.Name}")"
|
aria-label="@($"Rimuovi la foto {item.p.Name}")"
|
||||||
@@ -336,6 +339,9 @@
|
|||||||
// Gli allegati vivono in AttachedList finche' non si salva: li tracciamo con un flag.
|
// Gli allegati vivono in AttachedList finche' non si salva: li tracciamo con un flag.
|
||||||
private bool _attachmentsDirty;
|
private bool _attachmentsDirty;
|
||||||
private List<AttachedDto>? AttachedList { get; set; }
|
private List<AttachedDto>? AttachedList { get; set; }
|
||||||
|
// Foto gia' salvate tolte dal rilevatore: si eliminano davvero solo al salvataggio,
|
||||||
|
// cosi' uscendo senza salvare restano dove sono.
|
||||||
|
private readonly List<AttachedDto> _removedAttachments = [];
|
||||||
|
|
||||||
private IDisposable? _backRegistration;
|
private IDisposable? _backRegistration;
|
||||||
// Il tasto indietro puo' arrivare mentre il prompt di uscita e' gia' a video.
|
// Il tasto indietro puo' arrivare mentre il prompt di uscita e' gia' a video.
|
||||||
@@ -505,10 +511,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task Update(SaveSchedaResponseDto? apiResponse, bool preserveActivityId = false)
|
private async Task Update(SaveSchedaResponseDto? apiResponse, bool preserveActivityId = false)
|
||||||
{
|
|
||||||
if (!AttachedList.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var attached in AttachedList!.Where(x => !x.SavedOnAppData))
|
|
||||||
{
|
{
|
||||||
var ispezione = new Ispezione
|
var ispezione = new Ispezione
|
||||||
{
|
{
|
||||||
@@ -517,7 +519,13 @@
|
|||||||
Rilevatore = UserSession.User.Username
|
Rilevatore = UserSession.User.Username
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!attached.ToRemove)
|
// Prima di toccare l'ActivityId: le foto gia' inviate vanno tolte dall'attivita'
|
||||||
|
// su cui sono state caricate.
|
||||||
|
await RemoveDeletedAttachments(ispezione);
|
||||||
|
|
||||||
|
if (!AttachedList.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
foreach (var attached in AttachedList!.Where(x => !x.SavedOnAppData))
|
||||||
{
|
{
|
||||||
var fileNameAdded = await FileManager.SaveInspectionFile(
|
var fileNameAdded = await FileManager.SaveInspectionFile(
|
||||||
ispezione,
|
ispezione,
|
||||||
@@ -529,9 +537,6 @@
|
|||||||
if (fileNameAdded != null)
|
if (fileNameAdded != null)
|
||||||
Scheda.ImageNames.Add(fileNameAdded);
|
Scheda.ImageNames.Add(fileNameAdded);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
_ = FileManager.RemoveInspectionFile(ispezione, attached.Name!);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Salvando una bozza non tocchiamo l'ActivityId: se la scheda era già sul server,
|
// Salvando una bozza non tocchiamo l'ActivityId: se la scheda era già sul server,
|
||||||
@@ -549,6 +554,70 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Elimina le foto salvate che il rilevatore ha tolto dalla scheda: dal server se
|
||||||
|
/// erano gia' state inviate, poi dal dispositivo e dall'elenco della scheda.
|
||||||
|
/// Se il server non conferma, la foto resta (sul server e sul dispositivo) invece
|
||||||
|
/// di sparire solo da qui.
|
||||||
|
/// </summary>
|
||||||
|
private async Task RemoveDeletedAttachments(Ispezione ispezione)
|
||||||
|
{
|
||||||
|
if (_removedAttachments.Count == 0) return;
|
||||||
|
|
||||||
|
var nonEliminate = 0;
|
||||||
|
|
||||||
|
foreach (var attached in _removedAttachments)
|
||||||
|
{
|
||||||
|
if (attached.Name.IsNullOrEmpty()) continue;
|
||||||
|
|
||||||
|
var giaInviata = !attached.ToUpload;
|
||||||
|
|
||||||
|
// Una foto ancora "da inviare" di norma non e' sul server, ma l'invio dalla
|
||||||
|
// card o dalla chiusura ispezione non la sposta fra le inviate: con la rete
|
||||||
|
// si prova comunque a toglierla, senza bloccare l'eliminazione se non c'e'.
|
||||||
|
if (Scheda.ActivityId.IsValorized() && (giaInviata || NetworkService.ConnectionAvailable))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await IntegrySteupService.RemoveFile(Scheda.ActivityId!, attached.Name!);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (giaInviata)
|
||||||
|
{
|
||||||
|
Logger.LogError(e, "Eliminazione della foto {FileName} dal server non riuscita", attached.Name);
|
||||||
|
nonEliminate++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogWarning(e, "Foto {FileName} non trovata sul server", attached.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileManager.RemoveInspectionFile(ispezione, attached.Name!);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Il file orfano non fa danni: conta che la foto esca dalla scheda.
|
||||||
|
Logger.LogError(e, "Eliminazione del file {FileName} non riuscita", attached.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Scheda.ImageNames?.RemoveAll(x => System.IO.Path.GetFileName(x) == attached.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
_removedAttachments.Clear();
|
||||||
|
|
||||||
|
if (nonEliminate > 0)
|
||||||
|
{
|
||||||
|
Snackbar.Add(nonEliminate == 1
|
||||||
|
? "Una foto già inviata non è stata eliminata: riprova con la connessione"
|
||||||
|
: $"{nonEliminate} foto già inviate non sono state eliminate: riprova con la connessione",
|
||||||
|
Severity.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task UploadFile(Scheda scheda)
|
private async Task UploadFile(Scheda scheda)
|
||||||
{
|
{
|
||||||
if (AttachedList.IsNullOrEmpty()) return;
|
if (AttachedList.IsNullOrEmpty()) return;
|
||||||
@@ -703,7 +772,8 @@
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Salva il lavoro in corso solo sul dispositivo, marcato come da completare.
|
/// Salva il lavoro in corso solo sul dispositivo, marcato come da completare.
|
||||||
/// Niente chiamate al server e niente validazione: una bozza può essere incompleta.
|
/// Niente salvataggio sul server e niente validazione: una bozza può essere incompleta.
|
||||||
|
/// Unica eccezione: le foto già inviate tolte dal rilevatore si eliminano anche dal server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task SaveDraft()
|
private async Task SaveDraft()
|
||||||
{
|
{
|
||||||
@@ -754,12 +824,60 @@
|
|||||||
|
|
||||||
#region File
|
#region File
|
||||||
|
|
||||||
|
// Dopo un rifiuto definitivo Android non ripropone la richiesta: il
|
||||||
|
// permesso si riattiva solo dalle impostazioni, quindi le apriamo noi.
|
||||||
|
private void ShowCameraPermissionDenied()
|
||||||
|
{
|
||||||
|
Snackbar.Clear();
|
||||||
|
Snackbar.Add("Per scattare le foto serve il permesso della fotocamera", Severity.Warning, config =>
|
||||||
|
{
|
||||||
|
config.Action = "Impostazioni";
|
||||||
|
config.OnClick = _ =>
|
||||||
|
{
|
||||||
|
AttachedService.OpenAppSettings();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async Task OpenAddAttached()
|
private async Task OpenAddAttached()
|
||||||
{
|
{
|
||||||
var selectImageFromCamera = await AttachedService.SelectImageFromCamera();
|
List<AttachedDto>? attachedList;
|
||||||
if (selectImageFromCamera == null) return;
|
|
||||||
|
|
||||||
var attachedList = new List<AttachedDto> { selectImageFromCamera };
|
if (AttachedService.IsCameraAvailable)
|
||||||
|
{
|
||||||
|
if (!await AttachedService.RequestCameraPermissions())
|
||||||
|
{
|
||||||
|
ShowCameraPermissionDenied();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachedDto? selectImageFromCamera;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
selectImageFromCamera = await AttachedService.SelectImageFromCamera();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Gia' registrato e inviato a Sentry dal servizio
|
||||||
|
Snackbar.Clear();
|
||||||
|
Snackbar.Add("Non è stato possibile scattare la foto, riprova", Severity.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectImageFromCamera == null) return;
|
||||||
|
attachedList = [selectImageFromCamera];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Senza fotocamera "Aggiungi una foto" non avrebbe altra strada:
|
||||||
|
// si passa alla galleria invece di lasciare il rilevatore fermo.
|
||||||
|
Snackbar.Clear();
|
||||||
|
Snackbar.Add("Fotocamera non disponibile: scegli la foto dalla galleria", Severity.Warning);
|
||||||
|
|
||||||
|
attachedList = await AttachedService.SelectImageFromGallery();
|
||||||
|
if (attachedList is null || attachedList.Count == 0) return;
|
||||||
|
}
|
||||||
|
|
||||||
OnLoading = true;
|
OnLoading = true;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
@@ -848,29 +966,32 @@
|
|||||||
|
|
||||||
var modal = await WithChildDialog(() => Dialog.OpenSelectArt(articoli));
|
var modal = await WithChildDialog(() => Dialog.OpenSelectArt(articoli));
|
||||||
|
|
||||||
|
// Gli articoli si aggiungono sul thread della UI, come fanno le scansioni:
|
||||||
|
// toccare Scheda.Articoli da qui mentre arriva una lettura (o mentre la
|
||||||
|
// lista viene disegnata) puo' far perdere articoli.
|
||||||
await InvokeAsync(() =>
|
await InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
OnLoading = false;
|
OnLoading = false;
|
||||||
TextLoading = null;
|
TextLoading = null;
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (modal is { Canceled: false, Data: List<ArticoliInGrigliaDto> articoliSelezionati })
|
if (modal is { Canceled: false, Data: List<ArticoliInGrigliaDto> articoliSelezionati })
|
||||||
{
|
{
|
||||||
Scheda.Articoli.InsertRange(0, articoliSelezionati.ConvertAll(x => new SchedaArticolo
|
// Quelli gia' sparati non si aggiungono di nuovo.
|
||||||
|
Scheda.Articoli.InsertRange(0, articoliSelezionati
|
||||||
|
.DistinctBy(x => x.Barcode)
|
||||||
|
.Where(x => !ContainsBarcode(x.Barcode))
|
||||||
|
.Select(x => new SchedaArticolo
|
||||||
{
|
{
|
||||||
Barcode = x.Barcode,
|
Barcode = x.Barcode,
|
||||||
Descrizione = x.Descrizione
|
Descrizione = x.Descrizione
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
await InvokeAsync(() =>
|
|
||||||
{
|
|
||||||
RecalcDirty();
|
RecalcDirty();
|
||||||
|
}
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -878,8 +999,22 @@
|
|||||||
{
|
{
|
||||||
if (AttachedList is null || index < 0 || index >= AttachedList.Count) return;
|
if (AttachedList is null || index < 0 || index >= AttachedList.Count) return;
|
||||||
|
|
||||||
if (AttachedList[index].SavedOnAppData)
|
var attached = AttachedList[index];
|
||||||
AttachedList[index].ToRemove = true;
|
|
||||||
|
// Le foto appena scattate stanno solo in memoria: basta toglierle dall'elenco.
|
||||||
|
if (attached.SavedOnAppData)
|
||||||
|
{
|
||||||
|
// Una foto gia' inviata va tolta anche dal server: senza rete resterebbe
|
||||||
|
// nella scheda inviata pur sparendo dal dispositivo.
|
||||||
|
if (!attached.ToUpload && !NetworkService.ConnectionAvailable)
|
||||||
|
{
|
||||||
|
Snackbar.Clear();
|
||||||
|
Snackbar.Add("Per eliminare una foto già inviata serve la connessione", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_removedAttachments.Add(attached);
|
||||||
|
}
|
||||||
|
|
||||||
AttachedList.RemoveAt(index);
|
AttachedList.RemoveAt(index);
|
||||||
_attachmentsDirty = true;
|
_attachmentsDirty = true;
|
||||||
@@ -936,7 +1071,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (value is null) return;
|
if (value is null) return;
|
||||||
if (Scheda.Articoli.Any(x => x.Barcode.Equals(value))) return;
|
if (ContainsBarcode(value)) return;
|
||||||
|
|
||||||
await InvokeAsync(() =>
|
await InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
@@ -951,6 +1086,11 @@
|
|||||||
OnLoading = false;
|
OnLoading = false;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
|
||||||
|
// Il controllo va ripetuto sul barcode restituito: il server puo' rispondere
|
||||||
|
// con un barcode diverso da quello letto (lo stesso gia' scelto dalla griglia),
|
||||||
|
// e due letture ravvicinate superano entrambe il controllo iniziale.
|
||||||
|
if (art != null && ContainsBarcode(art.Barcode)) return;
|
||||||
|
|
||||||
if (art != null)
|
if (art != null)
|
||||||
{
|
{
|
||||||
Scheda.Articoli.Insert(0, new SchedaArticolo
|
Scheda.Articoli.Insert(0, new SchedaArticolo
|
||||||
@@ -984,6 +1124,8 @@
|
|||||||
|
|
||||||
private void OnErrorScan(string? value) => OnError(new Exception(value), value);
|
private void OnErrorScan(string? value) => OnError(new Exception(value), value);
|
||||||
|
|
||||||
|
private bool ContainsBarcode(string barcode) => Scheda.Articoli.Any(x => x.Barcode.Equals(barcode));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void OnError(Exception? e, string? errorMessage)
|
private void OnError(Exception? e, string? errorMessage)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ public class AttachedDto
|
|||||||
public string? ThumbPath { get; set; }
|
public string? ThumbPath { get; set; }
|
||||||
|
|
||||||
public bool SavedOnAppData { get; set; }
|
public bool SavedOnAppData { get; set; }
|
||||||
public bool ToRemove { get; set; }
|
|
||||||
public bool ToUpload { get; set; }
|
public bool ToUpload { get; set; }
|
||||||
|
|
||||||
public Stream? FileContent =>
|
public Stream? FileContent =>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public interface IIntegrySteupService
|
|||||||
Task<SaveSchedaResponseDto?> SaveMultipleSchede(List<SaveRequestDto> request);
|
Task<SaveSchedaResponseDto?> SaveMultipleSchede(List<SaveRequestDto> request);
|
||||||
Task CompleteInspection(string activityId);
|
Task CompleteInspection(string activityId);
|
||||||
Task UploadFile(string activityId, byte[] file, string fileName);
|
Task UploadFile(string activityId, byte[] file, string fileName);
|
||||||
|
Task RemoveFile(string activityId, string fileName);
|
||||||
|
|
||||||
Task DeleteScheda(string activityId);
|
Task DeleteScheda(string activityId);
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,14 @@ namespace SteUp.Shared.Core.Interface.System;
|
|||||||
|
|
||||||
public interface IAttachedService
|
public interface IAttachedService
|
||||||
{
|
{
|
||||||
|
bool IsCameraAvailable { get; }
|
||||||
|
|
||||||
|
/// <summary>Chiede i permessi per scattare; false se negati.</summary>
|
||||||
|
Task<bool> RequestCameraPermissions();
|
||||||
|
|
||||||
|
void OpenAppSettings();
|
||||||
|
|
||||||
|
/// <summary>Null se l'utente annulla; lancia se lo scatto fallisce.</summary>
|
||||||
Task<AttachedDto?> SelectImageFromCamera();
|
Task<AttachedDto?> SelectImageFromCamera();
|
||||||
Task<List<AttachedDto>?> SelectImageFromGallery();
|
Task<List<AttachedDto>?> SelectImageFromGallery();
|
||||||
}
|
}
|
||||||
@@ -70,6 +70,20 @@ public class IntegrySteupService(IIntegryApiRestClient integryApiRestClient) : I
|
|||||||
content.Dispose();
|
content.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toglie un allegato dalla scheda. Il server lo riconosce dal nome con cui
|
||||||
|
/// è stato caricato da <see cref="UploadFile"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Task RemoveFile(string activityId, string fileName) =>
|
||||||
|
integryApiRestClient.AuthorizedGet<object>(
|
||||||
|
$"{BaseRequest}/removeAttachment",
|
||||||
|
new Dictionary<string, object?>
|
||||||
|
{
|
||||||
|
{ "activityId", activityId },
|
||||||
|
{ "fileName", fileName }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
public Task DeleteScheda(string activityId) =>
|
public Task DeleteScheda(string activityId) =>
|
||||||
integryApiRestClient.AuthorizedGet<object>(
|
integryApiRestClient.AuthorizedGet<object>(
|
||||||
$"{BaseRequest}/deleteScheda",
|
$"{BaseRequest}/deleteScheda",
|
||||||
|
|||||||
@@ -11,13 +11,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="IntegryApiClient.Core" Version="2.0.1" />
|
<PackageReference Include="IntegryApiClient.Core" Version="2.6.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.7" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageReference Include="MudBlazor" Version="9.0.0" />
|
<PackageReference Include="MudBlazor" Version="9.0.0" />
|
||||||
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="9.0.1" />
|
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="9.0.1" />
|
||||||
<PackageReference Include="Sentry" Version="6.4.1" />
|
<PackageReference Include="Sentry" Version="6.4.1" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.17.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.18.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.7" />
|
||||||
<PackageReference Include="Microsoft.Maui.Essentials" Version="10.0.51" />
|
<PackageReference Include="Microsoft.Maui.Essentials" Version="10.0.51" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="IntegryApiClient.Blazor" Version="2.0.1" />
|
<PackageReference Include="IntegryApiClient.Blazor" Version="2.6.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.7" />
|
||||||
|
|||||||
Reference in new issue
Block a user