Skip to content

ADFA-4399: Floating windows feature#1456

Merged
Daniel-ADFA merged 10 commits into
stagefrom
ADFA-4399-floating-windows
Jun 30, 2026
Merged

ADFA-4399: Floating windows feature#1456
Daniel-ADFA merged 10 commits into
stagefrom
ADFA-4399-floating-windows

Conversation

@Daniel-ADFA

Copy link
Copy Markdown
Contributor

No description provided.

…on (#1449)

feat(ADFA-4400): add floating-window module with docking model and overlay foundation
* feat(ADFA-4400): add floating-window module with docking model and overlay foundation

* feat(ADFA-4401): add floating window chrome

* ADFA-4401: localize floating window chrome accessibility labels
* feat(ADFA-4400): add floating-window module with docking model and overlay foundation

* feat(ADFA-4401): add floating window chrome

* feat(ADFA-4402): add per-window controller and foreground service
* feat(ADFA-4400): add floating-window module with docking model and overlay foundation

* feat(ADFA-4401): add floating window chrome

* feat(ADFA-4402): add per-window controller and foreground service

* feat(ADFA-4403): undock and redock editor and plugin tabs

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@Daniel-ADFA Daniel-ADFA requested a review from jatezzz June 26, 2026 15:41
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a floating-window module, overlay runtime, tab adapters, and editor activity wiring that let file and plugin tabs be undocked into a foreground service and later redocked or closed through docking events.

Changes

Floating window docking

Layer / File(s) Summary
Module setup and contracts
settings.gradle.kts, floating-window/build.gradle.kts, floating-window/src/main/AndroidManifest.xml, floating-window/src/main/java/com/itsaky/androidide/floating/permission/OverlayPermission.kt, floating-window/src/main/java/com/itsaky/androidide/floating/model/*, floating-window/src/main/java/com/itsaky/androidide/floating/window/InitialBounds.kt, floating-window/src/main/java/com/itsaky/androidide/floating/window/OverlayLayoutParams.kt, plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/ui/PluginEditorTabManager.kt
Adds the floating-window module, manifest, overlay permission helper, shared model types, layout helpers, and plugin tab fragment creation.
Docking state and service
floating-window/src/main/java/com/itsaky/androidide/floating/model/DockingManager.kt, floating-window/src/main/java/com/itsaky/androidide/floating/service/FloatingTabService.kt, floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindow.kt
Adds the docking state manager, foreground service, and floating window runtime that updates bounds, switches modes, handles focus and touch behavior, and renders tab content.
Overlay hosts and content adapters
floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindowHost.kt, floating-window/src/main/java/com/itsaky/androidide/floating/fragment/OverlayFragmentHost.kt, app/src/main/java/com/itsaky/androidide/editor/floating/*, app/src/main/java/com/itsaky/androidide/api/ActionContextProvider.kt, app/src/main/java/com/itsaky/androidide/api/IDEApiFacade.kt
Adds the overlay window host, fragment host, dockable content contract, and the editor and plugin tab adapters used by floating content.
Theme and chrome
floating-window/src/main/java/com/itsaky/androidide/floating/ui/FloatingTheme.kt, floating-window/src/main/java/com/itsaky/androidide/floating/ui/FloatingWindowChrome.kt, app/src/main/java/com/itsaky/androidide/editor/floating/ChromeControlTooltips.kt, idetooltips/src/main/java/com/itsaky/androidide/idetooltips/TooltipTag.kt, floating-window/src/main/java/com/itsaky/androidide/floating/model/ChromeControl.kt, floating-window/src/main/java/com/itsaky/androidide/floating/model/DockAction.kt, app/src/main/java/com/itsaky/androidide/utils/ActionMenuUtils.kt, plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/FileOpenExtension.kt, resources/src/main/res/values/strings.xml
Adds Compose theming, floating-window chrome, tooltip tag plumbing, and plugin menu tooltip metadata.
Controller and editor wiring
app/build.gradle.kts, app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt, app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt, resources/src/main/res/values/strings.xml
Adds the app dependency on the floating-window module and wires the editor tab menus, activity lifecycle handling, and run-action error handling used by floating undock actions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested reviewers

  • jatezzz
  • itsaky-adfa
  • jomen-adfa

Possibly related PRs

Poem

(_/)
(•‿•) A bunny built a floating nook,
/ >🪟 Then docked and undocked by the book.
With tooltips, chrome, and tabs that roam,
I twitch my nose—there’s no place like home.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No description was provided, so there is no meaningful summary to assess. Add a brief description of the floating windows changes and main user impact.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is clearly related to the main change: adding floating window support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ADFA-4399-floating-windows

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/src/main/java/com/itsaky/androidide/editor/floating/EditorPanelDockableContent.kt`:
- Around line 75-78: The teardown currently only happens in release(), but the
floating-window lifecycle expects EditorPanelDockableContent to clean up in
onDestroyView(). Add the DockableContent.onDestroyView() implementation to
invoke the same CodeEditorView.close() and null-out logic used by release(), so
the editor is always released even when the overlay is destroyed outside the
redock flow.

In
`@app/src/main/java/com/itsaky/androidide/editor/floating/IdeFloatingTabController.kt`:
- Around line 65-70: In IdeFloatingTabController’s floating-tab flow, the
original tab is being removed too early, before the floating copy is confirmed
to exist. Reorder the logic so remove() is only called after
DockingManager.undock and FloatingTabService.ensureRunning complete
successfully, or gate it behind a successful floating-host creation path, so the
docked tab can be restored if the floating setup fails.
- Around line 44-47: The undock flow in IdeFloatingTabController.launch
currently proceeds to mark the panel saved and close the file unconditionally
after panel.save(). Update this path so the save result is checked first; if
panel.save() returns false, stop the coroutine flow and do not call
panel.markAsSaved() or activity.closeFile(...). Keep the existing save/close
sequence only when the save succeeds.
- Around line 29-33: The event collection in IdeFloatingTabController.start is
tied to activity.lifecycleScope, so DockingManager.events can be missed when the
activity is recreated or inactive. Move the collection out of the activity
lifecycle (for example, use an application-wide scope) or change
DockingManager.events to a MutableSharedFlow with replay = 1 so new subscribers
still receive the latest Redock/Close event. Keep the fix centered around
start() and DockingManager.events.

In
`@app/src/main/java/com/itsaky/androidide/editor/floating/PluginTabDockableContent.kt`:
- Around line 37-39: `PluginTabDockableContent.createContent` currently returns
`overlayHost.view` even when `PluginEditorTabManager.newTabFragment(tabId)` is
null, which bypasses the existing failure UI. Update the flow so the
`overlayHost` only returns its normal view after `setFragment` succeeds, and
otherwise switch to the fallback error view already implemented for load
failures. Keep the null-handling logic centered around `newTabFragment(tabId)`
and `overlayHost` so a missing plugin fragment is treated as an actual failure.

In `@floating-window/src/main/AndroidManifest.xml`:
- Around line 6-8: Add the missing foreground-service declaration for
FloatingTabService in AndroidManifest.xml: the service that calls
startForeground/startForegroundService needs
android:foregroundServiceType="specialUse" on the <service> entry. Also add the
matching android.permission.FOREGROUND_SERVICE_SPECIAL_USE uses-permission
alongside the other manifest permissions. Update the existing FloatingTabService
declaration rather than introducing a new service entry.

In
`@floating-window/src/main/java/com/itsaky/androidide/floating/model/DockingManager.kt`:
- Around line 28-29: The event flow in `DockingManager.dock()` and
`DockingManager.close()` can desynchronize `_windows` from the UI because state
is removed before `MutableSharedFlow.tryEmit()` is confirmed. Update these
methods so the removal only happens after a successful emission, or handle the
`false` return from `_events.tryEmit(...)` by aborting the mutation and
preserving the tab in `_windows`. If the caller can suspend, prefer using a
coroutine-backed `emit` path; otherwise ensure `DockingEvent` delivery is
guaranteed before mutating state.

In
`@floating-window/src/main/java/com/itsaky/androidide/floating/service/FloatingTabService.kt`:
- Around line 89-97: The undock recovery in FloatingTabService is marking a tab
as floating before FloatingWindow.show() has actually succeeded, and the failure
path closes the tab instead of restoring it. Update the attach flow so
FloatingWindow.show() reports success/failure, only store the window in windows
after a successful attach, and on exceptions redock the tab through
DockingManager rather than calling DockingManager.close; use FloatingTabService,
FloatingWindow.show(), and the existing windows/failed handling to keep the tab
recoverable.

In
`@floating-window/src/main/java/com/itsaky/androidide/floating/ui/FloatingWindowChrome.kt`:
- Around line 251-261: The `combinedClickable` click handler in
`FloatingWindowChrome.kt` is swallowing all failures from
`DockAction.onInvoke()` by using `runCatching`, which also hides cancellation
and unexpected errors. Replace the broad catch with narrow handling for only the
expected failure path around the `action.onInvoke()` call, and let other
exceptions propagate or be logged. Keep the existing confirm/`ACTION_CONFIRM_MS`
behavior intact in the `onClick` coroutine.
- Around line 112-116: The resize grip in FloatingWindowChrome is still shown
even when the window is maximized, but FloatingWindow.resizeBy() does nothing
outside WindowMode.NORMAL, so hide this dead UI in non-normal modes. Update the
ResizeHandle rendering in FloatingWindowChrome to be conditional on the current
window mode, using the same state or mode source already available to the
composable, so the handle is only visible when resizing is actually supported.

In
`@floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindow.kt`:
- Around line 98-104: The show() method in FloatingWindow currently swallows
addView() failures via runCatching, which prevents
FloatingTabService.reconcile() from detecting and recovering from a failed show.
Remove the exception suppression in show(), keep the existing
host.attach(rootView) and windowManager.addView(rootView, params) flow, and let
addView() errors propagate so the service can retry or close the window; keep
the added flag update only on success.

In
`@floating-window/src/main/java/com/itsaky/androidide/floating/window/InitialBounds.kt`:
- Around line 22-27: The cascaded window position logic in
InitialBounds.calculate/WindowBounds only clamps to zero, so later cascade steps
can place windows beyond the visible viewport. Update the x and y calculations
to clamp within both bounds: keep the current centered base plus cascade step,
but also cap each coordinate at the maximum visible position derived from
metrics.widthPixels/heightPixels minus the window size before returning
WindowBounds, so OverlayLayoutParams.create receives on-screen coordinates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 395f6d7f-d1d9-4b3e-8438-cc1c54f34def

📥 Commits

Reviewing files that changed from the base of the PR and between 2354af1 and 3bd4bf4.

📒 Files selected for processing (26)
  • app/build.gradle.kts
  • app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
  • app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
  • app/src/main/java/com/itsaky/androidide/editor/floating/EditorPanelDockableContent.kt
  • app/src/main/java/com/itsaky/androidide/editor/floating/IdeFloatingTabController.kt
  • app/src/main/java/com/itsaky/androidide/editor/floating/PluginTabDockableContent.kt
  • floating-window/build.gradle.kts
  • floating-window/src/main/AndroidManifest.xml
  • floating-window/src/main/java/com/itsaky/androidide/floating/fragment/OverlayFragmentHost.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/DockAction.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/DockableContent.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/DockingEvent.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/DockingManager.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/FloatingTab.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/permission/OverlayPermission.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/service/FloatingTabService.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/ui/FloatingTheme.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/ui/FloatingWindowChrome.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindow.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindowHost.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindowState.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/window/InitialBounds.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/window/OverlayLayoutParams.kt
  • plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/ui/PluginEditorTabManager.kt
  • resources/src/main/res/values/strings.xml
  • settings.gradle.kts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/FileOpenExtension.kt (1)

19-27: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve the existing FileTabMenuItem ABI. Adding tooltipTag to the primary constructor changes the generated constructor, copy(...), and componentN() signatures for this public data class. Independently compiled plugins can fail with linkage errors unless they’re rebuilt, so keep the old constructor shape compatible or make this an explicit plugin-API version bump.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/FileOpenExtension.kt`
around lines 19 - 27, The public FileTabMenuItem data class has an ABI-breaking
primary constructor change because tooltipTag was added, which alters the
generated constructor, copy, and componentN signatures. Update FileTabMenuItem
in FileOpenExtension.kt to preserve the existing constructor shape for binary
compatibility, or move tooltipTag behind a compatibility-safe API change; if the
new parameter must stay, make this an explicit plugin-api version bump and keep
the old entry points available.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/com/itsaky/androidide/api/IDEApiFacade.kt`:
- Around line 100-114: The one-time build listener remains registered even when
IDEApiFacade’s action launch fails synchronously, so it can later try to resume
an already-completed continuation. Fix this by either moving the listener
registration in IDEApiFacade.executeAction flow until after the null-registry
and registry.executeAction failure paths are cleared, or by explicitly
unregistering the listener before each early ToolResult.failure resume in the
registry == null branch and the catch block.

In
`@app/src/main/java/com/itsaky/androidide/editor/floating/ChromeControlTooltips.kt`:
- Around line 18-24: The tagFor(ChromeControl) mapping assigns
ChromeControl.CLOSE to TooltipTag.WINDOW_UNDOCK, which shows the wrong tooltip
for the close button. Update the ChromeControl.CLOSE branch in
ChromeControlTooltips.tagFor to use a close-specific tooltip tag if one exists,
or return null instead of reusing the undock copy. Keep the existing mappings
for MINIMIZE, MAXIMIZE, and DOCK unchanged.

---

Outside diff comments:
In
`@plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/FileOpenExtension.kt`:
- Around line 19-27: The public FileTabMenuItem data class has an ABI-breaking
primary constructor change because tooltipTag was added, which alters the
generated constructor, copy, and componentN signatures. Update FileTabMenuItem
in FileOpenExtension.kt to preserve the existing constructor shape for binary
compatibility, or move tooltipTag behind a compatibility-safe API change; if the
new parameter must stay, make this an explicit plugin-api version bump and keep
the old entry points available.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2a082996-051b-4c36-b56c-30d30f53faab

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd4bf4 and d0b78c3.

📒 Files selected for processing (15)
  • app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
  • app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
  • app/src/main/java/com/itsaky/androidide/api/ActionContextProvider.kt
  • app/src/main/java/com/itsaky/androidide/api/IDEApiFacade.kt
  • app/src/main/java/com/itsaky/androidide/editor/floating/ChromeControlTooltips.kt
  • app/src/main/java/com/itsaky/androidide/editor/floating/EditorPanelDockableContent.kt
  • app/src/main/java/com/itsaky/androidide/editor/floating/PluginTabDockableContent.kt
  • app/src/main/java/com/itsaky/androidide/utils/ActionMenuUtils.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/ChromeControl.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/DockAction.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/DockableContent.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/ui/FloatingWindowChrome.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindow.kt
  • idetooltips/src/main/java/com/itsaky/androidide/idetooltips/TooltipTag.kt
  • plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/FileOpenExtension.kt
✅ Files skipped from review due to trivial changes (1)
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/ChromeControl.kt
🚧 Files skipped from review as they are similar to previous changes (5)
  • floating-window/src/main/java/com/itsaky/androidide/floating/model/DockAction.kt
  • app/src/main/java/com/itsaky/androidide/editor/floating/PluginTabDockableContent.kt
  • app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
  • app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
  • floating-window/src/main/java/com/itsaky/androidide/floating/window/FloatingWindow.kt

Comment thread app/src/main/java/com/itsaky/androidide/api/IDEApiFacade.kt
…ing-window error string

- EditorHandlerActivity.undockPluginTab: use the already-imported PluginEditorTabManager short name instead of the fully-qualified name.
- PluginTabDockableContent: move the hardcoded error message into strings.xml (msg_floating_window_open_failed) and resolve it via context.getString().
@Daniel-ADFA Daniel-ADFA requested a review from jatezzz June 29, 2026 21:52
The compose-preview module was removed from stage in a separate PR. The
merge into this branch kept the now-dangling implementation(projects.composePreview)
in app/build.gradle.kts, causing 'Unresolved reference: composePreview' at script
compilation. No source references the compose.preview package anymore, so removing
the dependency is sufficient.
@Daniel-ADFA Daniel-ADFA merged commit d1c9c07 into stage Jun 30, 2026
2 checks passed
@Daniel-ADFA Daniel-ADFA deleted the ADFA-4399-floating-windows branch June 30, 2026 11:08
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.

2 participants