Skip to content

Close the camera editor on Back without leaving the app - #110

Merged
keyldev merged 1 commit into
mainfrom
fix/back-dialog
Nov 7, 2026
Merged

keyldev merged 1 commit into
mainfrom
fix/back-dialog

Conversation

@compot-dev

Copy link
Copy Markdown
Collaborator

Fixes #108.

Back never skipped the dialog: Avalonia on Android delivers Back as Key.Escape as well, so IsCancel on the Cancel button closed the form, and the Back that followed 16–50 ms later found no dialog open and sent the app to the background. CameraEditorContent was the only form with IsCancel, so Discovery, Camera groups and Welcome were not affected.

  • Remove IsCancel; Escape is now handled in CameraEditorWindow, so it works on desktop wherever the focus is. A KeyDown in the content would miss it: with a tap-opened overlay, or when editing on desktop, the focus is outside the form.
  • On Android the form now closes through the regular TryDismissTopmost path, which does not call Finish, so a pending connect is cancelled when the form is detached.

Tested on the Android TV 16 emulator, x86_64 local build:

  • Rebased on c76ea65 after Follow-ups to #104, #106 and #107: CI test order, dialog focus, TV keyboard #109; the Back and soft keyboard cases were rerun there.
  • Back closes Add camera and the app stays in front: opened by tap, D-pad and from Welcome. The same for editing a camera.
  • With the soft keyboard open, Back hides it and keeps the form; the next Back closes the form.
  • Back during Connect drops the sockets at once, instead of at the 3 s and 5 s timeouts.
  • The form reopens after that, Cancel works, and Back on the root screen still leaves the app.

Desktop Escape checked with a throwaway Avalonia.Headless test, with no focus and with the focus in a text field. Not tested on a real desktop session.

Behaviour change: a separate Esc key on Android no longer closes this form, the same as the other dialogs. Back does.

Not tested: a phone, a physical remote.

Android delivers Back as Escape as well, so IsCancel on the Cancel button
closed the overlay and the Back that followed found nothing open and sent
the app to the background.

Handle Escape in the desktop window instead and leave Android to the system
Back path, which also needs the pending connect cancelled when the form is
detached.

Fixes #108
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Close the camera editor on Android Back without leaving the app

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Remove the Cancel button’s Escape behavior so Android Back reaches overlay dismissal instead of
 backgrounding the app.
• Handle Escape in the desktop editor window, regardless of which field has focus.
• Cancel pending camera connections when Back detaches the editor.
Diagram

graph TD
  I["Dismiss input"] --> P{"Desktop Escape?"} -->|Yes| W["Window handler"] --> C["Editor content"] --> X["Pending connect"]
  P -->|Android Back| B["Back request"] --> O["Overlay presenter"] --> C
Loading
High-Level Assessment

Keep Escape handling in the desktop window and Android Back in the existing overlay path. Restoring IsCancel would recreate the Back conflict, while handling KeyDown in the content could miss Escape when focus is outside the form.

Files changed (3) +15 / -1

Bug fix (3) +15 / -1
CameraEditorContent.axamlRemove automatic Escape cancellation from the Cancel button +1/-1

Remove automatic Escape cancellation from the Cancel button

• Removes IsCancel so Android’s Escape key event cannot close the editor before its Back request dismisses the overlay. The button remains clickable.

src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml

CameraEditorContent.axaml.csCancel connections when the editor is dismissed +5/-0

Cancel connections when the editor is dismissed

• Exposes a Cancel method for the desktop window and cancels pending connection work when the content detaches. This covers Android Back dismissal, which does not call Finish.

src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml.cs

CameraEditorWindow.axaml.csHandle desktop Escape at the window level +9/-0

Handle desktop Escape at the window level

• Handles Escape in the desktop wrapper by cancelling the editor and marking the event handled. Window-level handling allows Escape to work when focus is outside the form.

src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorWindow.axaml.cs

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. A closed editor can still connect to a camera 🐞 Bug ☼ Reliability
Description
DetachedFromVisualTree calls CancelPending(), which only cancels a connection that has already
created its cancellation token. If Back closes an auto-connecting editor while LoadGroupsAsync is
awaiting, the attach handler resumes afterward and starts a camera connection despite the editor
being closed.
Code

src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml.cs[75]

+        DetachedFromVisualTree += (_, _) => (DataContext as CameraEditorViewModel)?.CancelPending();
Evidence
The new detach cleanup relies on CancelPending, but group loading is awaited with
CancellationToken.None before auto-connect is invoked. CancelPending only cancels _connectCts,
and that token is created when ConnectAsync begins; discovery explicitly opens editors with
AutoConnect = true.

src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml.cs[62-75]
src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs[284-290]
src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs[371-387]
src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs[546-547]
src/OpenIPC.Viewer.App/ViewModels/CameraLibraryPageViewModel.cs[582-590]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
System Back can detach an auto-connecting camera editor before its group load completes. `CancelPending()` has no connection to cancel yet, so the attach handler can start a connection after the editor closes.
## Fix Focus Areas
- src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml.cs[62-75]
- src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs[284-298]
## Recommended Fix
Give the attach-time work a cancellation token or lifecycle guard that detachment invalidates. After `LoadGroupsAsync` returns, check that the editor is still attached before focusing a field or executing auto-connect; retain cancellation of connections that have already started.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can hide the parts of a finding you never read, like the evidence or the agent prompt

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@keyldev
keyldev merged commit c9ca5d4 into main Nov 7, 2026
5 of 6 checks passed
@compot-dev
compot-dev deleted the fix/back-dialog branch November 7, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android: Back while a dialog is open sends the app to the background instead of closing the dialog

2 participants