Skip to content

[Fix] 푸시 알림 설정 변경 사항 반영 안되는 거 수정(공통), 안드로이드 스타일 복구(폰트, 그림자) #12#13

Merged
alswlekk merged 3 commits intodevelopfrom
fix/push-sync-android-style-#12
Mar 18, 2026
Merged

[Fix] 푸시 알림 설정 변경 사항 반영 안되는 거 수정(공통), 안드로이드 스타일 복구(폰트, 그림자) #12#13
alswlekk merged 3 commits intodevelopfrom
fix/push-sync-android-style-#12

Conversation

@alswlekk
Copy link
Copy Markdown
Contributor

@alswlekk alswlekk commented Mar 12, 2026

🔗 관련 이슈

📙 작업 설명

  • 설정화면의 푸시알림 설정과 관련해서 설정을 변경했을 때 해당 설정이 제대로 반영되지 않는 문제를 해결했습니다.
  • 안드로이드앱에서 폰트, 그림자가 제대로 적용되지 않았던 문제를 해결했습니다.

📸 스크린샷 또는 시연 영상 (선택)

기능 미리보기 기능 미리보기
기능 설명 기능 설명

💬 추가 설명 or 리뷰 포인트 (선택)

Summary by CodeRabbit

  • 새로운 기능

    • 안드로이드와 iOS에서 다층 그림자(Figma 스타일) 렌더링 지원 추가
  • 개선 사항

    • 공통 테마 접근 방식 개선으로 색상·타이포그래피·그림자 전역 접근성 향상
    • 알림 설정 인터랙션 개선: 토글 변경 시 관련 상태를 일괄 계산해 적용하고 서버 동기화 수행
  • 기타

    • 플랫폼별 그림자 구현을 분리해 멀티플랫폼 호환성 강화

@alswlekk alswlekk self-assigned this Mar 12, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 12, 2026

Walkthrough

푸시 알림 토글이 변경될 때 ViewModel이 서버로 즉시 반영하도록 로직을 재구성했고, Modifier.figmaShadow를 expect/actual로 멀티플랫폼화하여 Android와 iOS에 각각 그림자 구현을 추가했습니다. 테마는 CompositionLocal로 래핑되었습니다.

Changes

Cohort / File(s) Summary
멀티플랫폼 그림자 API 변경 및 구현
composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.kt, composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt, composeApp/src/iosMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.ios.kt
Modifier.figmaShadow가 common에 expect로 선언됨. Android와 iOS에 각각 actual 구현 추가(안드로이드는 여러 Modifier.shadow 호출로 레이어별 누적 그림자 적용, iOS는 drawWithCache로 레이어 드로잉).
알림 설정 ViewModel 리팩토링
composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt
개별 토글 세터들을 제거하고 updateNotificationSettingByType(type: String, checked: Boolean) 단일 함수로 통합. 토글 변경 시 관련 PushNotification 상태를 구성해 updateUserData로 서버에 동기화하도록 변경. resetStatus() 삭제.
알림 설정 화면 UI 변경
composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/notification/screen/SettingsNotificationScreen.kt
로컬 updateSettings 헬퍼 제거. 각 스위치에서 viewModel.updateNotificationSettingByType(...)을 직접 호출하도록 변경하여 ViewModel 중심 업데이트 흐름으로 전환.
테마 CompositionLocal 적용
composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/theme/Theme.kt
MediCareCallTheme을 CompositionLocalProvider로 래핑하여 색상, 타이포그래피, 그림자 정보를 CompositionLocal로 제공하도록 변경.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI (Settings Screen)
    participant VM as SettingsEditMyDataViewModel
    participant Repo as UserRepository
    participant API as Server API

    UI->>VM: toggle notification (type, checked)
    VM->>VM: compute updated PushNotification & UI state
    VM->>Repo: updateUserData(updated UserInfo)
    Repo->>API: PATCH /user (new PushNotification)
    API-->>Repo: 200 OK
    Repo-->>VM: persist & return updated UserInfo
    VM-->>UI: update state (master/complete/abnormal/missed, isUpdateSuccess)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

