diff --git a/SteUp.Maui/Core/Services/AttachedService.cs b/SteUp.Maui/Core/Services/AttachedService.cs index 5ceedc3..9b39f25 100644 --- a/SteUp.Maui/Core/Services/AttachedService.cs +++ b/SteUp.Maui/Core/Services/AttachedService.cs @@ -8,12 +8,21 @@ namespace SteUp.Maui.Core.Services; public class AttachedService(ILogger logger) : IAttachedService { - public async Task SelectImageFromCamera() + public bool IsCameraAvailable => MediaPicker.Default.IsCaptureSupported; + + public async Task RequestCameraPermissions() { var cameraPerm = await Permissions.RequestAsync(); var storagePerm = await Permissions.RequestAsync(); - if (cameraPerm != PermissionStatus.Granted || storagePerm != PermissionStatus.Granted) + return cameraPerm == PermissionStatus.Granted && storagePerm == PermissionStatus.Granted; + } + + public void OpenAppSettings() => AppInfo.Current.ShowSettingsUI(); + + public async Task SelectImageFromCamera() + { + if (!await RequestCameraPermissions()) return null; FileResult? result; @@ -28,7 +37,10 @@ public class AttachedService(ILogger logger) : IAttachedService logger.LogError(ex, ex.Message); Console.WriteLine($"Errore cattura foto: {ex.Message}"); 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); diff --git a/SteUp.Maui/Platforms/Android/AndroidManifest.xml b/SteUp.Maui/Platforms/Android/AndroidManifest.xml index e4623c3..2ad7f73 100644 --- a/SteUp.Maui/Platforms/Android/AndroidManifest.xml +++ b/SteUp.Maui/Platforms/Android/AndroidManifest.xml @@ -25,4 +25,11 @@ + + + + + + + diff --git a/SteUp.Maui/SteUp.Maui.csproj b/SteUp.Maui/SteUp.Maui.csproj index 55069ac..96ca097 100644 --- a/SteUp.Maui/SteUp.Maui.csproj +++ b/SteUp.Maui/SteUp.Maui.csproj @@ -30,8 +30,8 @@ it.integry.SteUp - 1.2.2 - 8 + 1.2.3 + 9 15.0 diff --git a/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor b/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor index 13b63c2..00dfa18 100644 --- a/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor +++ b/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor @@ -40,7 +40,32 @@ 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) { diff --git a/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor b/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor index 1a93399..5e3de39 100644 --- a/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor +++ b/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor @@ -754,12 +754,60 @@ #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() { - var selectImageFromCamera = await AttachedService.SelectImageFromCamera(); - if (selectImageFromCamera == null) return; - - var attachedList = new List { selectImageFromCamera }; + List? attachedList; + + 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; await InvokeAsync(StateHasChanged); diff --git a/SteUp.Shared/Core/Interface/System/IAttachedService.cs b/SteUp.Shared/Core/Interface/System/IAttachedService.cs index 87863c9..588d61a 100644 --- a/SteUp.Shared/Core/Interface/System/IAttachedService.cs +++ b/SteUp.Shared/Core/Interface/System/IAttachedService.cs @@ -4,6 +4,14 @@ namespace SteUp.Shared.Core.Interface.System; public interface IAttachedService { + bool IsCameraAvailable { get; } + + /// Chiede i permessi per scattare; false se negati. + Task RequestCameraPermissions(); + + void OpenAppSettings(); + + /// Null se l'utente annulla; lancia se lo scatto fallisce. Task SelectImageFromCamera(); Task?> SelectImageFromGallery(); } \ No newline at end of file