Skip to content

Fix file list height on iOS/Android by measuring chrome dynamically#396

Merged
nitrobass24 merged 3 commits intodevelopfrom
fix/file-list-dynamic-chrome-height
Apr 22, 2026
Merged

Fix file list height on iOS/Android by measuring chrome dynamically#396
nitrobass24 merged 3 commits intodevelopfrom
fix/file-list-dynamic-chrome-height

Conversation

@nitrobass24
Copy link
Copy Markdown
Owner

@nitrobass24 nitrobass24 commented Apr 20, 2026

Summary

PR #371 fixed Android scroll, but iOS/Chrome still shows empty space below the file list. The 160px (desktop) and 200px (mobile) deductions hardcoded in the viewport calc() are larger than the actual rendered chrome on iOS, and they also don't adapt to notification banners or different #file-options wrapping at intermediate widths.

  • Add a ResizeObserver on #top-header, #file-options, and the #file-list host (the last covers the column header and bulk-action-bar that live above .file-viewport inside the host).
  • Measure .file-viewport.getBoundingClientRect().top + window.scrollY — everything stacked above the list flows into that offset — and expose it as --file-list-chrome-height.
  • Rewrite the calc to read the CSS var with a 160px fallback; drop the brittle mobile media query since measurement is now breakpoint-agnostic.
  • Runs outside the Angular zone with rAF throttling to avoid change-detection churn, and calls checkViewportSize() so CDK re-measures after the height updates.

Works the same across iOS Safari/Chrome, Android Chrome/Firefox, and desktop because it measures the actual rendered layout rather than guessing per-breakpoint.

Test plan

  • cd src/angular && npx ng lint — no new warnings in the changed files
  • cd src/angular && npx ng test — 322 tests pass (3 new)
  • Verify file list fills the screen on iOS Safari
  • Verify file list fills the screen on iOS Chrome
  • Verify file list fills the screen on Android Chrome
  • Verify file list fills the screen on Android Firefox
  • Verify desktop layout still fills the screen (no column-header gap)
  • Verify bottom item is reachable in a long list on each browser
  • Verify height recalculates when a notification banner appears

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • File list viewport now sizes dynamically using runtime measurements, improving layout accuracy across banners and mobile/desktop differences and providing a safe fallback for older browsers.
    • Ensures viewport height updates are applied and cleared when the view is torn down.
  • Tests

    • Added deterministic tests to verify viewport height updates, observer behavior, and proper cleanup on destroy.

PR #371 hardcoded 160px (desktop) and 200px (mobile) deductions for the
viewport calc(). The estimates are too large on iOS Chrome/Safari because
they count elements (e.g. a 56px navbar, 52px title bar) that don't match
the actual rendered chrome — leaving a gap of empty space below the file
list. They also ignore the notification banner (0px when empty, taller
when shown) and file-options wrapping.

Replace the guesswork with a ResizeObserver on #top-header, #file-options,
and the #file-list host. Measure the virtual viewport's page-Y offset
(= everything stacked above it) and expose it via --file-list-chrome-height
so the calc() subtracts the real value on any device or breakpoint. The
media query can now go away since measurement is intrinsically responsive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2a23e25c-24a2-4586-8899-ed1aec95fb94

📥 Commits

Reviewing files that changed from the base of the PR and between 8ec9423 and 8ce2fce.

📒 Files selected for processing (1)
  • src/angular/src/app/pages/files/file-list.component.spec.ts

📝 Walkthrough

Walkthrough

File-list viewport sizing moved from compile-time SASS vars to a runtime CSS custom property. A ResizeObserver measures header/options/host positions, schedules RAF-updated writes to --file-list-chrome-height, calls checkViewportSize(), and disconnects/cancels RAF on component destroy.

Changes

