From fd0c218ab5d7b2d88962743a2d35ef2c757f1fb4 Mon Sep 17 00:00:00 2001 From: MarcoE Date: Wed, 21 Oct 2026 08:45:57 +0200 Subject: [PATCH 1/4] Dichiara la fotocamera di sistema nelle queries del manifest Da Android 11 un'app vede le altre app installate solo se le dichiara in . Senza l'intent IMAGE_CAPTURE, MediaPicker.CapturePhotoAsync non trovava la fotocamera di sistema e falliva con "Either there was no camera on the device or 'android.media.action.IMAGE_CAPTURE' was not added to the element" (segnalato su Sentry). Co-Authored-By: Claude Opus 5.5 (1M context) --- SteUp.Maui/Platforms/Android/AndroidManifest.xml | 7 +++++++ 1 file changed, 7 insertions(+) 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 @@ + + + + + + + From 7e1492d11805d015716c864fdbb8557287d900b6 Mon Sep 17 00:00:00 2001 From: MarcoE Date: Wed, 21 Oct 2026 08:45:57 +0200 Subject: [PATCH 2/4] Avvisa quando la fotocamera non si apre e passa alla galleria Se lo scatto falliva, AttachedService restituiva null come per un annullamento: il rilevatore toccava "Aggiungi una foto" e non succedeva nulla. - AttachedService: espone IsCameraAvailable (IsCaptureSupported) e, dopo aver registrato l'errore e averlo inviato a Sentry, lo rilancia invece di restituire null. - ModalFormScheda: dalla scheda il pulsante apre solo la fotocamera, quindi senza fotocamera non c'era alternativa. Ora avvisa e apre la galleria; se lo scatto fallisce mostra un errore. - ModalAddAttached: stessa gestione dell'errore di scatto. Co-Authored-By: Claude Opus 5.5 (1M context) --- SteUp.Maui/Core/Services/AttachedService.cs | 7 +++- .../Modal/ModalAddAttached.razor | 12 ++++++- .../Modal/ModalFormScheda.razor | 34 ++++++++++++++++--- .../Core/Interface/System/IAttachedService.cs | 3 ++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/SteUp.Maui/Core/Services/AttachedService.cs b/SteUp.Maui/Core/Services/AttachedService.cs index 5ceedc3..fde9132 100644 --- a/SteUp.Maui/Core/Services/AttachedService.cs +++ b/SteUp.Maui/Core/Services/AttachedService.cs @@ -8,6 +8,8 @@ namespace SteUp.Maui.Core.Services; public class AttachedService(ILogger logger) : IAttachedService { + public bool IsCameraAvailable => MediaPicker.Default.IsCaptureSupported; + public async Task SelectImageFromCamera() { var cameraPerm = await Permissions.RequestAsync(); @@ -28,7 +30,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.Shared/Components/SingleElements/Modal/ModalAddAttached.razor b/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor index 13b63c2..224703d 100644 --- a/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor +++ b/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor @@ -40,7 +40,17 @@ private async Task OnCamera() { - var selectImageFromCamera = await AttachedService.SelectImageFromCamera(); + 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..7a60f47 100644 --- a/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor +++ b/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor @@ -756,10 +756,36 @@ private async Task OpenAddAttached() { - var selectImageFromCamera = await AttachedService.SelectImageFromCamera(); - if (selectImageFromCamera == null) return; - - var attachedList = new List { selectImageFromCamera }; + List? attachedList; + + if (AttachedService.IsCameraAvailable) + { + 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..f39fcce 100644 --- a/SteUp.Shared/Core/Interface/System/IAttachedService.cs +++ b/SteUp.Shared/Core/Interface/System/IAttachedService.cs @@ -4,6 +4,9 @@ namespace SteUp.Shared.Core.Interface.System; public interface IAttachedService { + bool IsCameraAvailable { get; } + + /// Null se l'utente annulla; lancia se lo scatto fallisce. Task SelectImageFromCamera(); Task?> SelectImageFromGallery(); } \ No newline at end of file From 885b3cc6b6557d43834382bea713e8b353ea82d7 Mon Sep 17 00:00:00 2001 From: MarcoE Date: Wed, 21 Oct 2026 08:49:34 +0200 Subject: [PATCH 3/4] Avvisa quando manca il permesso della fotocamera Con il permesso negato "Aggiungi una foto" non faceva nulla: il servizio restituiva null come per un annullamento. Dopo un rifiuto definitivo Android non ripropone la richiesta, quindi il rilevatore restava bloccato senza capire perche'. - AttachedService: la richiesta dei permessi diventa RequestCameraPermissions, usata anche da SelectImageFromCamera; OpenAppSettings apre le impostazioni dell'app. - ModalFormScheda e ModalAddAttached: chiedono i permessi prima di scattare e, se negati, mostrano un avviso con l'azione "Impostazioni". Co-Authored-By: Claude Opus 5.5 (1M context) --- SteUp.Maui/Core/Services/AttachedService.cs | 11 ++++++++-- .../Modal/ModalAddAttached.razor | 15 +++++++++++++ .../Modal/ModalFormScheda.razor | 22 +++++++++++++++++++ .../Core/Interface/System/IAttachedService.cs | 5 +++++ 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/SteUp.Maui/Core/Services/AttachedService.cs b/SteUp.Maui/Core/Services/AttachedService.cs index fde9132..9b39f25 100644 --- a/SteUp.Maui/Core/Services/AttachedService.cs +++ b/SteUp.Maui/Core/Services/AttachedService.cs @@ -10,12 +10,19 @@ public class AttachedService(ILogger logger) : IAttachedService { public bool IsCameraAvailable => MediaPicker.Default.IsCaptureSupported; - public async Task SelectImageFromCamera() + 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; diff --git a/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor b/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor index 224703d..00dfa18 100644 --- a/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor +++ b/SteUp.Shared/Components/SingleElements/Modal/ModalAddAttached.razor @@ -40,6 +40,21 @@ private async Task OnCamera() { + 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 { diff --git a/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor b/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor index 7a60f47..5e3de39 100644 --- a/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor +++ b/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor @@ -754,12 +754,34 @@ #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() { List? attachedList; if (AttachedService.IsCameraAvailable) { + if (!await AttachedService.RequestCameraPermissions()) + { + ShowCameraPermissionDenied(); + return; + } + AttachedDto? selectImageFromCamera; try { diff --git a/SteUp.Shared/Core/Interface/System/IAttachedService.cs b/SteUp.Shared/Core/Interface/System/IAttachedService.cs index f39fcce..588d61a 100644 --- a/SteUp.Shared/Core/Interface/System/IAttachedService.cs +++ b/SteUp.Shared/Core/Interface/System/IAttachedService.cs @@ -6,6 +6,11 @@ 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(); From 249b3019204a676d3d67d6244090ee414278501f Mon Sep 17 00:00:00 2001 From: MarcoE Date: Wed, 21 Oct 2026 08:51:43 +0200 Subject: [PATCH 4/4] -> 1.2.3 (9) --- SteUp.Maui/SteUp.Maui.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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