Il comando della barra si adatta alla schermata

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>
This commit is contained in:
2026-09-17 15:44:55 +02:00
parent 9703fca306
commit 13d5400104
5 changed files with 108 additions and 37 deletions
+24 -10
View File
@@ -1,5 +1,7 @@
@implements IDisposable
@inject IDialogService Dialog
@inject PageActionsService PageActions
@using SteUp.Shared.Core.Messages.System
@*
Navigazione flottante in basso (STILE_UI §6.15): il contenuto le scorre
@@ -7,11 +9,11 @@
riposo, piena da selezionata, etichetta sempre visibile in entrambe.
Da 720px diventa una colonna laterale (vedi components.css).
In mezzo alle due destinazioni sta l'unica azione dell'app: aprire una
nuova ispezione. Non e' un pulsante che galleggia sopra la barra e ne
copre il centro, e' la terza casella della barra, alla stessa altezza
delle altre due. Vale una cosa sola dappertutto: se cambiasse significato
da una pagina all'altra sarebbe un tasto da indovinare.
In mezzo alle due destinazioni sta il comando. Non e' un pulsante che
galleggia sopra la barra e ne copre il centro: e' la casella centrale,
alla stessa altezza delle altre due. Sta sempre nello stesso punto, ma
quello che fa lo decide la schermata sotto (vedi PageActionsService):
dentro un'ispezione apre le sue azioni, altrove apre una nuova ispezione.
*@
<nav class="navbar @(IsVisible ? "" : "navbar--hidden")" aria-label="Navigazione principale">
@@ -22,12 +24,11 @@
<span class="navbar__label">Ispezioni</span>
</NavLink>
<button type="button" class="navbar__action" @onclick="NewInspection"
<button type="button" class="navbar__action" @onclick="RunAction"
disabled="@(!NetworkService.IsNetworkAvailable())"
aria-label="Nuova ispezione"
title="@(NetworkService.IsNetworkAvailable() ? null : "Serve la connessione per aprire una nuova ispezione")">
aria-label="@ActionLabel"
title="@(NetworkService.IsNetworkAvailable() ? ActionLabel : "Serve la connessione")">
<i class="ri-add-line" aria-hidden="true"></i>
<span class="navbar__action-label">Nuova</span>
</button>
<NavLink class="navbar__item pressable" href="user" Match="NavLinkMatch.All">
@@ -49,12 +50,17 @@
private bool IsOn(string route) => CurrentRoute.EqualsIgnoreCase(route);
private string ActionLabel => PageActions.HasActions ? "Azioni" : "Nuova ispezione";
protected override void OnInitialized()
{
NavigationManager.LocationChanged += OnLocationChanged;
PageActions.Changed += OnPageActionsChanged;
Refresh();
}
private void OnPageActionsChanged() => InvokeAsync(StateHasChanged);
private void OnLocationChanged(object? sender, LocationChangedEventArgs args) => Refresh();
private void Refresh()
@@ -63,6 +69,10 @@
StateHasChanged();
}
/// Il comando vale quello che la schermata gli ha dato; se non gliel'ha
/// dato nessuno, vale la cosa che l'app fa piu' spesso.
private Task RunAction() => PageActions.HasActions ? PageActions.Invoke() : NewInspection();
private async Task NewInspection()
{
if (!await SteupDataService.CanOpenNewInspection())
@@ -77,5 +87,9 @@
await Dialog.OpenSelectShop();
}
public void Dispose() => NavigationManager.LocationChanged -= OnLocationChanged;
public void Dispose()
{
NavigationManager.LocationChanged -= OnLocationChanged;
PageActions.Changed -= OnPageActionsChanged;
}
}
@@ -13,27 +13,20 @@
@using SteUp.Shared.Core.Interface.IntegryApi
@using SteUp.Shared.Core.Interface.LocalDb
@using SteUp.Shared.Core.Interface.System
@using SteUp.Shared.Core.Messages.System
@inject IIspezioniService IspezioniService
@inject IDialogService Dialog
@inject IIntegrySteupService IntegrySteupService
@inject IFileManager FileManager
@inject ILogger<IspezionePage> Logger
@inject PageActionsService PageActions
@implements IDisposable
<HeaderLayout Title="@Titolo" Subtitle="@Sottotitolo" Back="true">
<Actions>
@* Su un'ispezione conclusa resta solo la consultazione: niente azioni. *@
@if (!IsCompleted)
{
@* Qui le azioni sono piu' d'una e non hanno lo stesso peso: lo
sheet le mostra con nome, icona e tono, invece di nasconderle
tutte dietro lo stesso glifo. *@
<button type="button" class="appbar__icon-action" @onclick="@(() => _actionsOpen = true)"
aria-label="Azioni sull'ispezione" title="Azioni">
<i class="ri-more-2-fill" aria-hidden="true"></i>
</button>
}
</Actions>
</HeaderLayout>
@* Le azioni non stanno nella testata: le apre il comando al centro della
barra in basso, che finche' questa schermata e' a video significa "azioni
di questa ispezione" (vedi PageActionsService). Su un'ispezione conclusa
non si registra nulla e resta solo la consultazione. *@
<HeaderLayout Title="@Titolo" Subtitle="@Sottotitolo" Back="true"/>
<ActionSheet @bind-Open="_actionsOpen" Title="Azioni ispezione" Subtitle="@Ispezione.CodMdep">
<div class="stack stack-xs">
@@ -253,7 +246,26 @@
private string Sottotitolo => Ispezione.CodMdep;
protected override void OnInitialized() => LoadSchede();
private IDisposable? _actionsRegistration;
protected override void OnInitialized()
{
LoadSchede();
// Su un'ispezione conclusa non c'e' niente da fare: il comando della
// barra si tiene il suo significato di default invece di aprire uno
// sheet di azioni tutte spente.
if (!IsCompleted)
_actionsRegistration = PageActions.Register(() => InvokeAsync(OpenActions));
}
private void OpenActions()
{
_actionsOpen = true;
StateHasChanged();
}
public void Dispose() => _actionsRegistration?.Dispose();
private void LoadSchede()
{