Cohort / File(s) Summary
Styles: viewport sizing
src/angular/src/app/pages/files/file-list.component.scss
Removed SASS vars $file-list-chrome-height/$file-list-chrome-height-mobile; .file-viewport now sets height: calc(100vh - var(--file-list-chrome-height, 160px)) and 100dvh fallback; comments updated to describe runtime CSS variable usage.
Component: lifecycle & observer
src/angular/src/app/pages/files/file-list.component.ts
Implements AfterViewInit & OnDestroy, adds @ViewChild for virtual viewport, injects ElementRef/NgZone; installs ResizeObserver observing #top-header, #file-options, and host; measures chrome height and writes --file-list-chrome-height via RAF; disconnects and clears RAF/CSS var on destroy.
Tests: deterministic observer & RAF
src/angular/src/app/pages/files/file-list.component.spec.ts
Adds chrome-height observer suite: fakes ResizeObserver, stubs requestAnimationFrame with flushRaf(), verifies observed elements, asserts CSS variable update to '138px', and checks observer disconnect and CSS var cleanup on fixture destroy.

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix file list height on iOS/Android by measuring chrome dynamically' clearly and concisely summarizes the main change: replacing hardcoded viewport heights with runtime measurement via ResizeObserver and CSS variables.
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.

✏️ 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 fix/file-list-dynamic-chrome-height

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
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/angular/src/app/pages/files/file-list.component.spec.ts`:
- Around line 446-453: The afterEach cleanup leaves a fake ResizeObserver
installed when the environment originally lacked it because it only restores
when originalResizeObserver is truthy; update the cleanup in the afterEach block
that references originalResizeObserver/ResizeObserver to restore when
originalResizeObserver is defined and otherwise delete the global ResizeObserver
(e.g. use delete (globalThis as any).ResizeObserver) so tests that start without
ResizeObserver do not retain the fake between tests.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0d9958ed-260c-4f4c-b633-0b8a1c8d7bdc

📥 Commits

Reviewing files that changed from the base of the PR and between 71f922b and d3ff8ff.

📒 Files selected for processing (3)
  • src/angular/src/app/pages/files/file-list.component.scss
  • src/angular/src/app/pages/files/file-list.component.spec.ts
  • src/angular/src/app/pages/files/file-list.component.ts

Comment thread src/angular/src/app/pages/files/file-list.component.spec.ts
If the test environment shipped without ResizeObserver, the previous
afterEach left the fake installed because it only restored on a truthy
original. Delete the global when the original was undefined so later tests
in the worker start clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nitrobass24
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/angular/src/app/pages/files/file-list.component.spec.ts`:
- Around line 406-456: The test redefines window.scrollY in beforeEach but never
restores it, leaking a changed global into other specs; capture the original
property descriptor (e.g., const originalScrollYDescriptor =
Object.getOwnPropertyDescriptor(window, 'scrollY') or from globalThis) when you
override scrollY in the setup and then in afterEach restore it: if
originalScrollYDescriptor is present use Object.defineProperty(window,
'scrollY', originalScrollYDescriptor) else delete (or define as undefined) the
property to return the environment to its prior state; update the
beforeEach/afterEach blocks around the ResizeObserver/requestAnimationFrame
logic and reference the scrollY override locations to ensure cleanup.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: df2e3ad4-21bd-4c4a-aa6b-51f9d21d35e6

📥 Commits

Reviewing files that changed from the base of the PR and between d3ff8ff and 8ec9423.

📒 Files selected for processing (1)
  • src/angular/src/app/pages/files/file-list.component.spec.ts

Comment thread src/angular/src/app/pages/files/file-list.component.spec.ts
…ests

Capture scrollY's original property descriptor before overriding it to 0,
then restore it (or delete, if the environment had none) in afterEach.
The override previously leaked into later specs as a static 0 value,
masking JSDOM's live getter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nitrobass24
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nitrobass24
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nitrobass24 nitrobass24 merged commit 2b9f9f9 into develop Apr 22, 2026
17 checks passed
@nitrobass24 nitrobass24 deleted the fix/file-list-dynamic-chrome-height branch April 22, 2026 00:28
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