Skip to content

SCRUM-267 design: add search result screen#33

Merged
gdaegeun539 merged 11 commits into
project-lyrics:developfrom
gdaegeun539:feature/SCRUM-267-search-result-screen
Apr 21, 2026
Merged

SCRUM-267 design: add search result screen#33
gdaegeun539 merged 11 commits into
project-lyrics:developfrom
gdaegeun539:feature/SCRUM-267-search-result-screen

Conversation

@gdaegeun539
Copy link
Copy Markdown
Member

@gdaegeun539 gdaegeun539 commented Apr 13, 2026

Please check if the PR fulfills these requirements

  • The commit message follows our guidelines

What kind of change does this PR introduce?

Select your one and delete others

  • Implement design

What is the current behavior?

You can also link to an open issue here

곡을 이용한 노트 검색의 상세 화면이 구현되어 있지 않습니다.

What is the new behavior (if this is a feature change)?

곡을 이용한 노트 검색의 상세 화면을 추가합니다.
기능 연동은 로그인/회원가입 연동 이후 진행합니다.

Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)

노트 카테고리를 표현하는 Enum을 추가합니다.

ScreenShots (If needed)

노트 검색 화면이 추가된 이후 스크린샷을 촬영하겠습니다.

Other information:

#32 병합 이후 라우팅 연결을 진행하고 Draft를 해제하겠습니다.

Summary by CodeRabbit

  • New Features

    • Dedicated note search results screen with collapsible header and pinned topic filter
    • Topic filtering with localized labels (All / Interpretation / Free / Question)
    • Seamless pagination with on-scroll loading and total result count
    • Navigation flow: music item → note search results, and back navigation support
    • Song summary shown atop results
  • Documentation

    • Added interactive commit/commit-message workflow documentation and guidance on staged-only commits

@gdaegeun539 gdaegeun539 self-assigned this Apr 13, 2026
@gdaegeun539 gdaegeun539 added the design 디자인 관련 수정 label Apr 13, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 13, 2026

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 NoteTopic enum, UI and navigation for a note search results screen, a ViewModel with pagination and topic filtering, view state types, and supporting presentation utilities and commit workflow docs.

Changes

