Skip to content

Conversation

@comst19
Copy link
Collaborator

@comst19 comst19 commented Jan 7, 2026

1. ⭐️ 변경된 내용

  • 각 항목 입력 시 키패드에 안 가리도록 수정

2. 🖼️ 스크린샷(선택)

3. 💡 알게된 부분

4. 📌 이 부분은 꼭 봐주세요!

Summary by CodeRabbit

  • Improvements
    • Automatic scrolling now ensures focused input fields are brought into view when the on-screen keyboard appears.
    • Per-item focus tracking improves scroll targeting so the active field is visible with a small offset.
    • Lazy list content now accounts for keyboard inset to prevent inputs from being obscured.
    • Improved focus propagation across input components for smoother text-entry interactions.

✏️ Tip: You can customize this high-level summary in your review settings.

@comst19 comst19 requested review from kkh725 and tgyuuAn January 7, 2026 13:37
@comst19 comst19 self-assigned this Jan 7, 2026
@comst19 comst19 added 리뷰 원해요🔥 피어의 리뷰를 기다리는 ing.. 🔥 ㅁㅅ민수 labels Jan 7, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 7, 2026

📝 Walkthrough

Walkthrough

Adds a new Modifier extension animateScrollToItemOnFocus() to detect IME visibility and focus changes and auto-scroll a LazyList to a given index. ValueTalk-related screens/pages were updated to pass list state and item indices, track input focus, and adjust LazyColumn padding for IME handling.

Changes

Cohort / File(s) Summary
Core Modifier Extension
core/common-ui/src/main/java/com/puzzle/common/ui/Modifier.kt
Adds fun Modifier.animateScrollToItemOnFocus(listState: LazyListState, index: Int, scrollOffsetDp: Dp = 20.dp): Modifier using WindowInsets.ime, LocalDensity, LaunchedEffect, and onFocusChanged to detect IME & focus and perform delayed scroll to item with pixel offset.
Profile — Register Page
feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt
Replaces prior scroll-on-focus usage with focus/IME-driven scrolling; ValueTalkCard now accepts index: Int and updates focus tracking to trigger listState.animateScrollToItem(index, scrollOffset = -100) when focused and IME visible.
Profile — ValueTalk Screen
feature/profile/src/main/java/com/puzzle/profile/graph/valuetalk/ValueTalkScreen.kt
Propagates listState and index into cards, adds IME bottom padding to LazyColumn (contentPadding = PaddingValues(bottom = imeBottom)), exposes onFocusChanged for AiSummaryContent and inputs, and annotates relevant composables with @OptIn(ExperimentalLayoutApi::class).

Sequence Diagram

sequenceDiagram
    actor User
    participant Focus as Focus System
    participant Modifier as animateScrollToItemOnFocus
    participant IME as WindowInsets/IME
    participant List as LazyListState

    User->>Focus: focus on input
    Focus->>Modifier: onFocusChanged(isFocused=true)
    Modifier->>IME: check ime visible
    alt IME visible
        IME-->>Modifier: imeVisible=true
        Modifier->>Modifier: small delay
        Modifier->>List: animateScrollToItem(index, offset)
        List-->>User: item scrolled into view
    else IME hidden
        IME-->>Modifier: imeVisible=false
        Modifier-->>User: no scroll
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

머지 해도될듯염🌟, 픽스 👨‍🔧

Suggested reviewers

  • tgyuuAn

Poem

🐰 I nudge the list with whiskered care,

When fingers tap and screens declare,
The keyboard warms, the items glide—
A tiny hop, the view's supplied. 🎋

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
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.
Description check ❓ Inconclusive The description follows the template structure but lacks substantive detail in most sections; only section 1 has minimal content while sections 3 and 4 remain empty. Add details in section 3 about key learnings and in section 4 about specific areas needing review, such as scroll offset values or edge cases to test.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: enhancing scroll functionality to keep focused areas visible when the keyboard appears.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

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

🧹 Nitpick comments (2)
core/common-ui/src/main/java/com/puzzle/common/ui/Modifier.kt (1)

210-232: Consider adding index to LaunchedEffect keys.

The index parameter is not included in the LaunchedEffect keys. If the index changes while the item is focused (e.g., due to list reordering), the scroll will target the stale index captured at effect launch time.

Additionally, consider extracting the 200 delay as a named constant for clarity.

