ca0aaf69b5
Lo splash era rosa (#FDECEA) mentre l'app apre su #E9EDF2: a ogni avvio si vedeva un lampo di colore prima della prima schermata. Ora e' la stessa superficie, e il passaggio non si nota. Il tema dello splash deriva da quello generato da MAUI e chiede le icone di sistema scure, coerenti con lo sfondo chiaro. Su Android 12+ lo splash e' disegnato dal sistema, che dell'attributo puo' non tenere conto: sul terminale di prova le icone restano chiare per la frazione di secondo dello splash. Marchio da 128 a 112: su 360 punti di larghezza riempiva troppo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
147 lines
6.2 KiB
C#
147 lines
6.2 KiB
C#
using Android.App;
|
|
using Android.Content.PM;
|
|
using Android.OS;
|
|
using Android.Views;
|
|
using AndroidX.Core.View;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using SteUp.Shared.Core.Messages.System;
|
|
|
|
namespace SteUp.Maui
|
|
{
|
|
[Activity(
|
|
Theme = "@style/SteUp.SplashTheme",
|
|
MainLauncher = true,
|
|
WindowSoftInputMode = SoftInput.AdjustResize | SoftInput.StateHidden,
|
|
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode |
|
|
ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
|
|
public class MainActivity : MauiAppCompatActivity
|
|
{
|
|
private BackButtonService? _backButton;
|
|
private BlazorBackCallback? _backCallback;
|
|
|
|
protected override void OnCreate(Bundle? savedInstanceState)
|
|
{
|
|
base.OnCreate(savedInstanceState);
|
|
|
|
ApplySystemBarsAppearance();
|
|
HookBackButton();
|
|
|
|
// Da Android 15 (API 35) il edge-to-edge e' forzato e adjustResize non ridimensiona
|
|
// piu' la finestra: la tastiera si limita a coprire la WebView. Riduciamo noi il
|
|
// content view dell'altezza dell'IME cosi' il layout Blazor (100vh) si ricalcola.
|
|
if (FindViewById(Android.Resource.Id.Content) is { } content)
|
|
ViewCompat.SetOnApplyWindowInsetsListener(content, new ImeInsetsListener());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Le barre di sistema si fondono con lo sfondo chiaro dell'app: icone
|
|
/// scure su fondo chiaro. Senza questo la barra di stato resta tinta
|
|
/// dell'accento, che nel sistema di design indica l'azione, non la
|
|
/// cornice.
|
|
/// </summary>
|
|
private void ApplySystemBarsAppearance()
|
|
{
|
|
if (Window is null) return;
|
|
|
|
var controller = WindowCompat.GetInsetsController(Window, Window.DecorView);
|
|
controller.AppearanceLightStatusBars = true;
|
|
controller.AppearanceLightNavigationBars = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Il tasto indietro va intercettato sul dispatcher di AndroidX, non
|
|
/// sovrascrivendo OnBackPressed: da AndroidX Activity 1.6 il gesto passa
|
|
/// tutto di li' e il metodo dell'Activity non viene piu' invocato — la
|
|
/// UI Blazor non riceveva mai il back e il lavoro non salvato del form
|
|
/// se ne andava con la navigazione.
|
|
///
|
|
/// Il callback resta acceso solo finche' c'e' davvero qualcuno in
|
|
/// ascolto: quando la UI non ha nulla da dire, il back torna a
|
|
/// comportarsi come sempre invece di essere inghiottito.
|
|
/// </summary>
|
|
private void HookBackButton()
|
|
{
|
|
_backButton = IPlatformApplication.Current?.Services.GetService<BackButtonService>();
|
|
if (_backButton is null) return;
|
|
|
|
_backCallback = new BlazorBackCallback(_backButton);
|
|
OnBackPressedDispatcher.AddCallback(this, _backCallback);
|
|
|
|
_backCallback.Enabled = _backButton.HasHandlers;
|
|
_backButton.HandlersChanged += OnBackHandlersChanged;
|
|
}
|
|
|
|
private void OnBackHandlersChanged(bool hasHandlers)
|
|
{
|
|
if (_backCallback is null) return;
|
|
|
|
_backCallback.Enabled = hasHandlers;
|
|
if (!hasHandlers) return;
|
|
|
|
// Il dispatcher consulta i callback dall'ultimo registrato al primo,
|
|
// e BlazorWebView registra il suo (che fa tornare indietro la
|
|
// cronologia della WebView) quando l'handler viene creato, cioe' dopo
|
|
// OnCreate. Ri-registrandoci nel momento in cui la UI ha davvero
|
|
// qualcosa da dire torniamo in cima e il back arriva prima a noi.
|
|
_backCallback.Remove();
|
|
OnBackPressedDispatcher.AddCallback(this, _backCallback);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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: ne' l'Activity ne' il dispatcher lo vedono mai.
|
|
/// Qui la chiave passa prima della gerarchia di view, quindi e' l'unico
|
|
/// punto in cui possiamo fermarla mentre un form ha lavoro non salvato.
|
|
/// Il callback sul dispatcher resta per la navigazione a gesti, dove
|
|
/// evento di tastiera non ce n'e'.
|
|
/// </summary>
|
|
public override bool DispatchKeyEvent(KeyEvent? e)
|
|
{
|
|
if (e?.KeyCode == Keycode.Back && _backButton?.HasHandlers == true)
|
|
{
|
|
// Si consuma anche il DOWN: lasciandolo passare la WebView
|
|
// reagirebbe lo stesso.
|
|
if (e.Action == KeyEventActions.Up) _backButton.TryHandleBackPressed();
|
|
return true;
|
|
}
|
|
|
|
return base.DispatchKeyEvent(e);
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
if (_backButton is not null) _backButton.HandlersChanged -= OnBackHandlersChanged;
|
|
|
|
base.OnDestroy();
|
|
}
|
|
|
|
private sealed class BlazorBackCallback(BackButtonService service)
|
|
: AndroidX.Activity.OnBackPressedCallback(false)
|
|
{
|
|
public override void HandleOnBackPressed() => service.TryHandleBackPressed();
|
|
}
|
|
|
|
private sealed class ImeInsetsListener : Java.Lang.Object, IOnApplyWindowInsetsListener
|
|
{
|
|
public WindowInsetsCompat OnApplyWindowInsets(Android.Views.View? v, WindowInsetsCompat? insets)
|
|
{
|
|
if (v is null || insets is null)
|
|
return insets!;
|
|
|
|
var ime = insets.GetInsets(WindowInsetsCompat.Type.Ime()).Bottom;
|
|
var systemBars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars()).Bottom;
|
|
|
|
// La barra di navigazione e' gia' gestita da SafeAreaEdges in MainPage:
|
|
// teniamo solo la parte di tastiera che la eccede, per non sommare due volte.
|
|
var bottom = System.Math.Max(0, ime - systemBars);
|
|
|
|
if (v.PaddingBottom != bottom)
|
|
v.SetPadding(v.PaddingLeft, v.PaddingTop, v.PaddingRight, bottom);
|
|
|
|
return insets;
|
|
}
|
|
}
|
|
}
|
|
}
|