Skip to content

Commit 2799e23

Browse files
authored
Merge pull request #10 from OpenIPC/fix/disable-nav-while-modal-open
fix(nav): disable bottom nav while a mobile modal dialog is open
2 parents 75eefd7 + b3a076f commit 2799e23

2 files changed

Lines changed: 27 additions & 1 deletion

File tree

src/OpenIPC.Viewer.App/Services/OverlayDialogPresenter.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ public static class OverlayDialogPresenter
2929
{
3030
private static readonly TimeSpan FadeIn = TimeSpan.FromMilliseconds(160);
3131

32+
// Number of overlay dialogs currently on screen. Mobile dialogs live in the
33+
// TopLevel.OverlayLayer; the dim Border does not reliably intercept taps on
34+
// the bottom nav, so the shell gates navigation on this instead. Desktop
35+
// uses real modal Windows (ShowDialog) and never goes through here.
36+
private static int _activeCount;
37+
38+
/// <summary>True while at least one overlay (mobile modal) dialog is open.</summary>
39+
public static bool IsAnyOpen => _activeCount > 0;
40+
41+
/// <summary>Raised on the UI thread whenever <see cref="IsAnyOpen"/> may have changed.</summary>
42+
public static event Action? ActiveChanged;
43+
3244
public static async Task<TResult> ShowAsync<TResult>(Control content, Task<TResult> completion)
3345
{
3446
var overlay = GetOverlayLayer();
@@ -82,6 +94,8 @@ public static async Task<TResult> ShowAsync<TResult>(Control content, Task<TResu
8294
};
8395

8496
overlay.Children.Add(dim);
97+
_activeCount++;
98+
ActiveChanged?.Invoke();
8599
// Kick the opacity transition after the first layout pass — set
86100
// synchronously the Avalonia renderer treats it as initial state
87101
// and skips the animation.
@@ -94,6 +108,8 @@ public static async Task<TResult> ShowAsync<TResult>(Control content, Task<TResu
94108
finally
95109
{
96110
overlay.Children.Remove(dim);
111+
_activeCount--;
112+
ActiveChanged?.Invoke();
97113
}
98114
}
99115

src/OpenIPC.Viewer.App/ViewModels/MainWindowViewModel.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,19 @@ public MainWindowViewModel(
6161

6262
WeakReferenceMessenger.Default.Register<OpenCameraMessage>(this);
6363
WeakReferenceMessenger.Default.Register<GoBackToLibraryMessage>(this);
64+
65+
// While a mobile overlay dialog is open the bottom nav must not switch
66+
// pages under it — the dim layer doesn't reliably swallow those taps.
67+
// Re-evaluate CanNavigate whenever an overlay opens/closes; this greys
68+
// out the nav buttons (Avalonia disables a control whose command can't
69+
// execute). This VM is an app-lifetime singleton, so the static
70+
// subscription lives as long as the process — no unsubscribe needed.
71+
OverlayDialogPresenter.ActiveChanged += () => NavigateCommand.NotifyCanExecuteChanged();
6472
}
6573

66-
[RelayCommand]
74+
private static bool CanNavigate() => !OverlayDialogPresenter.IsAnyOpen;
75+
76+
[RelayCommand(CanExecute = nameof(CanNavigate))]
6777
private void Navigate(string target)
6878
{
6979
if (_activeSingleCamera is not null && target != "library")

0 commit comments

Comments
 (0)