Cohort / File(s) Summary
Domain Enum
app/src/main/java/com/lyrics/feelin/core/domain/enum/NoteTopic.kt
Added NoteTopic enum with values ALL, INTERPRETATION, FREE, QUESTION.
Presentation Utilities
app/src/main/java/com/lyrics/feelin/presentation/util/NoteTopicLabelExtension.kt
Added val NoteTopic.label: String extension mapping enum values to Korean labels.
ViewModel & View State
app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultViewModel.kt, app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultViewState.kt
Added NoteSearchResultViewModel with loadInitial(), loadNextPage(), selectTopic() and pagination logic; added NoteSearchResultStatus, NoteSearchResultSongSummary, and NoteSearchResultViewState with initial() factory.
Navigation
app/src/main/java/com/lyrics/feelin/navigation/FeelinDestination.kt, app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt
Added FeelinDestination.NoteSearchResult route and wired navigation from NoteSearchScreen to NoteSearchResultScreen and back (popBackStack()).
UI Components
app/src/main/java/com/lyrics/feelin/presentation/view/note/search/NoteSearchScreen.kt, app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt
Exposed onMusicClick callback on NoteSearchScreen. Added NoteSearchResultScreen composable with collapsible header, topic filter row, scroll-driven header state, conditional states (loading/empty/error/success), and scroll-triggered pagination.
Docs / Workflows
.agent/workflows/commit.md, .opencode/command/commit.md, .opencode/command/suggest_commit.md
Tightened .agent/workflows/commit.md to require staged-only commits; added staged-only interactive commit guidance and commit-message suggestion docs in .opencode/command/*.md.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant NoteSearchScreen as "NoteSearchScreen\n(UI)"
    participant NavController as "NavController"
    participant NoteSearchResultScreen as "NoteSearchResultScreen\n(UI)"
    participant VM as "NoteSearchResultViewModel"
    participant Data as "DummyDataSource"

    User->>NoteSearchScreen: tap music item (onMusicClick)
    NoteSearchScreen->>NavController: navigate("note_search_result")
    NavController->>NoteSearchResultScreen: show screen
    NoteSearchResultScreen->>VM: init -> loadInitial()
    VM->>Data: request filtered notes (topic, page=0)
    Data-->>VM: return notes list
    VM-->>NoteSearchResultScreen: emit viewState (SUCCESS/EMPTY)
    NoteSearchResultScreen->>User: render notes
    NoteSearchResultScreen-->>VM: near-end scroll -> loadNextPage()
    VM->>Data: request next page
    Data-->>VM: return next page
    VM-->>NoteSearchResultScreen: emit updated viewState (append notes)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • hyunjung-choi

Poem

🐰 I hopped from search to result with cheer,
Topics and pages now appear,
Labels in Korean, headers that slide,
Notes march in order, page by page they glide —
A tiny rabbit clap for this new feature near!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.05% 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 clearly summarizes the main change: adding a new search result screen design, which is the primary focus of this changeset.
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 unit tests (beta)
  • Create PR with unit tests

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

🧹 Nitpick comments (2)
app/src/main/java/com/lyrics/feelin/presentation/util/NoteTopicLabelExtension.kt (1)

5-10: Move these labels to string resources.

Hardcoded Korean copy here makes localization and copy changes require code edits. A safer shape is mapping NoteTopic to @StringRes and resolving the text in the UI layer.

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

In
`@app/src/main/java/com/lyrics/feelin/presentation/util/NoteTopicLabelExtension.kt`
around lines 5 - 10, Replace the hardcoded Korean strings in the NoteTopic.label
extension with resource IDs: change the extension on NoteTopic (NoteTopic.label)
to return an `@StringRes` Int and map each enum case (NoteTopic.ALL,
INTERPRETATION, FREE, QUESTION) to R.string identifiers (e.g.,
R.string.note_topic_all, etc.), then update call sites in the UI layer to
resolve the text with context.getString(noteTopic.label) or view.getString(...);
ensure string entries are added to strings.xml for each label and adjust
imports/annotations to use androidx.annotation.StringRes where appropriate.
app/src/main/java/com/lyrics/feelin/core/domain/enum/NoteTopic.kt (1)

3-7: Keep ALL out of the domain enum.

NoteTopic lives under core.domain, but ALL is a UI filter, not an actual note category. Keeping it here makes later API or persistence mappings easy to misuse once this enum is reused outside the screen. A separate presentation-layer filter type would keep the boundary cleaner.

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

In `@app/src/main/java/com/lyrics/feelin/core/domain/enum/NoteTopic.kt` around
lines 3 - 7, Remove the UI-only value ALL from the domain enum NoteTopic and
keep NoteTopic limited to actual categories (INTERPRETATION, FREE, QUESTION);
introduce a separate presentation-layer filter type (e.g., NoteTopicFilter or
PresentationNoteTopic) in the UI/presentation module that includes ALL and any
other UI-only options, and add explicit mapping code between the new
presentation filter and the domain NoteTopic where the UI interacts with the
domain (update callers that relied on NoteTopic.ALL to use the new filter and
convert to nullable/Optional or explicit domain values before passing into
domain/persistence code).
🤖 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/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultViewModel.kt`:
- Around line 27-33: When switching to the LOADING state in
NoteSearchResultViewModel, also reset the previous total note count so
ExpandedSearchHeader doesn't show the old count for the new query; update the
_viewState.value.copy call that sets status = NoteSearchResultStatus.LOADING to
include totalNoteCount = null (or 0 if your UI expects an int) alongside notes =
emptyList(), nextCursor = null, isNextPageLoading = false, and errorMessage =
null.

In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultViewState.kt`:
- Around line 30-44: The initial() companion factory for
NoteSearchResultViewState currently hardcodes a NoteSearchResultSongSummary (시퍼런
봄 / 쏜애플); change the factory to accept the selected song (e.g., a
NoteSearchResultSongSummary? or required param) instead of embedding a concrete
song, remove the hardcoded NoteSearchResultSongSummary from
NoteSearchResultViewState.initial, and update callers (such as
NoteSearchResultViewModel construction) to pass the actual selected song into
the new factory so viewState.songSummary reflects the real selection at startup.

In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSerachResultScreen.kt`:
- Around line 130-133: The NoteSearchResultScreen currently hardcodes an inert
back action; add a parameter onBackClick: () -> Unit = {} to the
NoteSearchResultScreen signature and pass it into the app bar/back-action
composable so the screen API exposes navigation to callers (also update the
other NoteSearchResultScreen declaration/usage that mirrors this
implementation). Locate the NoteSearchResultScreen function and any duplicate
definitions/usages, add the onBackClick parameter, and forward it to the app
bar's onBackClick handler so callers can supply navigation behavior.

---

Nitpick comments:
In `@app/src/main/java/com/lyrics/feelin/core/domain/enum/NoteTopic.kt`:
- Around line 3-7: Remove the UI-only value ALL from the domain enum NoteTopic
and keep NoteTopic limited to actual categories (INTERPRETATION, FREE,
QUESTION); introduce a separate presentation-layer filter type (e.g.,
NoteTopicFilter or PresentationNoteTopic) in the UI/presentation module that
includes ALL and any other UI-only options, and add explicit mapping code
between the new presentation filter and the domain NoteTopic where the UI
interacts with the domain (update callers that relied on NoteTopic.ALL to use
the new filter and convert to nullable/Optional or explicit domain values before
passing into domain/persistence code).

In
`@app/src/main/java/com/lyrics/feelin/presentation/util/NoteTopicLabelExtension.kt`:
- Around line 5-10: Replace the hardcoded Korean strings in the NoteTopic.label
extension with resource IDs: change the extension on NoteTopic (NoteTopic.label)
to return an `@StringRes` Int and map each enum case (NoteTopic.ALL,
INTERPRETATION, FREE, QUESTION) to R.string identifiers (e.g.,
R.string.note_topic_all, etc.), then update call sites in the UI layer to
resolve the text with context.getString(noteTopic.label) or view.getString(...);
ensure string entries are added to strings.xml for each label and adjust
imports/annotations to use androidx.annotation.StringRes where appropriate.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 86c0ce97-9065-40a4-ac4f-978a4f02d145

📥 Commits

Reviewing files that changed from the base of the PR and between ef72f7c and 0745cec.

📒 Files selected for processing (5)
  • app/src/main/java/com/lyrics/feelin/core/domain/enum/NoteTopic.kt
  • app/src/main/java/com/lyrics/feelin/presentation/util/NoteTopicLabelExtension.kt
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultViewModel.kt
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultViewState.kt
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSerachResultScreen.kt

gdaegeun539 and others added 2 commits April 14, 2026 22:10
Update commit command and workflow documents to use the
repository's English-only `type: Subject` format and
staged-only flow with explicit confirmation before commit.
Reset the note count when a new search result load starts so the
header does not briefly show the previous topic's total.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
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: 4

🧹 Nitpick comments (1)
.opencode/command/suggest_commit.md (1)

1-132: Consider refactoring shared content with commit.md.

Steps 1–4 (lines 9–122) are nearly identical between suggest_commit.md and commit.md. This duplication makes maintenance harder and increases the risk of inconsistencies when rules are updated.

Consider extracting the shared workflow steps into a common reference document (e.g., .agent/rules/commit-message-generation.md) and having both command files reference it, leaving only the execution/presentation differences in each file.

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

In @.opencode/command/suggest_commit.md around lines 1 - 132, The sections in
suggest_commit.md and commit.md are duplicated; extract the shared Steps 1–4
content into a new shared reference file named commit-message-generation.md and
replace the duplicated blocks in both suggest_commit.md and commit.md with a
short include/reference line pointing to commit-message-generation.md, leaving
only the command-specific differences (presentation/execution rules) in each
original file; update any internal references in suggest_commit.md (e.g., "Step
1: Gather Context", "Step 2: Analyze Changes", "Step 3: Generate Commit
Message", "Step 4: Present Options") to use the shared document so future edits
are made in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.opencode/command/commit.md:
- Around line 98-122: In the "Suggested Commits" section update the three fenced
code blocks (Option 1 (recommended), Option 2 (minimal), Option 3 (detailed)) to
include a language specifier (e.g., text) after the opening triple-backticks so
markdownlint warnings are resolved; locate the blocks by their headings and
replace ``` with ```text for the examples under those three options.
- Around line 58-91: The commit guideline is missing the capitalization rule:
add a short bullet to the commit message rules (e.g., under "1. 커밋 메시지는 영문으로 쓴다"
or near the title rules) stating that "The first letter of the subject (after
the `type:` prefix) must be capitalized," mirroring the rule in the referenced
standard; ensure the wording is concise and consistent with existing bullets and
update any nearby examples or notes if present to reflect this capitalization
requirement.

In @.opencode/command/suggest_commit.md:
- Around line 98-122: The three fenced commit-message blocks under the headings
"Option 1 (recommended)", "Option 2 (minimal)", and "Option 3 (detailed)" are
missing language specifiers and trigger markdownlint warnings; fix by adding a
language tag (e.g., text) to each opening triple-backtick so the blocks become
```text, ensuring all three commit examples include the language specifier.
- Around line 57-92: Add the missing capitalization rule into the "Core rules"
section (near "1. 커밋 메시지는 영문으로 쓴다") by stating that the first letter of the
subject (the first character after the "type: " prefix, e.g., in "feat: Add
feature") must be capitalized; update the numbered list to include this rule and
mirror the wording from the referenced git-commit-rules.md standard so readers
know to use "feat: Add ..." not "feat: add ...".

---

Nitpick comments:
In @.opencode/command/suggest_commit.md:
- Around line 1-132: The sections in suggest_commit.md and commit.md are
duplicated; extract the shared Steps 1–4 content into a new shared reference
file named commit-message-generation.md and replace the duplicated blocks in
both suggest_commit.md and commit.md with a short include/reference line
pointing to commit-message-generation.md, leaving only the command-specific
differences (presentation/execution rules) in each original file; update any
internal references in suggest_commit.md (e.g., "Step 1: Gather Context", "Step
2: Analyze Changes", "Step 3: Generate Commit Message", "Step 4: Present
Options") to use the shared document so future edits are made in one place.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b0c9002-7e78-4970-ab2e-3fc913928d53

📥 Commits

Reviewing files that changed from the base of the PR and between 0745cec and cf2cc71.

📒 Files selected for processing (4)
  • .agent/workflows/commit.md
  • .opencode/command/commit.md
  • .opencode/command/suggest_commit.md
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultViewModel.kt
✅ Files skipped from review due to trivial changes (1)
  • .agent/workflows/commit.md

Comment thread .opencode/command/commit.md
Comment thread .opencode/command/commit.md
Comment thread .opencode/command/suggest_commit.md
Comment thread .opencode/command/suggest_commit.md
@gdaegeun539 gdaegeun539 marked this pull request as draft April 19, 2026 14:38
Register the note search result route
and connect the search and result screens through navigation
@gdaegeun539 gdaegeun539 marked this pull request as ready for review April 20, 2026 15:26
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: 2

🧹 Nitpick comments (1)
app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSerachResultScreen.kt (1)

248-253: Add a key parameter to items() for stable identity during pagination.

Without a key, adding items during pagination causes unnecessary recomposition of existing items. NoteComponentData has an id: Long field that should be used.

♻️ Suggested fix
-                    items(viewState.notes) { note ->
+                    items(
+                        items = viewState.notes,
+                        key = { it.id }
+                    ) { note ->
                         NoteComponent(
                             noteData = note,
                             modifier = Modifier.padding(horizontal = 20.dp, vertical = 8.dp),
                         )
                     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSerachResultScreen.kt`
around lines 248 - 253, The items(...) call that renders NoteComponent from
viewState.notes lacks a stable key, causing unnecessary recompositions during
pagination; update the call to supply a key that uses the note id (e.g., key = {
note.id } or key = { it.id }) so each NoteComponent is identified by its
NoteComponentData.id and preserves identity across list updates.
🤖 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/lyrics/feelin/navigation/FeelinNavHost.kt`:
- Around line 185-197: The selected song data from NoteSearchScreen (supplied
via onMusicClick as MusicComponentData.SearchNoteByMusic) is currently
discarded; modify navigation so the click handler forwards the song info to
NoteSearchResultScreen (rather than just
navController.navigate(FeelinDestination.NoteSearchResult.route)). Either: add a
song identifier to MusicComponentData.SearchNoteByMusic and pass it as a
navigation argument to FeelinDestination.NoteSearchResult.route, or serialize
the song payload (title+artist or JSON of
imageUrl/songName/artistName/noteCount) and attach it as a safe nav argument;
then update the destination composable (NoteSearchResultScreen) and its
ViewModel to read that argument (or use a shared ViewModel) and populate
songSummary. Ensure updates touch the onMusicClick call site in
NoteSearchScreen, the navController.navigate invocation for
FeelinDestination.NoteSearchResult.route, and the NoteSearchResultScreen input
handling (or its ViewModel) to consume the passed data.

In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSerachResultScreen.kt`:
- Line 1: The file name contains a typo—rename the file from
NoteSerachResultScreen.kt to NoteSearchResultScreen.kt and update the
corresponding class/compose function name (e.g., NoteSerachResultScreen ->
NoteSearchResultScreen) plus any imports/usages across the codebase to match the
corrected identifier; ensure package declaration remains the same and run a
build/IDE refactor to update all references to avoid broken imports.

---

Nitpick comments:
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSerachResultScreen.kt`:
- Around line 248-253: The items(...) call that renders NoteComponent from
viewState.notes lacks a stable key, causing unnecessary recompositions during
pagination; update the call to supply a key that uses the note id (e.g., key = {
note.id } or key = { it.id }) so each NoteComponent is identified by its
NoteComponentData.id and preserves identity across list updates.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fad99845-0517-4d00-99e8-e7ffd47fa3ad

📥 Commits

Reviewing files that changed from the base of the PR and between cf2cc71 and feca45b.

📒 Files selected for processing (4)
  • app/src/main/java/com/lyrics/feelin/navigation/FeelinDestination.kt
  • app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/NoteSearchScreen.kt
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSerachResultScreen.kt

Comment thread app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt
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

🧹 Nitpick comments (1)
app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt (1)

157-166: Pagination guards are already in place; consider defensive guards on Composable side as optional improvement.

The loadNextPage() function in NoteSearchResultViewModel already has protection against duplicate calls: the isNextPageLoading check at line 66 causes an early return if a load is already in progress. This guard prevents the concern about repeated pagination triggers.

That said, the suggestion to add defensive checks in the Composable side (distinctUntilChanged() on the flow, isNextPageLoading state check before calling loadNextPage()) is still valid as a belt-and-suspenders approach and can improve clarity of intent. However, this is an optional improvement rather than a required fix, as the critical deduplication is already handled by the ViewModel.

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

In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt`
around lines 157 - 166, The composable's pagination trigger can fire repeatedly
even though NoteSearchResultViewModel.loadNextPage already guards via
isNextPageLoading; add an extra defensive layer in the LaunchedEffect
snapshotFlow used with listState by applying distinctUntilChanged() so identical
(lastVisible, total) pairs don't re-emit, and check the ViewModel's
isNextPageLoading (or expose an isLoading state) before calling
viewModel.loadNextPage() to avoid redundant calls; update the LaunchedEffect
tied to listState/PAGINATION_PREFETCH_THRESHOLD to perform these checks and only
call loadNextPage when distinct and not already loading.
🤖 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/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt`:
- Around line 78-79: The header expand/collapse threshold uses raw pixels
(HEADER_EXPAND_OFFSET_THRESHOLD = 50) but is compared against
firstVisibleItemScrollOffset (pixel-based); change
HEADER_EXPAND_OFFSET_THRESHOLD to a Dp value (e.g., 50.dp) and, inside
rememberHeaderState(), convert that Dp to pixels using LocalDensity.current
(density.dipToPx or density.run { HEADER_EXPAND_OFFSET_THRESHOLD.toPx() })
before comparing to firstVisibleItemScrollOffset so the breakpoint is
density-independent; update references in rememberHeaderState() and any
comparisons that use HEADER_EXPAND_OFFSET_THRESHOLD, leaving
COLLAPSED_TOP_BAR_HEIGHT as-is.

---

Nitpick comments:
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt`:
- Around line 157-166: The composable's pagination trigger can fire repeatedly
even though NoteSearchResultViewModel.loadNextPage already guards via
isNextPageLoading; add an extra defensive layer in the LaunchedEffect
snapshotFlow used with listState by applying distinctUntilChanged() so identical
(lastVisible, total) pairs don't re-emit, and check the ViewModel's
isNextPageLoading (or expose an isLoading state) before calling
viewModel.loadNextPage() to avoid redundant calls; update the LaunchedEffect
tied to listState/PAGINATION_PREFETCH_THRESHOLD to perform these checks and only
call loadNextPage when distinct and not already loading.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 28b0cc18-7fc6-450d-b47f-39457ce4cd1b

📥 Commits

Reviewing files that changed from the base of the PR and between feca45b and 58efa29.

📒 Files selected for processing (1)
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt

@gdaegeun539
Copy link
Copy Markdown
Member Author

@codex

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58efa292a9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/src/main/java/com/lyrics/feelin/navigation/FeelinNavHost.kt
Rename the header expansion threshold to reflect its behavior and compare it as a density-aware pixel value instead of a raw number.
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: 2

🧹 Nitpick comments (1)
app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt (1)

137-137: Preview currently depends on runtime ViewModel resolution.

NoteSearchResultScreenPreview() (Line 448-451) calls NoteSearchResultScreen() which resolves viewModel() at Line 137. If NoteSearchResultViewModel is injected (e.g., Hilt constructor deps), Preview can fail or be non-deterministic. Consider a pure UI-content composable for preview with static state.

#!/bin/bash
set -euo pipefail

vm_file="$(fd 'NoteSearchResultViewModel.kt' app/src/main/java | head -n1)"
echo "ViewModel file: ${vm_file:-NOT_FOUND}"

if [[ -n "${vm_file:-}" ]]; then
  echo "---- ViewModel declaration context ----"
  cat -n "$vm_file" | sed -n '1,220p'
  echo "---- Hilt/injection markers ----"
  rg -n '@HiltViewModel|class\s+NoteSearchResultViewModel|constructor\(' "$vm_file"
fi

echo "---- NoteSearchResultScreen call sites ----"
rg -n 'NoteSearchResultScreen\s*\(' app/src/main/java -C2

echo "---- Existing screen-entry patterns (hiltViewModel) ----"
rg -n --type=kt 'hiltViewModel\s*\(' app/src/main/java/com/lyrics/feelin/presentation/view -C2

Also applies to: 448-451

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

In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt`
at line 137, NoteSearchResultScreen currently calls viewModel() at runtime which
breaks deterministic previews; instead extract the UI into a pure composable
(e.g., NoteSearchResultContent(state: NoteSearchState, onEvent:
(NoteSearchEvent)->Unit)) and make NoteSearchResultScreen a thin wrapper that
obtains a NoteSearchResultViewModel and passes its state/events into
NoteSearchResultContent; update NoteSearchResultScreen signature to accept an
optional viewModel parameter or only call viewModel from the wrapper, then
change NoteSearchResultScreenPreview to call NoteSearchResultContent with a
static NoteSearchState and noop handlers so preview no longer depends on runtime
ViewModel resolution.
🤖 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/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt`:
- Around line 134-138: Reorder the composable parameter lists so any lambda
parameters come last: for NoteSearchResultScreen change the signature so
onBackClick (the lambda) is the final parameter (e.g., fun
NoteSearchResultScreen(modifier: Modifier = Modifier, viewModel:
NoteSearchResultViewModel = viewModel(), onBackClick: () -> Unit = {}) ), and
apply the same reordering to the other composable signature mentioned (the one
with a trailing lambda currently after modifier/viewModel) so all lambda params
are placed last.
- Around line 161-170: The prefetch inside LaunchedEffect/snapshotFlow can fire
repeatedly while a page is already loading; guard the call to
viewModel.loadNextPage() with an in-flight/status check (e.g., expose and read a
ViewModel property such as isLoading or hasNextPage from the UI state) so you
only call loadNextPage() when not currently loading and when more pages exist;
update the snapshotFlow collector to check viewModel.isLoading (or
viewModel.uiState.isLoading / viewModel.uiState.hasMore) along with the existing
PAGINATION_PREFETCH_THRESHOLD condition before invoking
viewModel.loadNextPage().

---

Nitpick comments:
In
`@app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt`:
- Line 137: NoteSearchResultScreen currently calls viewModel() at runtime which
breaks deterministic previews; instead extract the UI into a pure composable
(e.g., NoteSearchResultContent(state: NoteSearchState, onEvent:
(NoteSearchEvent)->Unit)) and make NoteSearchResultScreen a thin wrapper that
obtains a NoteSearchResultViewModel and passes its state/events into
NoteSearchResultContent; update NoteSearchResultScreen signature to accept an
optional viewModel parameter or only call viewModel from the wrapper, then
change NoteSearchResultScreenPreview to call NoteSearchResultContent with a
static NoteSearchState and noop handlers so preview no longer depends on runtime
ViewModel resolution.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e5b5685e-f9e6-49eb-bb11-bea46e3c6c88

📥 Commits

Reviewing files that changed from the base of the PR and between 58efa29 and 50bc6e6.

📒 Files selected for processing (1)
  • app/src/main/java/com/lyrics/feelin/presentation/view/note/search/result/NoteSearchResultScreen.kt

@gdaegeun539
Copy link
Copy Markdown
Member Author

gdaegeun539 commented Apr 21, 2026

CodeRabbit Potential issue 모두 수정 완료했으므로 병합하겠습니다.

@gdaegeun539 gdaegeun539 merged commit dbf896a into project-lyrics:develop Apr 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

design 디자인 관련 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant