feat(mobile): pop a session or a file preview out beside the dashboard from a native wrapper - #432
shenlvkang-collab wants to merge 1 commit into
Conversation
…d from a native wrapper An Android WebView wrapper has no browser pop-ups, so a foldable could not show two sessions, or a session and a file, side by side. A wrapper that can open a window of its own now exposes window.CodemanHost.openWindow(url); detachSession, detachFilePreview and openWebviewExternal hand their URL to it, mobile.css keeps the pop-out icon under html.host-windows, and a solo window closes and raises itself through the host when it offers the calls. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks for this. The two-windows-on-a-foldable problem is real, and you found the honest reason it could not work: a WebView wrapper has no The code is careful. I read all three call sites and both CSS rules and it is genuinely inert without a host: One thing genuinely needs to exist before this lands, and then a handful of one-liners. 1. The seam is documented nowhere. CLAUDE.md says third-party integration surfaces live in
A short "Seam 5: native wrapper windows" section covering the three methods, the return contract and the BroadcastChannel requirement would do it, plus one line saying the contract is outside 2. 3. 4. No liveness at all when BroadcastChannel is missing ( 5. The host-aware default is duplicated ( Smaller:
One call that is mine rather than yours, and I want to be straight about it since you have done the work already: this adds a Send those up and I will merge. If you want this in the next release, items 2 through 5 are the ones I need; the docs section can follow if it would hold you up, though I would rather land them together. |
On a foldable, the natural way to watch two sessions, or a session and a file, is two windows side by side. A browser can pop a session out with
window.open, but an Android WebView wrapper has no pop-ups, andmobile.csshides the pop-out icon at those widths anyway. So a wrapper app had no way to reuse the solo window (/session/<id>) or the file viewer's detach route.This adds a small, opt-in host contract. An embedding app that can open a page in a window of its own exposes:
window.CodemanHost.openWindow(absoluteUrl)→ whether a window opened (required)window.CodemanHost.closeWindow()/focusWindow()(optional; script-initiatedwindow.close()/focus()do nothing in a window the page did notwindow.open)When
openWindowis present:detachSessionhands the solo URL to the host instead ofwindow.open, marks the tab detached, and announces it on the window channel. Since there is no WindowProxy to poll, liveness uses the same roll-call path a reloaded dashboard already uses. The solo window's announcements andpagehidekeep working unchanged. If the host refuses, the tab stays docked and a toast appears.detachFilePreviewandopenWebviewExternalalso go through the host.html.host-windowskeeps the tab pop-out icon at tablet widths (600–768px), andshowTabDetachButtondefaults on when unset. Phone tabs (≤599px) still hide it with!important, so the gear + close tap-zone arithmetic inmobile-tab-tap-zonesstays valid. At that width the host offers the pop-out from its own chrome viaapp.detachSession(id).close-requestgo throughcloseWindow()when the host offers it.Browsers define none of this, so desktop and mobile browser behaviour is unchanged.
openInHostWindowreturnsnullwhen there is no host, and every call site falls through to the existingwindow.opencode.Validation:
test/host-window-detach.test.ts(5 tests, vm-loadedapp.js): the host path, a refusing host, a throwing host, the no-host fallthrough, and solo close/focus via the host.test/file-preview-detach.test.tsgained 2 host cases.mobile-tab-tap-zonesandfoldable-layout.CodemanHost: at 700px the icon is visible and tapping it callsopenWindow('<origin>/session/<id>'); at 440px the icon is hidden andapp.detachSessiontakes the same path. Opening that URL in a second page gives solo mode, the dashboard tab staysdetachedacross a roll-call, the solo re-dock button callscloseWindow(), and after the page closes the dashboard redocks. Without a host at 700px and 1280px there is nohost-windowsclass and no icon (unchanged).FLAG_ACTIVITY_LAUNCH_ADJACENT) has not been done yet. I am not claiming a physical-foldable test.Includes a minor changeset. AI-assisted; implementation and validation reviewed locally.
🤖 Generated with Claude Code