Skip to content

bug/ADFA-4854: Filter bar invisible - #1592

Open
dara-abijo-adfa wants to merge 9 commits into
stagefrom
bug/ADFA-4854-filter-bar-invisible
Open

bug/ADFA-4854: Filter bar invisible#1592
dara-abijo-adfa wants to merge 9 commits into
stagefrom
bug/ADFA-4854-filter-bar-invisible

Conversation

@dara-abijo-adfa

Copy link
Copy Markdown
Contributor
  • Show filter bar even when filter result is empty
  • Dismiss keyboard on log filter bar and search dialog close
  • Handle state during rotation

@dara-abijo-adfa dara-abijo-adfa self-assigned this Jul 28, 2026
@dara-abijo-adfa
dara-abijo-adfa marked this pull request as ready for review July 28, 2026 18:57

@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 for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

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

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough
  • Keep the log filter bar visible when filtered results are empty, and update empty-state UI based on both source emptiness and whether a filter is active.
  • Show user-facing “no filter matches” and “no search matches” messages when applicable.
  • Dismiss the soft keyboard when hiding/closing the log filter bar and when closing the editor’s find-in-file/search dialog.
  • Preserve correct empty/filter UI state across rotation, restoration, and live log flushes by separating “UI empty” vs “source empty” state and syncing caches across detach/attach.
  • Flash “no filter matches” only on newly entered transitions into the filtered-empty state (not repeatedly while staying empty), using a dedicated no-match transition tracker.
  • Improve output editor restoration/updates to avoid lost or duplicated mutations during async replacement, timeout/deferred appends, and concurrent flushes.
  • Dynamically enable/disable output actions in the bottom sheet based on the currently displayed tab’s source emptiness (lifecycle-aware observation).
  • Add log-buffer emptiness tracking (LogBuffer.isEmpty) and expose it from LogViewModel (isBufferEmpty).
  • Add unit tests for the no-match transition tracker, the new empty-state view-model behavior, and the new emptiness helpers.
  • Risks / best-practice notes: The “no matches” flash behavior is sensitive to correct priming and render-transition detection during restore/rotation and asynchronous update ordering; regressions are most likely around restore/flush timing and lifecycle attachment/detachment of empty-state observation.

Walkthrough

The PR separates source and filtered emptiness, updates output rendering and bottom-sheet actions accordingly, adds no-match feedback for filtering and search, dismisses soft keyboards when controls close, and adds coverage for the new state transitions.

Changes

Output and search feedback

