Skip to content

ADFA-3048 | Implement landscape immersive mode for editor#1101

Open
jatezzz wants to merge 1 commit intostagefrom
feat/ADFA-3048-landscape-immersive-mode
Open

ADFA-3048 | Implement landscape immersive mode for editor#1101
jatezzz wants to merge 1 commit intostagefrom
feat/ADFA-3048-landscape-immersive-mode

Conversation

@jatezzz
Copy link
Collaborator

@jatezzz jatezzz commented Mar 20, 2026

Description

This PR introduces an immersive mode for the editor when in landscape orientation. It adds the LandscapeImmersiveController to manage the auto-hiding and toggling of the top and bottom toolbars. A new TouchObservingLinearLayout was implemented to wrap the app bar content, ensuring that the auto-hide delay is paused while the user is actively interacting with the top bar. Additionally, system window inset handling was updated to properly apply padding and margins during the immersive state.

Details

  • Added top and bottom toggle buttons to content_editor.xml (using a new hollow green circle drawable).
  • Top bar now automatically hides after a 3.5-second delay (if not interacted with).
  • Bottom bar translations are animated and synchronized with the BottomSheetBehavior.
  • Handled safe areas and system bar insets dynamically as the app bar expands/collapses.
Screen_Recording_20260320_161536_Code.on.the.Go.mp4

Ticket

ADFA-3048

Observation

The LandscapeImmersiveController binds directly to AppBarLayout.OnOffsetChangedListener and BottomSheetBehavior.BottomSheetCallback to calculate dynamic layout changes smoothly. Note that the toggle buttons are hidden by default in portrait mode and managed dynamically when configuration changes occur.

@jatezzz jatezzz requested a review from a team March 20, 2026 21:22
Adds LandscapeImmersiveController, touch observation, and UI toggles to handle auto-hiding toolbars.
@jatezzz jatezzz force-pushed the feat/ADFA-3048-landscape-immersive-mode branch from afdeec9 to f8d0878 Compare March 20, 2026 21:29
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough
  • Features

    • Adds landscape-only immersive editor mode via a new LandscapeImmersiveController to auto-hide and toggle top (AppBarLayout) and bottom (BottomSheetBehavior) toolbars.
    • Top toolbar auto-hides after a 3.5s inactivity delay; the delay is paused while the user touches the top bar.
    • Manual landscape-only toggle buttons for top and bottom bars added to layouts (hollow green circle drawable).
    • TouchObservingLinearLayout introduced to observe touch events on the app bar content and feed the immersive controller.
    • Window inset handling refactored in BaseEditorActivity.onApplyWindowInsets to correctly apply padding/margins for immersive state, toggle button placement, and bottom sheet/IME interactions.
    • Bottom bar show/hide is animated and synchronized with BottomSheetBehavior; bottom spacing for the editor adjusts when immersive state or bottom bar visibility changes.
    • New drawable: bg_hollow_green_circle.xml (hollow green circle outline).
    • New layout IDs added: btn_toggle_top_bar, btn_toggle_bottom_bar, and editor_appbar_content (TouchObservingLinearLayout).
  • Implementation notes

    • LandscapeImmersiveController binds to AppBarLayout.OnOffsetChangedListener and BottomSheetBehavior.BottomSheetCallback and exposes lifecycle methods: bind(), onPause(), onConfigurationChanged(), onSystemBarInsetsChanged(), destroy().
    • BaseEditorActivity now holds an optional immersiveController and calls lifecycle/configuration/Inset hooks; bottom sheet slide scaling clamps negative offsets.
    • TouchObservingLinearLayout dispatches touch events via onTouchEventObserved callback to pause/resume auto-hide logic.
  • Risks / Best-practice concerns

    • Hardcoded auto-hide delay (3.5s) is not user-configurable — consider exposing as a setting.
    • Controller requires an external CoroutineScope; ensure its lifecycle matches the controller to avoid leaked coroutines.
    • Increased complexity in onApplyWindowInsets (multiple conditional steps) — add tests for system-bar/IME/inset combinations to avoid layout regressions.
    • TouchObservingLinearLayout observes all touch events on the top bar; validate there’s no input or performance regression for interactive toolbar elements.
    • Manual translations of the BottomSheet view to hide/show the peek area may conflict with BottomSheetBehavior animations in edge cases (rapid state changes).
    • Rotation/configuration handling for landscape-only toggles must be validated to avoid visibility glitches across rotations.
    • Ensure destroy()/preDestroy paths remove all listeners and callbacks (AppBar/BottomSheet/touch listeners and coroutine jobs) to prevent memory leaks.