그림자층이 겹쳐지고 토글이 속삭여,
ViewModel이 귀 기울여 서버에 전하네.
CompositionLocal은 테마를 포근히 안고,
Android·iOS가 각자의 빛을 드리우네. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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 PR 제목이 주요 변경 사항을 명확하게 요약하고 있습니다. 푸시 알림 설정 동기화 문제 수정과 안드로이드 스타일(폰트, 그림자) 복구라는 두 가지 핵심 변경 사항을 포함합니다.
Linked Issues check ✅ Passed PR의 코드 변경 사항이 이슈 #12의 목표를 충족합니다. 푸시 알림 설정 동기화 문제를 ViewModel에서 updateNotificationSettingByType으로 수정했고, 안드로이드 그림자 문제를 Effect.android.kt에서 해결했습니다.
Out of Scope Changes check ✅ Passed PR의 모든 변경 사항이 이슈 #12의 범위 내에 있습니다. Theme.kt의 CompositionLocalProvider 추가도 안드로이드 스타일 복구 작업의 일부로 관련성이 있습니다.

✏️ 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/push-sync-android-style-#12
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

Migrating from UI to YAML configuration.

Use the @coderabbitai configuration command in a PR comment to get a dump of all your UI settings in YAML format. You can then edit this YAML file and upload it to the root of your repository to configure CodeRabbit programmatically.

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 (4)
composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/notification/screen/SettingsNotificationScreen.kt (1)

48-50: LaunchedEffect와 myDataInfo 동기화 사이에 불필요한 리컴포지션 가능성

updateNotificationSettingByType 호출 시 updateUserData가 성공하면 myDataInfo가 업데이트됩니다. 이때 이 LaunchedEffect가 다시 트리거되어 initializeNotificationSettings를 호출하게 되는데, 결과적으로 동일한 값으로 상태를 다시 설정하게 되어 불필요한 리컴포지션이 발생할 수 있습니다.

현재 로직이 기능적으로 깨지진 않지만, 초기 로딩 시에만 초기화하도록 분리하면 더 깔끔해질 수 있습니다.

♻️ 선택적 개선안: 초기 로딩 시에만 초기화
-    LaunchedEffect(uiState.myDataInfo) {
-        uiState.myDataInfo?.let { viewModel.initializeNotificationSettings(it) }
-    }
+    // 초기 로딩 완료 후 한 번만 초기화
+    LaunchedEffect(uiState.myDataInfo?.memberId) {
+        uiState.myDataInfo?.let { viewModel.initializeNotificationSettings(it) }
+    }

또는 ViewModel 내부에서 초기화 여부를 플래그로 관리하는 방법도 있습니다.

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

In
`@composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/notification/screen/SettingsNotificationScreen.kt`
around lines 48 - 50, The LaunchedEffect tied to uiState.myDataInfo causes
redundant re-initialization when updateNotificationSettingByType ->
updateUserData updates myDataInfo; change the initialization to run only once on
first load (e.g., switch LaunchedEffect(uiState.myDataInfo) to
LaunchedEffect(Unit) or guard with a one-time flag) and ensure you still call
viewModel.initializeNotificationSettings(myDataInfo) only when myDataInfo is
non-null and not yet initialized; alternatively implement an "initialized"
boolean in the ViewModel (checked in initializeNotificationSettings) to avoid
repeated work when updateUserData updates myDataInfo.
composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt (2)

94-96: Magic string 대신 enum 또는 sealed class 사용 권장

type: String 파라미터에 "master", "complete", "abnormal", "missed" 같은 magic string을 사용하고 있습니다. 오타나 잘못된 값 전달 시 컴파일 타임에 잡지 못하고 else -> return으로 조용히 무시됩니다.

♻️ NotificationType sealed class/enum 사용 예시
enum class NotificationType {
    MASTER, COMPLETE, ABNORMAL, MISSED
}

fun updateNotificationSettingByType(
    type: NotificationType,
    checked: Boolean,
) {
    // when (type) 에서 else 분기 불필요
}

Screen에서 호출:

viewModel.updateNotificationSettingByType(
    type = NotificationType.MASTER,
    checked = isChecked,
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt`
around lines 94 - 96, updateNotificationSettingByType에서 사용하는 magic string 대신
enum 또는 sealed class를 도입해 타입 안정성을 확보하세요: 정의한 NotificationType (예: MASTER,
COMPLETE, ABNORMAL, MISSED)을 만들고
SettingsEditMyDataViewModel.updateNotificationSettingByType의 시그니처를 type:
NotificationType으로 변경한 다음 when 타입별 분기를 명시적으로 처리해 else 분기를 제거하세요; 또한 이 변경에 맞춰
화면/호출부에서 문자열 대신 NotificationType 상수로 호출하고(필요하면 직렬화/저장 시 변환 유틸을 추가) 기존 when 분기(또는
저장/로딩 로직)를 NotificationType으로 대체하여 컴파일 타임에 누락/오타를 잡도록 하세요.

98-98: myDataInfo가 null일 때 조용히 리턴하면 사용자가 이유를 알 수 없음

myDataInfo가 null이면 함수가 아무 동작 없이 리턴되어 스위치 토글이 무시됩니다. 사용자 입장에서는 스위치가 왜 동작하지 않는지 알 수 없습니다.

실제로 이 상황이 발생하기 어려울 수 있지만, 방어적으로 로그를 남기거나 에러 메시지를 설정하는 것도 고려해볼 수 있습니다.

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

In
`@composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt`
at line 98, The code silently returns when uiState.value.myDataInfo is null
(currentInfo assignment) causing toggles to be ignored; update the handler in
SettingsEditMyDataViewModel to handle the null case by logging the condition
(use your logger) and/or updating the UI state with an error/feedback flag
(e.g., set an errorMessage or showToast field on uiState) instead of an early
return so the user sees why the toggle didn't apply; keep referencing
uiState.value.myDataInfo and currentInfo to locate and modify the null-check
path.
composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt (1)

43-56: 불필요한 코드로 보입니다 - 제거를 고려해 주세요.

paint.color = 0(완전 투명)으로 설정된 상태에서 clearShadowLayer()drawRoundRect를 호출하면 화면에 아무것도 렌더링되지 않습니다. 이 코드 블록은 제거해도 동작에 영향이 없을 것으로 보입니다.

♻️ 불필요한 코드 제거 제안
         }

-        paint.clearShadowLayer()
-
-        drawIntoCanvas { canvas ->
-            val nc = canvas.nativeCanvas
-            nc.drawRoundRect(
-                0f,
-                0f,
-                size.width,
-                size.height,
-                radiusPx,
-                radiusPx,
-                paint,
-            )
-        }
-
         drawContent()
     }
 }

혹시 이 코드가 특정 목적(예: 그림자 클리핑, 배경 마스킹 등)을 위해 의도적으로 추가된 것인지 확인 부탁드립니다.

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

In
`@composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt`
around lines 43 - 56, The drawIntoCanvas block that calls
paint.clearShadowLayer() and then nc.drawRoundRect(...) with paint.color = 0 is
dead/unnecessary (it renders nothing); remove the entire drawIntoCanvas { ... }
block (the calls to paint.clearShadowLayer(), drawIntoCanvas, and
nc.drawRoundRect) unless you intentionally rely on it for a side effect like
shadow clipping—if that is the case, add a comment explaining the side effect
and keep only the minimal operations required for that behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt`:
- Around line 138-156: The code performs an optimistic UI update via
_uiState.update then calls updateUserData without rollback; capture the previous
UI state and previous currentInfo before calling _uiState.update (e.g., store
prevState and prevInfo), perform the optimistic update, then call updateUserData
and handle failure (catch exception or use onFailure callback) to restore
_uiState to prevState and, if needed, reset currentInfo to prevInfo and show an
error/toast; implement this rollback inside SettingsEditMyDataViewModel around
the _uiState.update and updateUserData calls so failures revert the
PushNotification changes and UI flags back to their previous values.

In
`@composeApp/src/iosMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.ios.kt`:
- Around line 17-24: The iOS implementation currently ignores
ShadowLayer.blurRadius (so group.layers loop only draws hard-edged rounded rects
via drawRoundRect), causing no blur; update the loop in Effect.ios.kt to apply a
shadow/blur when rendering each ShadowLayer by using the Compose Multiplatform
shadow APIs or drawIntoCanvas to configure a Paint with the layer's blurRadius,
color and offset before drawing; specifically, for each layer in group.layers
create/configure a Paint (or framework paint via paint.asFrameworkPaint()) to
set the shadow/mask filter using ShadowLayer.blurRadius and layer.color/offset,
then draw the rounded rect with that paint (replacing the plain drawRoundRect
call) so iOS renders the same blurred shadows as Android.

---

Nitpick comments:
In
`@composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt`:
- Around line 43-56: The drawIntoCanvas block that calls
paint.clearShadowLayer() and then nc.drawRoundRect(...) with paint.color = 0 is
dead/unnecessary (it renders nothing); remove the entire drawIntoCanvas { ... }
block (the calls to paint.clearShadowLayer(), drawIntoCanvas, and
nc.drawRoundRect) unless you intentionally rely on it for a side effect like
shadow clipping—if that is the case, add a comment explaining the side effect
and keep only the minimal operations required for that behavior.

In
`@composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt`:
- Around line 94-96: updateNotificationSettingByType에서 사용하는 magic string 대신 enum
또는 sealed class를 도입해 타입 안정성을 확보하세요: 정의한 NotificationType (예: MASTER, COMPLETE,
ABNORMAL, MISSED)을 만들고
SettingsEditMyDataViewModel.updateNotificationSettingByType의 시그니처를 type:
NotificationType으로 변경한 다음 when 타입별 분기를 명시적으로 처리해 else 분기를 제거하세요; 또한 이 변경에 맞춰
화면/호출부에서 문자열 대신 NotificationType 상수로 호출하고(필요하면 직렬화/저장 시 변환 유틸을 추가) 기존 when 분기(또는
저장/로딩 로직)를 NotificationType으로 대체하여 컴파일 타임에 누락/오타를 잡도록 하세요.
- Line 98: The code silently returns when uiState.value.myDataInfo is null
(currentInfo assignment) causing toggles to be ignored; update the handler in
SettingsEditMyDataViewModel to handle the null case by logging the condition
(use your logger) and/or updating the UI state with an error/feedback flag
(e.g., set an errorMessage or showToast field on uiState) instead of an early
return so the user sees why the toggle didn't apply; keep referencing
uiState.value.myDataInfo and currentInfo to locate and modify the null-check
path.

In
`@composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/notification/screen/SettingsNotificationScreen.kt`:
- Around line 48-50: The LaunchedEffect tied to uiState.myDataInfo causes
redundant re-initialization when updateNotificationSettingByType ->
updateUserData updates myDataInfo; change the initialization to run only once on
first load (e.g., switch LaunchedEffect(uiState.myDataInfo) to
LaunchedEffect(Unit) or guard with a one-time flag) and ensure you still call
viewModel.initializeNotificationSettings(myDataInfo) only when myDataInfo is
non-null and not yet initialized; alternatively implement an "initialized"
boolean in the ViewModel (checked in initializeNotificationSettings) to avoid
repeated work when updateUserData updates myDataInfo.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3dff7311-2600-43b8-82bc-28684916cc71

📥 Commits

Reviewing files that changed from the base of the PR and between de92cbb and 627d0c8.

📒 Files selected for processing (6)
  • composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt
  • composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt
  • composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/notification/screen/SettingsNotificationScreen.kt
  • composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.kt
  • composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/theme/Theme.kt
  • composeApp/src/iosMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.ios.kt

Comment on lines 138 to +156
_uiState.update {
it.copy(
missedChecked = value,
masterChecked = if (!value) false else it.masterChecked,
masterChecked = newMasterChecked,
completeChecked = newCompleteChecked,
abnormalChecked = newAbnormalChecked,
missedChecked = newMissedChecked,
)
}

val updatedUserInfo = currentInfo.copy(
pushNotification = PushNotification(
all = if (newMasterChecked) "ON" else "OFF",
carecallCompleted = if (newCompleteChecked) "ON" else "OFF",
healthAlert = if (newAbnormalChecked) "ON" else "OFF",
carecallMissed = if (newMissedChecked) "ON" else "OFF",
),
)

updateUserData(updatedUserInfo)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

낙관적 업데이트(Optimistic Update) 시 에러 발생 시 롤백 로직 부재

UI 상태를 먼저 업데이트(Line 138-145)한 후 서버 호출(Line 156)을 하는 낙관적 업데이트 패턴을 사용하고 있는데, updateUserData가 실패하면 UI는 이미 변경된 상태로 남아있고 서버와 불일치하게 됩니다.

사용자 경험을 위해 에러 발생 시 이전 상태로 롤백하거나, 실패 토스트 메시지와 함께 상태를 복원하는 로직을 추가하면 좋을 것 같습니다.

🛡️ 롤백 로직 추가 예시
+        // 롤백을 위해 이전 상태 저장
+        val previousState = _uiState.value.copy()
+
         _uiState.update {
             it.copy(
                 masterChecked = newMasterChecked,
                 completeChecked = newCompleteChecked,
                 abnormalChecked = newAbnormalChecked,
                 missedChecked = newMissedChecked,
             )
         }

         val updatedUserInfo = currentInfo.copy(
             pushNotification = PushNotification(
                 all = if (newMasterChecked) "ON" else "OFF",
                 carecallCompleted = if (newCompleteChecked) "ON" else "OFF",
                 healthAlert = if (newAbnormalChecked) "ON" else "OFF",
                 carecallMissed = if (newMissedChecked) "ON" else "OFF",
             ),
         )

-        updateUserData(updatedUserInfo)
+        updateUserData(updatedUserInfo) {
+            // onComplete - 성공 시 아무것도 안 함
+        }
+        // 또는 실패 시 롤백하는 별도 콜백 파라미터 추가 고려

updateUserDataonFailure 핸들러에서 previousState로 복원하는 방식도 고려할 수 있습니다.

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

In
`@composeApp/src/commonMain/kotlin/com/konkuk/medicarecall/ui/feature/settings/mydata/viewmodel/SettingsEditMyDataViewModel.kt`
around lines 138 - 156, The code performs an optimistic UI update via
_uiState.update then calls updateUserData without rollback; capture the previous
UI state and previous currentInfo before calling _uiState.update (e.g., store
prevState and prevInfo), perform the optimistic update, then call updateUserData
and handle failure (catch exception or use onFailure callback) to restore
_uiState to prevState and, if needed, reset currentInfo to prevInfo and show an
error/toast; implement this rollback inside SettingsEditMyDataViewModel around
the _uiState.update and updateUserData calls so failures revert the
PushNotification changes and UI flags back to their previous values.

Copy link
Copy Markdown
Contributor

@librawish808 librawish808 left a comment

Choose a reason for hiding this comment

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

LGTM

@alswlekk
Copy link
Copy Markdown
Contributor Author

@ProtossManse 리뷰 부탁드려요 ~

@ProtossManse
Copy link
Copy Markdown
Contributor

안드로이드에서도 그림자가 제대로 적용이 안된 것 같습니다!
image
image

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
`@composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt`:
- Around line 8-19: The current Modifier.figmaShadow implementation ignores each
ShadowLayer's offsetX/offsetY so shadows don't match Figma; update
Modifier.figmaShadow (the fold over group.layers) to apply layer offsets before
applying shadow (e.g., compose acc.offset(x = layer.offsetX, y = layer.offsetY)
then .shadow(...)) so the ShadowGroup layers' offsets are respected when
rendering; ensure you reference layer.offsetX and layer.offsetY from the
ShadowLayer and preserve existing cornerRadius, blurRadius, color, and clip
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c2e6606c-d365-4600-abc6-35a143de8cd0

📥 Commits

Reviewing files that changed from the base of the PR and between 627d0c8 and e18c5f3.

📒 Files selected for processing (1)
  • composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt

Comment on lines +8 to +19
actual fun Modifier.figmaShadow(
group: ShadowGroup,
cornerRadius: Dp,
): Modifier = group.layers.fold(this) { acc, layer ->
acc.shadow(
elevation = layer.blurRadius,
shape = RoundedCornerShape(cornerRadius),
ambientColor = layer.color,
spotColor = layer.color,
clip = false
)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: ShadowLayer 및 ShadowGroup 정의 확인

# ShadowLayer 클래스/데이터 클래스 정의 검색
echo "=== ShadowLayer 정의 ==="
rg -n -A 10 'data class ShadowLayer|class ShadowLayer'

echo ""
echo "=== ShadowGroup 정의 ==="
rg -n -A 10 'data class ShadowGroup|class ShadowGroup'

Repository: Medicare-Call/Medicare-Call-KMP

Length of output: 4049


offset 속성 처리 필요해요 🎨

코드 구조는 깔끔하고 fold 패턴으로 여러 shadow layer를 쌓아가는 방식도 좋습니다. 근데 예상대로 ShadowLayer에는 offsetXoffsetY 속성이 있는데, 현재 구현에서는 이게 무시되고 있어요.

Modifier.shadow()는 x/y offset을 직접 지원하지 않기 때문에, offset 값들을 반영하려면 Modifier.offset()을 조합하거나 다른 접근이 필요합니다. Figma 디자인에서 offset이 중요하다면 다음처럼 처리할 수 있어요:

actual fun Modifier.figmaShadow(
    group: ShadowGroup,
    cornerRadius: Dp,
): Modifier = group.layers.fold(this) { acc, layer ->
    acc.offset(x = layer.offsetX, y = layer.offsetY)
        .shadow(
            elevation = layer.blurRadius,
            shape = RoundedCornerShape(cornerRadius),
            ambientColor = layer.color,
            spotColor = layer.color,
            clip = false
        )
}

offset 없이도 디자인이 괜찮다면 현재대로 두셔도 괜찮지만, Figma와의 정확한 일치가 필요하다면 위처럼 처리해주세요.

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

In
`@composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt`
around lines 8 - 19, The current Modifier.figmaShadow implementation ignores
each ShadowLayer's offsetX/offsetY so shadows don't match Figma; update
Modifier.figmaShadow (the fold over group.layers) to apply layer offsets before
applying shadow (e.g., compose acc.offset(x = layer.offsetX, y = layer.offsetY)
then .shadow(...)) so the ShadowGroup layers' offsets are respected when
rendering; ensure you reference layer.offsetX and layer.offsetY from the
ShadowLayer and preserve existing cornerRadius, blurRadius, color, and clip
behavior.

@alswlekk
Copy link
Copy Markdown
Contributor Author

안드로이드에서도 그림자가 제대로 적용이 안된 것 같습니다!
image
image

Screenshot_20260318_155355.jpg

엄... 적용돼 있는 거 아닌가요 ....?

@alswlekk alswlekk merged commit 6029907 into develop Mar 18, 2026
3 checks passed
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.

[Fix] 푸시 알림 설정 변경 사항 반영 안되는 거 수정(공통), 안드로이드 스타일 복구(폰트, 그림자)

3 participants