Layer / File(s) Summary
Empty-state propagation and action gating
app/src/main/java/com/itsaky/androidide/fragments/EmptyStateFragment.kt, app/src/main/java/com/itsaky/androidide/viewmodel/EmptyStateFragmentViewModel.kt, app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
Source and UI empty states are tracked separately, observed by the bottom sheet, and used to control output actions.
Filter-aware output rendering and feedback
app/src/main/java/com/itsaky/androidide/fragments/output/*, app/src/main/java/com/itsaky/androidide/logs/LogBuffer.kt, app/src/main/java/com/itsaky/androidide/viewmodel/LogViewModel.kt
Build and log output handle filtered-empty states during rendering, restoration, clearing, and live updates, with transition-based no-match feedback.
Search completion and keyboard feedback
editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt, editor/src/main/java/com/itsaky/androidide/editor/ui/EditorSearchLayout.kt, common/src/main/java/com/itsaky/androidide/utils/KeyboardUtils.kt, resources/src/main/res/values/strings.xml
Search reports completed no-match states, search/filter controls hide the soft keyboard, and new no-result messages are displayed.
State and transition validation
app/src/test/java/com/itsaky/androidide/fragments/output/FilterNoMatchTrackerTest.kt, app/src/test/java/com/itsaky/androidide/logs/LogBufferTest.kt, app/src/test/java/com/itsaky/androidide/viewmodel/*Test.kt
Tests cover no-match transitions and empty-state changes in buffers and view models.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: jatezzz, jomen-adfa, itsaky-adfa

Sequence Diagram(s)

sequenceDiagram
  participant OutputFragment
  participant EmptyStateFragment
  participant EditorBottomSheet
  OutputFragment->>EmptyStateFragment: updateEmptyState(sourceEmpty, filterActive)
  EmptyStateFragment-->>EditorBottomSheet: emit source-empty state
  EditorBottomSheet->>EditorBottomSheet: update output actions
Loading
sequenceDiagram
  participant EditorSearchLayout
  participant IDEEditorSearcher
  participant flashInfo
  EditorSearchLayout->>IDEEditorSearcher: navigate to next or previous match
  IDEEditorSearcher-->>EditorSearchLayout: return no match
  EditorSearchLayout->>IDEEditorSearcher: check completed search state
  EditorSearchLayout->>flashInfo: show no-search-matches message
Loading

Poem

I’m a bunny with logs in a row,
Filtering tells what’s empty below.
Search finds no match, then softly says,
“Nothing hopped through these paths today!”
Keyboards hide, and states stay bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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
Title check ✅ Passed The title matches the main change: keeping the filter bar visible when filters yield no results.
Description check ✅ Passed The description is related to the changeset and matches the implemented filter-bar, keyboard, and rotation-state updates.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bug/ADFA-4854-filter-bar-invisible

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: 2

Caution

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

⚠️ Outside diff range comments (2)
app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt (1)

148-155: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

clearOutput bypasses the isEmpty cache contract.

emptyStateViewModel.setEmpty(true) is called directly instead of through EmptyStateFragment.isEmpty's setter (or updateEmptyState). Only that setter also updates cachedIsEmpty; calling the ViewModel directly leaves the cache stale. If the fragment is later detached/reattached (e.g. on rotation), onViewCreated's resync logic will overwrite the correctly-cleared empty state with the stale cached value — undermining the PR's rotation-correctness goal.

🐛 Proposed fix
 	override fun clearOutput() {
 		wasLastFilteredResultEmpty = false
 		hasInitialContentRendered = false
 		viewModel.clear()
 		_binding?.editor?.setText("")?.also {
-			emptyStateViewModel.setEmpty(true)
+			isEmpty = true
 		}
 	}
🤖 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 `@app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt`
around lines 148 - 155, Update LogViewFragment.clearOutput to set the empty
state through the EmptyStateFragment.isEmpty setter or its updateEmptyState
helper, rather than calling emptyStateViewModel.setEmpty directly. Preserve the
existing clear/reset behavior while ensuring cachedIsEmpty is updated for
correct state restoration after detachment and reattachment.
app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt (1)

316-333: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Live-append paths never clear wasLastFilteredResultEmpty, so a later real "no matches" event can be silently suppressed.

Both fragments duplicate the same "last filtered result empty" flash-info tracking (in renderFiltered/setText), and both independently miss updating it from their live-append path. If a "no matches" flash already fired (wasLastFilteredResultEmpty = true), then a live line matching the current filter arrives via appendBatch, the flag should reset to false since the filtered result is no longer empty — otherwise a subsequent genuine empty-transition won't re-flash the notice.

  • app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt#L316-L333: after editor?.appendBatch(visibleText) succeeds (both the immediate and deferred paths), also set wasLastFilteredResultEmpty = false.
  • app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt#L285-L295: after editor.appendBatch(chars.toString()), also set wasLastFilteredResultEmpty = false.

Longer term, consider extracting this duplicated tracking (the two flags + flash-info gating) into a shared helper so this edge case isn't independently reintroduced.

🤖 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
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`
around lines 316 - 333, Reset wasLastFilteredResultEmpty to false whenever live
filtered output is appended. In BuildOutputFragment’s appendBatch flow, update
the flag after appendBatch succeeds in both immediate and deferred paths; in
LogViewFragment’s corresponding appendBatch(chars.toString()) path, make the
same update. Do not change the existing empty-result flash gating.
🧹 Nitpick comments (1)
editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt (1)

84-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add KDoc for the public no-match contract.

Document that true means a valid completed search has zero matches, while false also covers missing, invalid, or uninspectable result state.

Suggested KDoc
+/**
+ * Reports whether the current valid search completed with no matches.
+ *
+ * Returns false when the query/results are unavailable or cannot be inspected.
+ */
 fun isSearchCompleteWithNoMatches(): Boolean {
🤖 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 `@editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt` at
line 84, In the public isSearchCompleteWithNoMatches() method, add KDoc defining
that true indicates a valid completed search with zero matches, while false
includes missing, invalid, or uninspectable result state.

Source: Coding guidelines

🤖 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/ui/EditorBottomSheet.kt`:
- Around line 691-732: The observeCurrentFragmentEmptyState and
updateActionButtonsEnabledState flow incorrectly uses EmptyStateFragment.isEmpty
for action-button gating, because that value is overridden by filter UI state.
Expose and collect a separate source/content-empty signal from the relevant
EmptyStateFragment implementations, including LogViewFragment and
BuildOutputFragment, and pass that signal to updateActionButtonsEnabledState
while preserving isEmpty for ViewFlipper behavior.

In `@editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt`:
- Around line 84-122: Update isSearchCompleteWithNoMatches() to use a supported
search-result API instead of probing hasMatch and lastResults through
reflection; if compatibility reflection is unavoidable, isolate it and return an
explicit unknown state that EditorSearchLayout can handle rather than mapping
failures to false. Document the public method and replace broad Throwable
catches with narrowly scoped reflection/error handling that does not swallow
fatal VM errors.

---

Outside diff comments:
In
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`:
- Around line 316-333: Reset wasLastFilteredResultEmpty to false whenever live
filtered output is appended. In BuildOutputFragment’s appendBatch flow, update
the flag after appendBatch succeeds in both immediate and deferred paths; in
LogViewFragment’s corresponding appendBatch(chars.toString()) path, make the
same update. Do not change the existing empty-result flash gating.

In `@app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt`:
- Around line 148-155: Update LogViewFragment.clearOutput to set the empty state
through the EmptyStateFragment.isEmpty setter or its updateEmptyState helper,
rather than calling emptyStateViewModel.setEmpty directly. Preserve the existing
clear/reset behavior while ensuring cachedIsEmpty is updated for correct state
restoration after detachment and reattachment.

---

Nitpick comments:
In `@editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt`:
- Line 84: In the public isSearchCompleteWithNoMatches() method, add KDoc
defining that true indicates a valid completed search with zero matches, while
false includes missing, invalid, or uninspectable result state.
🪄 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 Plus

Run ID: 53ddc2a8-5752-497a-9dc0-18a05048c631

📥 Commits

Reviewing files that changed from the base of the PR and between d2bee6b and de8b6a3.

📒 Files selected for processing (10)
  • app/src/main/java/com/itsaky/androidide/fragments/EmptyStateFragment.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/LogFilterBarController.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt
  • app/src/main/java/com/itsaky/androidide/logs/LogBuffer.kt
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
  • app/src/main/java/com/itsaky/androidide/viewmodel/LogViewModel.kt
  • editor/src/main/java/com/itsaky/androidide/editor/ui/EditorSearchLayout.kt
  • editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt
  • resources/src/main/res/values/strings.xml

Comment thread app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt

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

Caution

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

⚠️ Outside diff range comments (1)
app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt (1)

176-181: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Move restored-output filtering off the main thread.

Line 179 runs filterLines on the lifecycle main dispatcher. Large build output can stall restoration; mirror renderFiltered and use Dispatchers.Default.

Proposed fix
-		val content = BuildOutputViewModel.filterLines(window, query)
+		val content =
+			withContext(Dispatchers.Default) {
+				BuildOutputViewModel.filterLines(window, query)
+			}

As per coding guidelines, "Move disk, network, database, large parsing, decoding, serialization, cryptography, and image/APK processing off the main thread."

🤖 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
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`
around lines 176 - 181, Update restoreWindowFromViewModel so the
BuildOutputViewModel.filterLines call runs inside
withContext(Dispatchers.Default), matching renderFiltered, while preserving the
existing window, query, and filtering behavior.

Source: Coding guidelines

🤖 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/fragments/output/LogFilterBarController.kt`:
- Around line 82-97: add KDoc for the public isVisible property, toggle(), and
hide() in LogFilterBarController, documenting their visibility behavior;
explicitly note that hide() dismisses the filter input IME and invokes
onVisibilityChanged.

In `@app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt`:
- Around line 148-152: Update the repeatOnLifecycle collection around the
restored snapshot handling near SetText and the noMatchTracker usage so each new
collection primes the tracker with its initial snapshot without invoking
onRender. Preserve onRender for subsequent snapshots, preventing no-match
feedback from flashing after resume or rotation.

In
`@app/src/test/java/com/itsaky/androidide/fragments/output/FilterNoMatchTrackerTest.kt`:
- Around line 20-22: Update FilterNoMatchTrackerTest.kt (20-22) to use JUnit
Jupiter’s test annotation and Truth assertions throughout the new tracker suite.
In LogBufferTest.kt (23, 98-108) and LogViewModelTest.kt (30, 184-194), replace
JUnit 4 assertion imports and new emptiness assertions with Truth APIs while
retaining JUnit Jupiter test execution. Apply only these test API migrations and
preserve existing test behavior.

---

Outside diff comments:
In
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`:
- Around line 176-181: Update restoreWindowFromViewModel so the
BuildOutputViewModel.filterLines call runs inside
withContext(Dispatchers.Default), matching renderFiltered, while preserving the
existing window, query, and filtering behavior.
🪄 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 Plus

Run ID: c5b4fcd5-6706-4b66-ba08-d31cc756df34

📥 Commits

Reviewing files that changed from the base of the PR and between de8b6a3 and 393b799.

📒 Files selected for processing (11)
  • app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/FilterNoMatchTracker.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/LogFilterBarController.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
  • app/src/test/java/com/itsaky/androidide/fragments/output/FilterNoMatchTrackerTest.kt
  • app/src/test/java/com/itsaky/androidide/logs/LogBufferTest.kt
  • app/src/test/java/com/itsaky/androidide/viewmodel/LogViewModelTest.kt
  • common/src/main/java/com/itsaky/androidide/utils/KeyboardUtils.kt
  • editor/src/main/java/com/itsaky/androidide/editor/ui/EditorSearchLayout.kt
  • editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt

@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

🤖 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/viewmodel/EmptyStateFragmentViewModel.kt`:
- Around line 49-54: Add KDoc to the public setEmptyState method describing that
isEmpty controls the displayed overall empty state, isSourceEmpty controls
whether the underlying source has no items, and divergent values are valid when
the source is empty but other content still makes the overall state non-empty.

In
`@app/src/test/java/com/itsaky/androidide/viewmodel/EmptyStateFragmentViewModelTest.kt`:
- Around line 20-53: Update EmptyStateFragmentViewModelTest to use JUnit
Jupiter’s `@Test` and Truth’s assertThat assertions instead of JUnit 4 imports and
Assert methods. Replace every assertTrue/assertFalse call in both states start
empty, setEmpty sets both states together, and setEmptyState sets the states
independently with equivalent isTrue()/isFalse() assertions.
🪄 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 Plus

Run ID: 03b4fdb0-f483-41e7-bf90-8ec12997dae7

📥 Commits

Reviewing files that changed from the base of the PR and between 393b799 and cd9d772.

📒 Files selected for processing (4)
  • app/src/main/java/com/itsaky/androidide/fragments/EmptyStateFragment.kt
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
  • app/src/main/java/com/itsaky/androidide/viewmodel/EmptyStateFragmentViewModel.kt
  • app/src/test/java/com/itsaky/androidide/viewmodel/EmptyStateFragmentViewModelTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt

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