Walkthrough

Adds a landscape-only immersive UI controller and integrates it into BaseEditorActivity, refactors window-inset handling, adds touch-observing layout and toggle button views, and introduces a hollow green circle drawable for toggle backgrounds.

Changes

Cohort / File(s) Summary
Controller & Activity
app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt, app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt
New LandscapeImmersiveController class; BaseEditorActivity creates/binds/notifies/destroys it across lifecycle and refactors onApplyWindowInsets into system-bar, immersive, and IME handling. Bottom sheet slide offset clamped before scaling.
Layouts (land & portrait)
app/src/main/res/layout-land/content_editor.xml, app/src/main/res/layout/content_editor.xml
Added btn_toggle_top_bar and btn_toggle_bottom_bar; replaced appbar child with TouchObservingLinearLayout in landscape, moved progress/tab views into it, set scroll flags, removed animateLayoutChanges.
UI Utility
common/src/main/java/com/itsaky/androidide/ui/TouchObservingLinearLayout.kt
Added TouchObservingLinearLayout that exposes onTouchEventObserved and forwards touch events.
Drawable
app/src/main/res/drawable/bg_hollow_green_circle.xml
Added hollow green circle drawable used as toggle background.

Sequence Diagram(s)

sequenceDiagram
    participant Activity as BaseEditorActivity
    participant Controller as LandscapeImmersiveController
    participant TouchLayout as TouchObservingLinearLayout
    participant AppBar as AppBarLayout
    participant BottomSheet as BottomSheetBehavior

    Activity->>Controller: bind() / onCreate()
    Controller->>TouchLayout: set onTouchEventObserved callback
    Controller->>AppBar: add offset & layout listeners
    Controller->>BottomSheet: add state & slide listeners
    Activity->>Controller: onSystemBarInsetsChanged(topInset)
    Controller->>Controller: update stored inset, adjust paddings/margins

    Note over TouchLayout,Controller: User interacts with app bar
    TouchLayout->>Controller: onTouchEventObserved(MotionEvent)
    Controller->>Controller: cancel auto-hide
    Controller->>Controller: schedule auto-hide after delay

    Note over AppBar,BottomSheet: Auto-hide triggers
    Controller->>AppBar: collapse/hide top bar
    Controller->>BottomSheet: force collapse / hide peek view

    Activity->>Controller: onPause() / preDestroy()
    Controller->>AppBar: remove listeners
    Controller->>BottomSheet: remove listeners
    Controller->>TouchLayout: clear callback
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • Daniel-ADFA
  • itsaky-adfa
  • jomen-adfa

Poem

🐰 I hopped in landscape, ears held high,

I nudged the bars to hide and fly,
Green circles winked at top and bottom,
Quiet editor, peaceful and autumn,
A rabbit's nudge — now code feels spry.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature being implemented: landscape immersive mode for the editor, which aligns perfectly with the primary changes in the changeset.
Description check ✅ Passed The description is directly related to the changeset, providing clear context about the LandscapeImmersiveController, TouchObservingLinearLayout, and system window inset handling updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ADFA-3048-landscape-immersive-mode

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
app/src/main/res/drawable/bg_hollow_green_circle.xml (1)

1-8: Place this drawable in the shared resources module.

This is reusable UI chrome referenced from multiple layouts, so keeping it under app/src/main/res/drawable/ makes it harder to reuse and maintain consistently across modules.

Based on learnings, drawable resources in CodeOnTheGo should reside in ./resources/src/main/res/drawable/, not app/src/main/res/drawable/, so they stay reusable across the application.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/drawable/bg_hollow_green_circle.xml` around lines 1 - 8,
Move the shape drawable resource bg_hollow_green_circle.xml out of the app
module and into the shared resources module so it can be reused; specifically,
relocate the file (the oval shape with stroke and transparent solid) from
app/src/main/res/drawable to the resources module at
resources/src/main/res/drawable, update any references to
R.drawable.bg_hollow_green_circle if needed (ensuring the shared resources
module is added as a dependency to modules that use it), and verify
builds/imports so layouts referencing bg_hollow_green_circle continue to
resolve.
app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt (1)

514-521: Prefer end-aware insets for the toggle margins.

layout_gravity="...|end" follows layout direction, but systemBars.right does not. If this screen is shown in RTL, the toggles will ignore the left-side safe inset.

Possible fix
 private fun applyImmersiveModeInsets(systemBars: Insets) {
 	val content = _binding?.content ?: return
 	val baseMargin = SizeUtils.dp2px(16f)
+	val endInset =
+		if (content.root.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+			systemBars.left
+		} else {
+			systemBars.right
+		}

 	content.btnToggleTopBar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
 		topMargin = baseMargin + systemBars.top
-		marginEnd = baseMargin + systemBars.right
+		marginEnd = baseMargin + endInset
 	}

 	content.btnToggleBottomBar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
 		bottomMargin = baseMargin + systemBars.bottom
-		marginEnd = baseMargin + systemBars.right
+		marginEnd = baseMargin + endInset
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`
around lines 514 - 521, The toggle margin calculations use the absolute inset
(systemBars.right) so they break in RTL; update the two places where
content.btnToggleTopBar and content.btnToggleBottomBar call updateLayoutParams
to use systemBars.end (not systemBars.right) when computing marginEnd (i.e., set
marginEnd = baseMargin + systemBars.end) so the end-aware inset respects layout
direction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`:
- Around line 494-503: applyStandardInsets currently moves the status-bar top
inset onto editorAppbarContent when present but onSwipeRevealDragProgress still
animates padding on editorAppBarLayout, causing double top padding during drawer
drag; fix by making both places target the same view: either keep
applyStandardInsets applying top inset to editorAppBarLayout and update
onSwipeRevealDragProgress to animate editorAppBarLayout, or (preferred) keep
applyStandardInsets applying the inset to editorAppbarContent and change
onSwipeRevealDragProgress so it animates editorAppbarContent instead of
editorAppBarLayout; update all references to updatePadding calls in
applyStandardInsets and the padding animation in onSwipeRevealDragProgress to
use the same view (editorAppbarContent or editorAppBarLayout) and remove the
duplicated top inset application.
- Around line 693-696: The activity handles orientation changes without
recreation, but onConfigurationChanged in BaseEditorActivity calls
immersiveController?.onConfigurationChanged(newConfig) while the inflated
portrait layout lacks the required editor_appbar_content
wrapper/TouchObservingLinearLayout used by immersive mode; fix by detecting
orientation change in BaseEditorActivity.onConfigurationChanged and
rebinding/reinflating the appropriate layout (or swapping to the landscape
binding) before calling immersiveController?.onConfigurationChanged so the
editor_appbar_content and its scroll flags are present; target symbols:
onConfigurationChanged, immersiveController, editor_appbar_content,
TouchObservingLinearLayout, and the activity’s view-binding/rebind logic.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt`:
- Around line 128-132: onPause() currently cancels the auto-hide job
(cancelAutoHide()) and clears isUserInteractingWithTopBar without a resume path,
so if the top bar was visible it will remain pinned after returning; add an
onResume() method on LandscapeImmersiveController that checks the top-bar
visibility state (e.g., isTopBarVisible or similar) and re-schedules the
auto-hide job (call the existing schedule/start auto-hide helper) only when the
top bar is visible and the user is not interacting, then invoke
immersiveController?.onResume() from BaseEditorActivity.onResume() to restore
the auto-hide behavior.

In `@app/src/main/res/layout-land/content_editor.xml`:
- Around line 168-188: Replace the two plain View elements with accessible
clickable widgets (e.g., ImageButton or MaterialButton) for btn_toggle_top_bar
and btn_toggle_bottom_bar, make them focusable/clickable, add appropriate
android:contentDescription for TalkBack, and ensure a minimum 48dp touch target
by increasing layout_width/layout_height or adding extra padding (or wrap with a
larger touch container) while preserving the existing background drawable
(bg_hollow_green_circle) and visibility attributes; apply the same changes to
both layout variants so the toggles gain proper role, label, and hit area.

---

Nitpick comments:
In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`:
- Around line 514-521: The toggle margin calculations use the absolute inset
(systemBars.right) so they break in RTL; update the two places where
content.btnToggleTopBar and content.btnToggleBottomBar call updateLayoutParams
to use systemBars.end (not systemBars.right) when computing marginEnd (i.e., set
marginEnd = baseMargin + systemBars.end) so the end-aware inset respects layout
direction.

In `@app/src/main/res/drawable/bg_hollow_green_circle.xml`:
- Around line 1-8: Move the shape drawable resource bg_hollow_green_circle.xml
out of the app module and into the shared resources module so it can be reused;
specifically, relocate the file (the oval shape with stroke and transparent
solid) from app/src/main/res/drawable to the resources module at
resources/src/main/res/drawable, update any references to
R.drawable.bg_hollow_green_circle if needed (ensuring the shared resources
module is added as a dependency to modules that use it), and verify
builds/imports so layouts referencing bg_hollow_green_circle continue to
resolve.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 75c9dfb6-7c68-4222-8e81-b26cdceb78eb

📥 Commits

Reviewing files that changed from the base of the PR and between 0a1d98c and afdeec9.

📒 Files selected for processing (6)
  • app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
  • app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt
  • app/src/main/res/drawable/bg_hollow_green_circle.xml
  • app/src/main/res/layout-land/content_editor.xml
  • app/src/main/res/layout/content_editor.xml
  • common/src/main/java/com/itsaky/androidide/ui/TouchObservingLinearLayout.kt

Comment on lines +494 to +503
private fun applyStandardInsets(systemBars: Insets, windowInsets: WindowInsetsCompat) {
val content = _binding?.content ?: return

val appBarContent = content.editorAppbarContent
if (appBarContent != null) {
content.editorAppBarLayout.updatePadding(top = 0)
appBarContent.updatePadding(top = systemBars.top)
} else {
content.editorAppBarLayout.updatePadding(top = systemBars.top)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Landscape drawer drag will now apply the top inset twice.

These lines move the status-bar padding onto editorAppbarContent, but onSwipeRevealDragProgress() still animates editorAppBarLayout padding. Once the drawer starts dragging in landscape, both containers contribute top inset and the toolbar jumps downward.

Possible fix
 private fun onSwipeRevealDragProgress(progress: Float) {
 	_binding?.apply {
 		contentCard.progress = progress
 		val insetsTop = systemBarInsets?.top ?: 0
-		content.editorAppBarLayout.updatePadding(
-			top = (insetsTop * (1f - progress)).roundToInt(),
-		)
+		val topInset = (insetsTop * (1f - progress)).roundToInt()
+		(content.editorAppbarContent ?: content.editorAppBarLayout).updatePadding(top = topInset)
 		memUsageView.chart.updateLayoutParams<ViewGroup.MarginLayoutParams> {
 			topMargin = (insetsTop * progress).roundToInt()
 		}
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`
around lines 494 - 503, applyStandardInsets currently moves the status-bar top
inset onto editorAppbarContent when present but onSwipeRevealDragProgress still
animates padding on editorAppBarLayout, causing double top padding during drawer
drag; fix by making both places target the same view: either keep
applyStandardInsets applying top inset to editorAppBarLayout and update
onSwipeRevealDragProgress to animate editorAppBarLayout, or (preferred) keep
applyStandardInsets applying the inset to editorAppbarContent and change
onSwipeRevealDragProgress so it animates editorAppbarContent instead of
editorAppBarLayout; update all references to updatePadding calls in
applyStandardInsets and the padding animation in onSwipeRevealDragProgress to
use the same view (editorAppbarContent or editorAppBarLayout) and remove the
duplicated top inset application.

