Skip to content

[Refactor/#219] 상단바 아이콘 색상 변경 로직 수정#220

Open
l5x5l wants to merge 3 commits intodevelopfrom
refactor/#219-status_bar_icon_color
Open

[Refactor/#219] 상단바 아이콘 색상 변경 로직 수정#220
l5x5l wants to merge 3 commits intodevelopfrom
refactor/#219-status_bar_icon_color

Conversation

@l5x5l
Copy link
Copy Markdown
Contributor

@l5x5l l5x5l commented Apr 27, 2026

[ PR Content ]

홈 화면 탭에 한해서만 적용되었던 상단바 아이콘 색상 변경 로직을 모든 화면에 적용될 수 있도록 수정했습니다.

Related issue

Screenshot 📸

기존 동작

before.mp4

수정 후 동작

after.mp4

Work Description

  • 상단 StatusBar 영역의 Pixel값들을 토대로 휘도를 구해 상단 StatusBar 아이콘 색상을 변경하는 로직을 구현했습니다
  • 위 로직을 NavBackStackEntry가 변경될 때마다 해당 NavBackStackEntry의 생명주기 중 Resume에서 호출합니다.

To Reviewers 📢

  • 드로이드 나이츠에서 본 기억이 있어 해당 로직을 가져와 사용했습니다!
  • 이전에는 직접 화면에 따라 화면 전환시 바로 아이콘 색상을 변경했기에 아이콘 색상이 변경되는 속도가 빨랐지만, 현재는 NavBackStackEntry의 Resume에서 아이콘 색상이 변경되기에 살짝 반응 속도가 느립니다. 하지만 전체 화면에 적용되는게 더 중요하다고 판단되어 작업을 진행했습니다!
  • 궁금한 점 혹은 개선점 있으시면 코멘트 부탁드려요!

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 앱 내 네비게이션에 따라 상태 바 아이콘이 자동으로 조정되어 배경에 대한 가독성이 개선되었습니다.
  • 개선 사항

    • 상태 바 색상 관리 로직이 중앙화되어 더욱 일관된 사용자 경험을 제공합니다.

@l5x5l l5x5l self-assigned this Apr 27, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Warning

Rate limit exceeded

@l5x5l has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 41 minutes and 49 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1c10332-0cf9-4d04-90f3-5b3434b9030b

📥 Commits

Reviewing files that changed from the base of the PR and between b924953 and b45a2cc.

📒 Files selected for processing (2)
  • presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/NavStatusBarEffect.kt
  • presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt

개요

상단바 아이콘 색상 관리 로직을 홈 화면 한정에서 모든 화면으로 확장하기 위해 중앙집중식 NavStatusBarEffect 컴포저블을 도입하고, 기존의 홈 네비게이션별 상태바 관리 코드를 제거했습니다.

변경사항

Cohort / File(s) Summary
상태바 효과 중앙화
app/src/main/java/com/threegap/bitnagil/MainNavHost.kt
NavStatusBarEffect 컴포저블을 추가하여 모든 네비게이션 목적지에 대한 상태바 관리를 구현합니다.
홈 네비게이션 정리
app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavHost.kt
로컬 isHomeRoute 기반 상태바 색상 관리 및 LaunchedEffect를 제거하고 중앙집중식 NavStatusBarEffect로 대체합니다.
홈 네비게이터 속성 제거
app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavigator.kt
isHomeRoute 컴포저블 속성을 제거합니다.
상태바 관리 유틸리티
presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/NavStatusBarEffect.kt, presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt
네비게이션 기반 상태바 효과 및 광도 계산을 통한 상태바 아이콘 색상 관리 유틸리티를 새로 추가합니다.

시퀀스 다이어그램

sequenceDiagram
    participant NavController
    participant NavStatusBarEffect
    participant LifecycleOwner
    participant StatusBarAppearanceManager
    participant Window

    NavController->>NavStatusBarEffect: 현재 NavBackStackEntry 제공
    NavStatusBarEffect->>LifecycleOwner: repeatOnLifecycle(RESUMED) 설정
    LifecycleOwner->>NavStatusBarEffect: RESUMED 상태 진입
    NavStatusBarEffect->>Window: Activity의 window 접근
    NavStatusBarEffect->>StatusBarAppearanceManager: applyStatusBarColorByLuminance(window) 호출
    StatusBarAppearanceManager->>Window: 상태바 영역 비트맵 캡처 (PixelCopy)
    StatusBarAppearanceManager->>StatusBarAppearanceManager: 중앙 픽셀 광도 계산
    StatusBarAppearanceManager->>Window: WindowInsetsControllerCompat를 통해 아이콘 색상 업데이트
Loading

코드 리뷰 예상 난이도

🎯 3 (Moderate) | ⏱️ ~22 분

래빗의 축하 시

🐰 여러 화면마다 달라지는 상단바 색상,
이제 중앙에서 한 번에 관리해요!
픽셀마다 밝기를 재어 아이콘 색을 정하니,
모든 화면이 조화롭게 빛나요~ ✨
리팩터링 덕분에 코드도 깔끔해졌네요!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 주요 변경사항(상단바 아이콘 색상 변경 로직 수정)을 명확하게 반영하고 있으며, 이슈 번호도 포함되어 있습니다.
Description check ✅ Passed PR 설명은 관련 이슈, 스크린샷, 작업 설명, 리뷰어 참고사항을 포함하여 템플릿을 충실히 따르고 있습니다.
Linked Issues check ✅ Passed 코드 변경사항이 #219 이슈의 요구사항을 완벽하게 충족합니다: 상단바 아이콘 색상 변경 로직을 홈 화면 탭 외 모든 화면에 적용.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #219 이슈의 범위 내에 있습니다. 상단바 색상 관리 로직 중앙화 및 적용 범위 확대만 수행되었습니다.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#219-status_bar_icon_color

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt (2)

16-17: 상태가 없는 유틸리티이므로 object로 선언 권장.

이 클래스는 인스턴스 상태를 보관하지 않고 모든 메서드가 순수 함수처럼 동작합니다. class 대신 object 또는 최상위 함수로 노출하면 호출부의 인스턴스 생성을 줄이고 의도를 더 명확히 표현할 수 있습니다.

-class StatusBarAppearanceManager {
+object StatusBarAppearanceManager {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt`
around lines 16 - 17, StatusBarAppearanceManager is a stateless utility class;
change its declaration from a class to an object (or convert
applyStatusBarColorByLuminance into a top-level function) so callers don't need
to instantiate it; update any call sites that do StatusBarAppearanceManager() to
reference the singleton
(StatusBarAppearanceManager.applyStatusBarColorByLuminance) or the new top-level
function name, and ensure visibility (public) and imports are adjusted
accordingly.

48-53: 중심 픽셀 1개만으로 휘도를 계산하는 정확도 한계.

calculateLuminance가 비트맵 정중앙의 단일 픽셀만 샘플링합니다. 상단바 영역에 그라디언트, 좌측 상태 아이콘 영역과 우측 노치/캐리어 영역이 다른 색상을 가질 경우 중앙 픽셀이 전체 영역을 대표하지 못해 아이콘 가독성이 저하될 수 있습니다. 또한 150이라는 임계값이 0.299·R + 0.587·G + 0.114·B 기준이라면 실제 BT.601의 일반 임계값과 비교해 명시적인 근거가 부족합니다.

여러 지점(예: 좌/중/우)의 평균 또는 최소 휘도를 사용하는 것을 권장합니다.

♻️ 제안 예시
-    private fun calculateLuminance(bitmap: Bitmap): Int {
-        val x = bitmap.width / 2
-        val y = bitmap.height / 2
-        val px = bitmap[x, y]
-        return (0.299 * Color.red(px) + 0.587 * Color.green(px) + 0.114 * Color.blue(px)).toInt()
-    }
+    private fun calculateLuminance(bitmap: Bitmap): Int {
+        val y = bitmap.height / 2
+        val xs = intArrayOf(bitmap.width / 4, bitmap.width / 2, bitmap.width * 3 / 4)
+        val avg = xs.map { x ->
+            val px = bitmap[x, y]
+            0.299 * Color.red(px) + 0.587 * Color.green(px) + 0.114 * Color.blue(px)
+        }.average()
+        return avg.toInt()
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt`
around lines 48 - 53, calculateLuminance currently samples only the single
center pixel (bitmap[x, y]) which is unreliable for varied status bar regions;
update calculateLuminance to sample multiple points (e.g., left/center/right or
a small grid across the status bar area) and compute either the average or the
minimum luminance using the same BT.601 formula (0.299*R + 0.587*G + 0.114*B) to
better represent overall brightness, replace the single-pixel read with that
multisample result, and extract the hard-coded threshold (150) into a named
constant (e.g., STATUS_BAR_LUMINANCE_THRESHOLD) with a comment referencing the
BT.601 basis so it’s easy to tune or document.
presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/NavStatusBarEffect.kt (1)

19-21: StatusBarAppearanceManager 인스턴스화 비용.

StatusBarAppearanceManager는 상태가 없는 유틸리티 클래스입니다. navigation 변경마다 새 인스턴스를 생성하기보다 object 선언으로 변경하거나, 호출부에서 한 번만 만들어 재사용하는 편이 적절합니다.

♻️ 제안

StatusBarAppearanceManagerobject로 선언하면 호출부도 다음과 같이 단순해집니다.

-                StatusBarAppearanceManager().applyStatusBarColorByLuminance(window)
+                StatusBarAppearanceManager.applyStatusBarColorByLuminance(window)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/NavStatusBarEffect.kt`
around lines 19 - 21, StatusBarAppearanceManager is a stateless utility so avoid
re-instantiating it on every navigation change; either convert the class to a
Kotlin object (StatusBarAppearanceManager) so you can call
StatusBarAppearanceManager.applyStatusBarColorByLuminance(window) directly, or
create a single reusable instance (e.g., a private val
statusBarAppearanceManager = StatusBarAppearanceManager()) in NavStatusBarEffect
and call statusBarAppearanceManager.applyStatusBarColorByLuminance(window)
instead of instantiating it each time; update references to
applyStatusBarColorByLuminance accordingly.
app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavHost.kt (1)

55-55: 홈 탭 간 전환 시 effect 위치 정리 필요.

내부 navigator.navControllerNavStatusBarEffect를 호출하는 의도는 홈 하위 탭(Home/RecommendRoutine/MyPage) 전환에 따라 상단바 색상을 갱신하기 위한 것으로 보입니다. 다만 MainNavHost.kt Line 37의 외부 NavStatusBarEffect와 함께 동작하므로 Route.Home으로 진입할 때 두 effect가 동시에 발화합니다. 의도한 동작이라면 상관없지만, 외부 effect만으로는 홈 내부 탭 전환을 감지하지 못하므로 두 effect 모두 유지하는 것이 정상이라는 점을 코드 주석으로 남겨두면 추후 유지보수에 도움이 될 것 같습니다.

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

In `@app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavHost.kt` at
line 55, The NavStatusBarEffect call using navigator.navController in
HomeNavHost is causing duplicate effects together with the outer
NavStatusBarEffect in MainNavHost when entering Route.Home; add a concise code
comment immediately above the NavStatusBarEffect(navController =
navigator.navController) line explaining that this inner effect is intentionally
present to react to home sub-tab (Home/RecommendRoutine/MyPage) navigation
(which the outer effect alone cannot observe), and note that both effects will
fire on Route.Home entry but must be kept to handle internal tab changes;
reference NavStatusBarEffect, navigator.navController, MainNavHost, and
Route.Home in the comment for future maintainers.
🤖 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/threegap/bitnagil/MainNavHost.kt`:
- Line 37: MainNavHost와 HomeNavHost에서 동일한 NavStatusBarEffect를 두 번 호출해 PixelCopy
캡처가 중복 실행되는 문제입니다; 해결하려면 중복 호출을 제거하거나 조건부로 실행되게 변경하세요: 보통은 MainNavHost의
NavStatusBarEffect(navController = navigator.navController)를 유지하고 HomeNavHost 쪽의
NavStatusBarEffect 호출을 삭제하거나, HomeNavHost에서
rememberHomeNavigator().navController가 부모의 navController와 동일하거나 현재 목적지가
Route.Home이 아닐 때만 효과를 실행하도록 가드(예: currentBackStackEntry 비교 또는 navController 참조
비교)하세요 so only one PixelCopy capture runs per navigation change.

In
`@presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt`:
- Around line 21-29: The bitmap created in captureStatusBarBitmap is not being
recycled after use, causing memory pressure; update the lambda passed to
captureStatusBarBitmap (the callback that receives bmp) to ensure the Bitmap is
recycled after luminance is computed — e.g., wrap use of bmp in a try/finally
(or call bmp.recycle() at the end of the callback) so calculateLuminance(it) and
WindowInsetsControllerCompat(window,
window.decorView).isAppearanceLightStatusBars = (lum > 150) run before
bmp.recycle(), and avoid accessing the bitmap after recycling.
- Around line 38-46: In captureStatusBarBitmap, guard against callbacks running
after the Activity/Window is gone and handle PixelCopy result codes: before
calling PixelCopy.request ensure window is still valid (check
window.decorView.isAttachedToWindow and, if available, the Activity's
isFinishing/isDestroyed), and in the PixelCopy.request callback check the
copyResult == PixelCopy.SUCCESS; if success call onResult(bmp), otherwise
recycle the bmp (or let it be GC'd by explicitly bmp.recycle()) and call
onResult(null). Also avoid invoking WindowInsetsControllerCompat or other window
APIs unless the window/decorView is still attached.

---

Nitpick comments:
In `@app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavHost.kt`:
- Line 55: The NavStatusBarEffect call using navigator.navController in
HomeNavHost is causing duplicate effects together with the outer
NavStatusBarEffect in MainNavHost when entering Route.Home; add a concise code
comment immediately above the NavStatusBarEffect(navController =
navigator.navController) line explaining that this inner effect is intentionally
present to react to home sub-tab (Home/RecommendRoutine/MyPage) navigation
(which the outer effect alone cannot observe), and note that both effects will
fire on Route.Home entry but must be kept to handle internal tab changes;
reference NavStatusBarEffect, navigator.navController, MainNavHost, and
Route.Home in the comment for future maintainers.

In
`@presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/NavStatusBarEffect.kt`:
- Around line 19-21: StatusBarAppearanceManager is a stateless utility so avoid
re-instantiating it on every navigation change; either convert the class to a
Kotlin object (StatusBarAppearanceManager) so you can call
StatusBarAppearanceManager.applyStatusBarColorByLuminance(window) directly, or
create a single reusable instance (e.g., a private val
statusBarAppearanceManager = StatusBarAppearanceManager()) in NavStatusBarEffect
and call statusBarAppearanceManager.applyStatusBarColorByLuminance(window)
instead of instantiating it each time; update references to
applyStatusBarColorByLuminance accordingly.

In
`@presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt`:
- Around line 16-17: StatusBarAppearanceManager is a stateless utility class;
change its declaration from a class to an object (or convert
applyStatusBarColorByLuminance into a top-level function) so callers don't need
to instantiate it; update any call sites that do StatusBarAppearanceManager() to
reference the singleton
(StatusBarAppearanceManager.applyStatusBarColorByLuminance) or the new top-level
function name, and ensure visibility (public) and imports are adjusted
accordingly.
- Around line 48-53: calculateLuminance currently samples only the single center
pixel (bitmap[x, y]) which is unreliable for varied status bar regions; update
calculateLuminance to sample multiple points (e.g., left/center/right or a small
grid across the status bar area) and compute either the average or the minimum
luminance using the same BT.601 formula (0.299*R + 0.587*G + 0.114*B) to better
represent overall brightness, replace the single-pixel read with that
multisample result, and extract the hard-coded threshold (150) into a named
constant (e.g., STATUS_BAR_LUMINANCE_THRESHOLD) with a comment referencing the
BT.601 basis so it’s easy to tune or document.
🪄 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

Run ID: 4e8efa56-9a11-46ff-aea1-8a0b6425e945

📥 Commits

Reviewing files that changed from the base of the PR and between 53de51b and b924953.

📒 Files selected for processing (5)
  • app/src/main/java/com/threegap/bitnagil/MainNavHost.kt
  • app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavHost.kt
  • app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavigator.kt
  • presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/NavStatusBarEffect.kt
  • presentation/src/main/java/com/threegap/bitnagil/presentation/util/statusbar/StatusBarAppearanceManager.kt
💤 Files with no reviewable changes (1)
  • app/src/main/java/com/threegap/bitnagil/navigation/home/HomeNavigator.kt

Comment thread app/src/main/java/com/threegap/bitnagil/MainNavHost.kt
@l5x5l l5x5l requested a review from wjdrjs00 April 27, 2026 11:12
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.

[REFACTOR] 상단바 아이콘 색상이 홈 화면 탭 외 모든 화면에 따라 변경되도록 수정합니다.

1 participant