Finora la foto si poteva togliere solo prima di salvare la scheda.
- La X compare su tutte le foto (non in sola lettura, non mentre la foto e'
ancora in elaborazione). L'eliminazione avviene al salvataggio: uscendo
senza salvare le foto restano.
- Una foto gia' inviata si toglie prima dal server (nuovo endpoint
steup/removeAttachment), poi dal dispositivo e da Scheda.ImageNames. Senza
rete la X avvisa e non la toglie; se il server non conferma al salvataggio
la foto resta ovunque e compare un avviso.
- Una foto salvata ma non ancora inviata si elimina dal dispositivo (con la
rete si prova anche a toglierla dal server, senza bloccare).
- Togliere una foto salvata non la cancellava mai: il flag ToRemove finiva
su un elemento appena rimosso dall'elenco. Ora le foto tolte stanno in una
lista a parte fino al salvataggio; ToRemove e' stato eliminato.
- FileManager.GetInspectionFiles: le foto in /toUpload si filtravano per
nome, ma ImageNames contiene il percorso completo, quindi quelle salvate
senza rete non ricomparivano mai riaprendo la scheda. Ora si accetta sia il
percorso sia il nome, e il DTO porta anche i byte del file per l'invio.
Richiede i Servizi con steup/removeAttachment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
Le foto venivano zippate tutte in un unico allegato: oltre i 100 MB i servizi
rifiutavano l'invio (MaxUploadSizeExceededException) e, costruendo tutto in RAM
sul thread della UI, il dispositivo si bloccava.
- Invio diviso in più email da massimo ~40 MB ciascuna
- Zip scritti su disco una parte alla volta e caricati in streaming
- Preparazione in background, avanzamento "parte X di N"
- Richiesta se includere le foto, con il loro peso (default: solo i log)
- Database inviato insieme al file -wal
- Avviso subito se si è offline
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Il tasto al centro perde l'etichetta: non ne ha una sola, perche' quello
che fa lo decide la schermata sotto. Dentro un'ispezione apre le sue
azioni (nuova scheda, concludi, elimina); altrove apre una nuova
ispezione. Il glifo resta lo stesso e resta nello stesso punto: quello
che cambia e' cosa c'e' dietro, non dove mettere il dito.
Le azioni dell'ispezione lasciano quindi la testata, dove stavano dietro
un menu a tre punti, e tornano sotto il pollice.
Il collegamento passa da PageActionsService: la pagina si registra
finche' e' a video e si sfila uscendo, cosi' la barra non tiene in vita
schermate che non ci sono piu'. Chi non registra niente lascia al
comando il suo significato di default — un'ispezione conclusa non
registra, e il tasto non resta li' a non fare nulla.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Il "+" stava incastrato a destra nella barra di navigazione, che per il resto
contiene destinazioni. Cambiava significato da una schermata all'altra senza
mai dichiararlo, e su Ispezioni apriva un menu per far scegliere fra una cosa
sola. Il documento di stile esclude esplicitamente il FAB di serie, e la barra
torna a contenere solo le due destinazioni.
Su Ispezioni l'azione e' un bottone con il suo nome nella testata, e porta
dritta alla scelta del punto vendita senza passaggi intermedi. Lo stato vuoto
offre lo stesso comando invece di spiegare dove trovarlo.
Su Ispezione le azioni sono tre e con pesi diversi: restano in un bottom sheet,
aperto dalla testata. Eliminare un'ispezione ora chiede conferma — prima un
tocco cancellava ispezione e schede senza appello.
Le azioni vivono nella pagina che le esegue, quindi i messaggi che le
rimbalzavano dalla barra (NewSchedaService, CompleteInspectionService) non
hanno piu' mittente e se ne vanno.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Il salvataggio come bozza non e' mai scattato dal tasto indietro: la UI Blazor
non riceveva l'evento, e uscire da un form con modifiche in corso buttava via
il lavoro esattamente come prima che la bozza esistesse.
Il back non arrivava a OnBackPressed per due motivi diversi:
- da AndroidX Activity 1.6 il gesto passa dall'OnBackPressedDispatcher e il
metodo dell'Activity non viene piu' invocato;
- con la navigazione a tre tasti il back arriva come evento di tastiera e la
WebView lo intercetta per conto suo, tornando indietro nella propria
cronologia, prima che Activity o dispatcher lo vedano.
Ora la chiave si ferma in DispatchKeyEvent, che passa prima della gerarchia di
view, e resta un callback sul dispatcher per la navigazione a gesti, dove
evento di tastiera non ce n'e'. Entrambi restano accesi solo finche' la UI ha
davvero qualcosa da dire: altrimenti il back si comporta come sempre.
I gestori diventano una pila, cosi' sopra il form puo' aprirsi un bottom sheet
e il back chiude prima quello senza portarsi via la registrazione sottostante.
ActionSheet si registra da solo mentre e' aperto.
Verificato sull'EDA52: back sul form con modifiche apre "Lavoro non salvato" e
salva la bozza; back sullo sheet chiude solo lo sheet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adotta lo stile condiviso delle app Integry: superfici piatte, raggi ampi,
spaziature a scala fissa, gerarchia data dallo spazio prima che dalla
decorazione. La palette storica di SteUP resta intatta; sono stati aggiunti
solo i ruoli che mancavano (workspace, surfaceMuted, divider, inkMuted e le
triplette dei toni semantici).
Fondamenta
- tokens.css: ruoli colore, scale di spazio/raggi/tipografia, curve di
movimento e scala z-index semantica. Unica fonte di verita': pilotano
anche le variabili CSS di MudBlazor.
- Inter variabile ospitata in locale (133KB) al posto di Nunito da Google
Fonts: l'app lavora offline, un font che arriva dalla rete in campo non
arriva.
- base.css: shell applicativa e comportamenti da app nativa — niente
selezione testo, niente menu al tocco lungo, niente lampo grigio sul tap,
niente rimbalzo elastico, niente zoom a doppio tocco, scroll con inerzia.
- mudblazor-overrides.css: MudBlazor appiattito (elevation 0, nessun tint,
target 44/48, etichette in caso naturale).
- Rimossi Bootstrap (CSS, icone e JS) e i 996 righe di CSS con ambito per
componente del vecchio sistema: erano tutti inutilizzati.
Struttura
- Navigazione flottante in basso con icona piena sulla voce attiva; da 720px
diventa colonna laterale. Il MudFabMenu e' sostituito da un bottom sheet:
stessa funzione, bersagli molto piu' grandi.
- Testata alta col titolo a sinistra, fusa con la pagina.
- Nel form scheda il salvataggio sta in una barra ancorata in fondo, non in
coda a uno scroll lungo.
- Scelta di punto vendita e articoli a schermo intero con ricerca; la
selezione multipla usa righe da 56px invece di un menu a tendina.
- Urgenza scelta a pillole invece che da una select.
Stato e riscontro
- StatusBadgeHelper: tono, icona ed etichetta di ogni stato in un punto solo,
cosi' lo stesso stato si presenta identico ovunque.
- Scheletri al posto degli spinner; l'overlay bloccante dice sempre cosa sta
facendo; gli stati vuoti suggeriscono la mossa successiva.
- Rimosso il ritardo artificiale di 250ms in InspectionCard, che non
attendeva nulla.
DESIGN.md riscritto sul nuovo sistema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Oltre alle etichette a peso variabile (EAN13/CODE128 a 13 cifre), ora
vengono riconosciuti i CODE128 di 7 cifre che iniziano con '2': si scarta
il prefisso e restano le 6 cifre del PLU, come per DecodeEanPeso.
Uscendo da una scheda a meta' (tasto indietro del dispositivo o "Annulla")
il lavoro veniva scartato. Il tasto indietro non era nemmeno gestito: non
arriva alla WebView e non c'e' stack di navigazione, quindi mandava l'app
in background con i dati solo in memoria.
Nuovo stato Bozza ("Da completare"): salvata in locale, mai inviabile
finche' non viene conclusa.
- Scheda.Bozza + migration additiva (default false: le schede esistenti
non cambiano stato).
- SchedaSyncHelper: terzo SyncState, CountBozze(). CountDaInviare()
esclude le bozze, quindi il badge "da inviare" resta corretto.
- ModalFormScheda: SaveDraft() salva solo in locale senza validazione;
Save() azzera il flag; Submit() avvisa quando il form e' invalido
(prima il tocco su "Salva" sembrava non fare nulla se i campi mancanti
erano fuori schermo); Update() prende preserveActivityId cosi' una
bozza di scheda gia' inviata mantiene il link al server e al
completamento lo aggiorna invece di duplicarlo.
- ConfirmUpdateActivity: il pulsante bozza sta su NoText, non CancelText
(CancelText ritorna null, NoText ritorna false).
- BackButtonService + MainActivity.OnBackPressed: il tasto indietro passa
dallo stesso percorso di "Annulla". Ignorato mentre e' aperto un dialog
figlio, per non mostrare il prompt sotto un altro dialog.
- IspezionePage: "Concludi ispezione" si blocca se ci sono bozze,
"Esporta reparto" le salta, chip "N da completare" per reparto.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ispezione:
- Stato sync visibile: badge per-scheda (Da inviare/Inviato) e contatore
"N da inviare" per reparto (nuovo SchedaSyncHelper)
- Completamento: progresso reale nell'overlay + spunta di successo;
NON completa se una scheda fallisce (resta editabile, schede "Da inviare")
- Export reparto/completamento blindati: conferma + guardia anti doppio-tap,
try/finally che libera sempre l'overlay
- Accento corallo unico per l'azione "invia"; target di tocco >=44px;
empty state; solo il primo pannello espanso di default
- Tasto "Invia" nascosto sulle schede gia inviate
- Messaggio d'errore comprensibile in campo (dettaglio tecnico nei log)
- Fix OnSchedaModified (index >= 0)
Aspetto card:
- SchedaCard e InspectionCard: superficie Carta + hairline border + ombra
morbida (nuovo token --card-box-shadow); pagina con tinta Grigio Campo
- SchedaCard compattata
Form scheda (ModalFormScheda):
- Tasto Salva/Aggiorna full-width
- Fix "Suggerisci note descrittive": la nota selezionata ora viene inserita
nel campo (metodo async sul thread UI + OnAfterChangeValue)
StatusEnum: etichette in sentence-case
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>