Comment on lines +128 to +132
fun onPause() {
cancelAutoHide()
isUserInteractingWithTopBar = false
cancelBottomSheetAnimation()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Pausing the app cancels top-bar auto-hide permanently.

onPause() clears the auto-hide job, but there is no matching resume path that schedules it again when the top bar is still visible. Repro: show the top bar, background the app before 3.5s elapses, return — the bar stays pinned until another tap.

Possible fix
 fun onPause() {
     cancelAutoHide()
     isUserInteractingWithTopBar = false
     cancelBottomSheetAnimation()
 }
+
+fun onResume() {
+    if (isLandscape && isTopBarRequestedVisible && !isUserInteractingWithTopBar) {
+        scheduleTopBarAutoHide()
+    }
+}

And call it from BaseEditorActivity.onResume():

immersiveController?.onResume()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun onPause() {
cancelAutoHide()
isUserInteractingWithTopBar = false
cancelBottomSheetAnimation()
}
fun onPause() {
cancelAutoHide()
isUserInteractingWithTopBar = false
cancelBottomSheetAnimation()
}
fun onResume() {
if (isLandscape && isTopBarRequestedVisible && !isUserInteractingWithTopBar) {
scheduleTopBarAutoHide()
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt`
around lines 128 - 132, onPause() currently cancels the auto-hide job
(cancelAutoHide()) and clears isUserInteractingWithTopBar without a resume path,
so if the top bar was visible it will remain pinned after returning; add an
onResume() method on LandscapeImmersiveController that checks the top-bar
visibility state (e.g., isTopBarVisible or similar) and re-schedules the
auto-hide job (call the existing schedule/start auto-hide helper) only when the
top bar is visible and the user is not interacting, then invoke
immersiveController?.onResume() from BaseEditorActivity.onResume() to restore
the auto-hide behavior.

Comment on lines +168 to +188
<View
android:id="@+id/btn_toggle_top_bar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="top|end"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_hollow_green_circle"
android:visibility="gone"
tools:visibility="visible" />

<View
android:id="@+id/btn_toggle_bottom_bar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_hollow_green_circle"
android:visibility="gone"
tools:visibility="visible" />
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

These toggles need real button semantics and a larger hit area.

They are interactive in immersive mode, but plain Views at 24dp here (32dp in the default variant) expose no accessible role/label and miss the 48dp minimum touch target. That makes the bars hard or impossible to toggle for TalkBack and motor-impaired users. Please switch both layout variants to ImageButton/MaterialButton (or similar) and add contentDescription.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/layout-land/content_editor.xml` around lines 168 - 188,
Replace the two plain View elements with accessible clickable widgets (e.g.,
ImageButton or MaterialButton) for btn_toggle_top_bar and btn_toggle_bottom_bar,
make them focusable/clickable, add appropriate android:contentDescription for
TalkBack, and ensure a minimum 48dp touch target by increasing
layout_width/layout_height or adding extra padding (or wrap with a larger touch
container) while preserving the existing background drawable
(bg_hollow_green_circle) and visibility attributes; apply the same changes to
both layout variants so the toggles gain proper role, label, and hit area.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (4)
app/src/main/res/layout-land/content_editor.xml (1)

168-188: ⚠️ Potential issue | 🟠 Major

Toggle buttons lack accessible semantics and minimum touch target.

These toggle View elements at 24×24dp expose no accessible role, label, or focus state, and miss the 48dp minimum touch target recommended by Android accessibility guidelines. This makes the toggles difficult or impossible to use for TalkBack and motor-impaired users.

Consider switching to ImageButton with contentDescription, and ensure a minimum 48dp touch area (via size or padding).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/layout-land/content_editor.xml` around lines 168 - 188,
Replace the bare 24×24dp View toggles (btn_toggle_top_bar and
btn_toggle_bottom_bar) with accessible clickable controls (e.g., ImageButton or
AppCompatImageButton), add contentDescription for TalkBack, set clickable="true"
and focusable="true" (or android:importantForAccessibility="yes"), and ensure a
minimum 48dp touch target by increasing layout_width/layout_height to 48dp or
keeping 24dp visual size but adding 12dp padding/inset to reach 48dp; also
preserve the bg_hollow_green_circle background and gravity/margins so layout
position is unchanged.
app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt (3)

854-871: ⚠️ Potential issue | 🟡 Minor

Missing onResume() call to restore auto-hide behavior.

onPause() (line 845) cancels the top-bar auto-hide job, but onResume() doesn't reschedule it. If the user backgrounds the app while the top bar is visible, upon return the bar will remain pinned indefinitely.

Suggested fix

Add a call to restore auto-hide in onResume():

 override fun onResume() {
     super.onResume()
     invalidateOptionsMenu()
+    immersiveController?.onResume()

     memoryUsageWatcher.listener = memoryUsageListener

And add onResume() to LandscapeImmersiveController:

fun onResume() {
    if (isLandscape && isTopBarRequestedVisible && !isUserInteractingWithTopBar) {
        scheduleTopBarAutoHide()
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`
around lines 854 - 871, onResume() in BaseEditorActivity doesn't restore the
top-bar auto-hide scheduled by onPause(); update BaseEditorActivity.onResume()
to call the immersive controller's resume logic and add a new
LandscapeImmersiveController.onResume() that re-schedules the auto-hide when
appropriate. Specifically, in BaseEditorActivity.onResume() invoke the
controller method (e.g., landscapeImmiveController.onResume()) after other
resume work, and implement LandscapeImmersiveController.onResume() to check
isLandscape, isTopBarRequestedVisible and !isUserInteractingWithTopBar and call
scheduleTopBarAutoHide() when those conditions are met.

749-760: ⚠️ Potential issue | 🟡 Minor

Drawer drag still applies top inset to editorAppBarLayout instead of editorAppbarContent.

applyStandardInsets() (lines 497-503) conditionally applies the status-bar padding to editorAppbarContent when present, but onSwipeRevealDragProgress() still animates padding on editorAppBarLayout. In landscape, both containers will contribute top inset during drawer drag, causing the toolbar to jump.

Suggested fix
 private fun onSwipeRevealDragProgress(progress: Float) {
     _binding?.apply {
         contentCard.progress = progress
         val insetsTop = systemBarInsets?.top ?: 0
-        content.editorAppBarLayout.updatePadding(
-            top = (insetsTop * (1f - progress)).roundToInt(),
-        )
+        val targetView = content.editorAppbarContent ?: content.editorAppBarLayout
+        targetView.updatePadding(
+            top = (insetsTop * (1f - progress)).roundToInt(),
+        )
         memUsageView.chart.updateLayoutParams<ViewGroup.MarginLayoutParams> {
             topMargin = (insetsTop * progress).roundToInt()
         }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`
around lines 749 - 760, onSwipeRevealDragProgress is animating top padding on
editorAppBarLayout which duplicates applyStandardInsets behavior that applies
status-bar inset to editorAppbarContent when present; change the padding update
to target editorAppbarContent when that view exists (fall back to
editorAppBarLayout only if editorAppbarContent is null) so the animated inset is
applied to the same container used by applyStandardInsets (update the
content.editorAppBarLayout.updatePadding call to conditionally update
content.editorAppbarContent.updatePadding instead), leaving the
memUsageView.chart topMargin animation unchanged.

693-696: ⚠️ Potential issue | 🟠 Major

Landscape immersive features require layout rebind after in-place rotation.

The activity handles orientation|screenSize via configChanges, so it won't recreate on rotation. The portrait layout lacks editor_appbar_content (the TouchObservingLinearLayout wrapper), meaning touch observation and scroll-based collapse won't function after rotating from portrait to landscape without rebinding.

Consider either adding editor_appbar_content to the portrait layout (even if with different scroll flags) or implementing a rebind/reinflate path in onConfigurationChanged().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`
around lines 693 - 696, The portrait->landscape rotation leaves the UI without
the TouchObservingLinearLayout wrapper ("editor_appbar_content"), so after
in-place rotation touch observation and scroll-based collapse break; update
BaseEditorActivity.onConfigurationChanged to rebind the layout components after
rotation (or alternatively add editor_appbar_content to the portrait layout).
Specifically, in onConfigurationChanged (in BaseEditorActivity) either
inflate/re-attach the layout that contains editor_appbar_content and re-run the
findViewById/initialization logic for the TouchObservingLinearLayout and AppBar
behaviors, or modify the portrait XML to include the editor_appbar_content
wrapper (TouchObservingLinearLayout) so the view hierarchy is consistent across
orientations; ensure immersiveController is reinitialized/connected to the new
view references after the rebind.
🧹 Nitpick comments (1)
app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt (1)

38-44: View binding access uses runCatching but could fail silently.

Line 39 wraps editorAppbarContent access with runCatching { ... }.getOrNull(), which swallows any exception and returns null. While this handles the portrait layout case where the view doesn't exist, it also silently ignores other potential issues. Consider using direct nullable access if available via view binding, or at minimum logging when the view is unexpectedly missing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt`
around lines 38 - 44, Replace the runCatching/getOrNull pattern around
contentBinding.editorAppbarContent in LandscapeImmersiveController with a
deterministic check and logging: attempt direct access to editorAppbarContent
(or fallback to contentBinding.root.findViewById(...) if the generated binding
property isn't nullable), assign the result to appBarContent, and if it's null
log a warning (use the class's logger or Android Log) so missing-view cases are
explicit instead of silently swallowed; remove runCatching and getOrNull and
reference the editorAppbarContent symbol in the fix so the change is easy to
find.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt`:
- Around line 854-871: onResume() in BaseEditorActivity doesn't restore the
top-bar auto-hide scheduled by onPause(); update BaseEditorActivity.onResume()
to call the immersive controller's resume logic and add a new
LandscapeImmersiveController.onResume() that re-schedules the auto-hide when
appropriate. Specifically, in BaseEditorActivity.onResume() invoke the
controller method (e.g., landscapeImmiveController.onResume()) after other
resume work, and implement LandscapeImmersiveController.onResume() to check
isLandscape, isTopBarRequestedVisible and !isUserInteractingWithTopBar and call
scheduleTopBarAutoHide() when those conditions are met.
- Around line 749-760: onSwipeRevealDragProgress is animating top padding on
editorAppBarLayout which duplicates applyStandardInsets behavior that applies
status-bar inset to editorAppbarContent when present; change the padding update
to target editorAppbarContent when that view exists (fall back to
editorAppBarLayout only if editorAppbarContent is null) so the animated inset is
applied to the same container used by applyStandardInsets (update the
content.editorAppBarLayout.updatePadding call to conditionally update
content.editorAppbarContent.updatePadding instead), leaving the
memUsageView.chart topMargin animation unchanged.
- Around line 693-696: The portrait->landscape rotation leaves the UI without
the TouchObservingLinearLayout wrapper ("editor_appbar_content"), so after
in-place rotation touch observation and scroll-based collapse break; update
BaseEditorActivity.onConfigurationChanged to rebind the layout components after
rotation (or alternatively add editor_appbar_content to the portrait layout).
Specifically, in onConfigurationChanged (in BaseEditorActivity) either
inflate/re-attach the layout that contains editor_appbar_content and re-run the
findViewById/initialization logic for the TouchObservingLinearLayout and AppBar
behaviors, or modify the portrait XML to include the editor_appbar_content
wrapper (TouchObservingLinearLayout) so the view hierarchy is consistent across
orientations; ensure immersiveController is reinitialized/connected to the new
view references after the rebind.

In `@app/src/main/res/layout-land/content_editor.xml`:
- Around line 168-188: Replace the bare 24×24dp View toggles (btn_toggle_top_bar
and btn_toggle_bottom_bar) with accessible clickable controls (e.g., ImageButton
or AppCompatImageButton), add contentDescription for TalkBack, set
clickable="true" and focusable="true" (or
android:importantForAccessibility="yes"), and ensure a minimum 48dp touch target
by increasing layout_width/layout_height to 48dp or keeping 24dp visual size but
adding 12dp padding/inset to reach 48dp; also preserve the
bg_hollow_green_circle background and gravity/margins so layout position is
unchanged.

---

Nitpick comments:
In
`@app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt`:
- Around line 38-44: Replace the runCatching/getOrNull pattern around
contentBinding.editorAppbarContent in LandscapeImmersiveController with a
deterministic check and logging: attempt direct access to editorAppbarContent
(or fallback to contentBinding.root.findViewById(...) if the generated binding
property isn't nullable), assign the result to appBarContent, and if it's null
log a warning (use the class's logger or Android Log) so missing-view cases are
explicit instead of silently swallowed; remove runCatching and getOrNull and
reference the editorAppbarContent symbol in the fix so the change is easy to
find.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ca02ac84-6dd8-4984-870b-557eca13aa21

📥 Commits

Reviewing files that changed from the base of the PR and between afdeec9 and f8d0878.

📒 Files selected for processing (6)
  • app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
  • app/src/main/java/com/itsaky/androidide/activities/editor/LandscapeImmersiveController.kt
  • app/src/main/res/drawable/bg_hollow_green_circle.xml
  • app/src/main/res/layout-land/content_editor.xml
  • app/src/main/res/layout/content_editor.xml
  • common/src/main/java/com/itsaky/androidide/ui/TouchObservingLinearLayout.kt
✅ Files skipped from review due to trivial changes (1)
  • common/src/main/java/com/itsaky/androidide/ui/TouchObservingLinearLayout.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/main/res/drawable/bg_hollow_green_circle.xml
  • app/src/main/res/layout/content_editor.xml

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.

1 participant