♻️ Suggested improvement
+private const val IME_ANIMATION_DELAY_MS = 200L
+
 @OptIn(ExperimentalLayoutApi::class)
 fun Modifier.animateScrollToItemOnFocus(
     listState: LazyListState,
     index: Int,
     scrollOffsetDp: Dp = 20.dp
 ): Modifier = composed {
     val density = LocalDensity.current
     val imeBottom = WindowInsets.ime.asPaddingValues().calculateBottomPadding()
     var isFocused by remember { mutableStateOf(false) }

-    LaunchedEffect(imeBottom, isFocused) {
+    LaunchedEffect(imeBottom, isFocused, index) {
         if (isFocused && imeBottom > 0.dp) {
-            delay(200)
+            delay(IME_ANIMATION_DELAY_MS)
             listState.animateScrollToItem(
                 index = index,
                 scrollOffset = with(density) { -scrollOffsetDp.roundToPx() }
             )
         }
     }

     this.onFocusChanged { isFocused = it.isFocused }
 }
feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt (1)

158-158: Remove unused variable.

The density variable is no longer used after replacing animateScrollWhenFocus with animateScrollToItemOnFocus. This is dead code that can be removed.

🧹 Suggested cleanup
-    val density = LocalDensity.current
-
     Column(modifier = modifier) {
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf43d6e and bd64948.

📒 Files selected for processing (2)
  • core/common-ui/src/main/java/com/puzzle/common/ui/Modifier.kt
  • feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt (1)

125-135: LGTM! Integration looks correct.

The idx + 1 calculation correctly accounts for the header item at LazyList index 0, ensuring the scroll targets the correct ValueTalkCard. The modifier usage and parameter passing are properly wired.

Also applies to: 183-189

Copy link
Collaborator

@kkh725 kkh725 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다

Copy link
Member

@tgyuuAn tgyuuAn left a comment

Choose a reason for hiding this comment

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

해당 Modifier가 다른 디바이스에서도 온전히 동작하나요?
체크가 필요할 것 같아요.
추가적으로 해당 Modifier가 생겨나면 기존 Modifier는 제거해도 될까요 ?

state = listState,
modifier = modifier,
contentPadding = PaddingValues(bottom = imeBottom)
contentPadding = PaddingValues(bottom = imeBottom + 40.dp)
Copy link
Member

Choose a reason for hiding this comment

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

질문 : 이거 40.dp는 뭐에요 ?!

Copy link
Collaborator Author

@comst19 comst19 Jan 8, 2026

Choose a reason for hiding this comment

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

키패드가 올라왔을 때, 마지막 입력 칸이 키보드에 너무 붙는 현상이 있어 적당하게 추가 했습니다.

수정
스크롤 로직 변경하면서 없어졌습니다.

=> 97c0c63

Comment on lines +211 to +232
@OptIn(ExperimentalLayoutApi::class)
fun Modifier.animateScrollToItemOnFocus(
listState: LazyListState,
index: Int,
scrollOffsetDp: Dp = 20.dp
): Modifier = composed {
val density = LocalDensity.current
val imeBottom = WindowInsets.ime.asPaddingValues().calculateBottomPadding()
var isFocused by remember { mutableStateOf(false) }

LaunchedEffect(imeBottom, isFocused) {
if (isFocused && imeBottom > 0.dp) {
delay(200)
listState.animateScrollToItem(
index = index,
scrollOffset = with(density) { -scrollOffsetDp.roundToPx() }
)
}
}

this.onFocusChanged { isFocused = it.isFocused }
}
Copy link
Member

Choose a reason for hiding this comment

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

이거 Composed 말고 Modfiier.Node()로 변경해주시는 게 좋을 것 같아요.
composed로 작성되면 상위 Composable에서 리컴포지션 일어나면 항상 Modifier가 재트리거 되거든요.
참고 : https://developer.android.com/develop/ui/compose/custom-modifiers?hl=ko

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

해당 로직이 태블릿일 때 제대로 작성하지 않아 수정했습니다.

=> e6870f4

추가
아래 Column에서 스크롤 로직에서 Node를 적용해보려고 했지만 IME이가 Show/Hide일 때를 캐치하는 것이 어려워 유지하기로 했습니다. => 포커스가 변경 될 때는 잘 되지만 포커스는 그대로인 상태에서 IME만 Show/Hide가 되는 상황에서 스크롤이 작동하지 않는 문제가 있었습니다.

@Composable
fun Modifier.animateScrollWhenFocus(
    scrollState: ScrollState,
    verticalWeightPx: Int = 0
): Modifier = composed {
    var scrollToPosition by remember { mutableFloatStateOf(0f) }
    val scope = rememberCoroutineScope()

    this
        .onGloballyPositioned { coordinates ->
            val itemTop = coordinates.positionInParent().y

            scrollToPosition = itemTop + verticalWeightPx
        }
        .onFocusEvent {
            if (it.isFocused) {
                scope.launch {
                    delay(300L)
                    scrollState.animateScrollTo(scrollToPosition.toInt())
                }
            }
        }
}

@comst19 comst19 marked this pull request as draft January 8, 2026 19:36
@comst19 comst19 changed the title [PC-1623] 가치관 톡 작성 시 각 항목 입력 시 키패드에 화면에 보이도록 스크롤 기능 고도화 [PC-1623] 키패드 표출 시 focuse 영역이 화면에 보이도록 스크롤 기능 고도화 Jan 9, 2026
@comst19 comst19 marked this pull request as ready for review January 9, 2026 20:18
Copy link

@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

🤖 Fix all issues with AI agents
In
@feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt:
- Line 175: The composable contains an unused coroutine scope declaration "val
scope = rememberCoroutineScope()" in ValueTalkPage; delete this unused variable
(and remove the now-unused import of rememberCoroutineScope if it becomes
unused) or, if you intended asynchronous work, replace usage by launching
coroutines with that scope (e.g., use scope.launch { ... }) so the variable is
actually used; otherwise simply remove the declaration to clean up the
composable.
🧹 Nitpick comments (2)
feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt (1)

165-173: Extract magic numbers to named constants.

The delay duration (200ms) and scroll offset (-100) are magic numbers that should be extracted to named constants for better maintainability and clarity. This would also help maintain consistency if these values need to be adjusted later.

♻️ Proposed refactor

At the top of the file, add constants:

private const val IME_SCROLL_DELAY_MS = 200L
private const val SCROLL_OFFSET_PX = -100

Then update the LaunchedEffect:

 LaunchedEffect(isImeVisible, isFocused) {
     if (isImeVisible && isFocused) {
-        delay(200)
+        delay(IME_SCROLL_DELAY_MS)
         listState.animateScrollToItem(
             index = index,
-            scrollOffset = -100
+            scrollOffset = SCROLL_OFFSET_PX
         )
     }
 }
feature/profile/src/main/java/com/puzzle/profile/graph/valuetalk/ValueTalkScreen.kt (1)

306-322: Extract magic numbers to named constants.

Similar to ValueTalkPage.kt, the delay duration (200ms) and scroll offsets (160, -100) should be extracted to named constants for better maintainability and to make the different offsets' purposes clearer.

♻️ Proposed refactor

At the top of the file, add constants:

private const val IME_SCROLL_DELAY_MS = 200L
private const val ANSWER_SCROLL_OFFSET_PX = -100
private const val AI_SUMMARY_SCROLL_OFFSET_PX = 160

Then update the LaunchedEffect:

 LaunchedEffect(isImeVisible, isAnswerFocused, isAiFocused) {
     if (!isImeVisible) return@LaunchedEffect
 
     val targetOffset = when {
-        isAiFocused -> 160
-        isAnswerFocused -> -100
+        isAiFocused -> AI_SUMMARY_SCROLL_OFFSET_PX
+        isAnswerFocused -> ANSWER_SCROLL_OFFSET_PX
         else -> null
     }
 
     targetOffset?.let { offset ->
-        delay(200)
+        delay(IME_SCROLL_DELAY_MS)
         listState.animateScrollToItem(
             index = index,
             scrollOffset = offset
         )
     }
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd64948 and 97c0c63.

📒 Files selected for processing (2)
  • feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt
  • feature/profile/src/main/java/com/puzzle/profile/graph/valuetalk/ValueTalkScreen.kt
🧰 Additional context used
🧬 Code graph analysis (1)
feature/profile/src/main/java/com/puzzle/profile/graph/valuetalk/ValueTalkScreen.kt (2)
feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt (1)
  • ValueTalkCard (153-214)
feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/ValueTalkPage.kt (1)
  • ValueTalkCard (159-216)
🔇 Additional comments (1)
feature/profile/src/main/java/com/puzzle/profile/graph/valuetalk/ValueTalkScreen.kt (1)

248-253: Verify if both IME padding approaches are needed.

The LazyColumn applies contentPadding = PaddingValues(bottom = imeBottom) at line 253, and there's also a Spacer with .imePadding() at the end (lines 280-283). This appears to apply IME-aware bottom padding twice, which might result in excessive spacing when the keyboard is visible. Consider whether both approaches are necessary or if one should be removed.

Also applies to: 278-284

}
}

val scope = rememberCoroutineScope()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused variable.

The scope variable is created but never used in this composable.

🧹 Proposed fix
-    val scope = rememberCoroutineScope()
-
     Column(modifier = modifier) {
📝 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
val scope = rememberCoroutineScope()
🤖 Prompt for AI Agents
In
@feature/profile/src/main/java/com/puzzle/profile/graph/register/page/ValueTalkPage.kt
at line 175, The composable contains an unused coroutine scope declaration "val
scope = rememberCoroutineScope()" in ValueTalkPage; delete this unused variable
(and remove the now-unused import of rememberCoroutineScope if it becomes
unused) or, if you intended asynchronous work, replace usage by launching
coroutines with that scope (e.g., use scope.launch { ... }) so the variable is
actually used; otherwise simply remove the declaration to clean up the
composable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ㅁㅅ민수 리뷰 원해요🔥 피어의 리뷰를 기다리는 ing.. 🔥

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants