Skip to content

[Feat] 순공시간 타이머 동작 시 사용성 개선#62

Merged
ff1451 merged 10 commits into
mainfrom
61-feat-순공시간-타이머-동작-시-사용성-개선
Apr 11, 2026

Hidden character warning

The head ref may contain hidden characters: "61-feat-\uc21c\uacf5\uc2dc\uac04-\ud0c0\uc774\uba38-\ub3d9\uc791-\uc2dc-\uc0ac\uc6a9\uc131-\uac1c\uc120"
Merged

[Feat] 순공시간 타이머 동작 시 사용성 개선#62
ff1451 merged 10 commits into
mainfrom
61-feat-순공시간-타이머-동작-시-사용성-개선

Conversation

@ff1451
Copy link
Copy Markdown
Contributor

@ff1451 ff1451 commented Apr 11, 2026

배경

  • 순공시간 타이머가 동작 중일 때 화면이 쉽게 꺼지거나 뒤로가기 제스처로 흐름이 끊길 수 있었습니다.
  • 타이머 집중 상태를 네이티브 레이어에서도 인지해 화면 밝기와 keep-awake를 제어할 필요가 있었습니다.

변경 사항

  • expo-brightness, expo-keep-awake를 추가하고 관련 Expo 패키지 버전을 정리했습니다.
  • WebView 브리지 메시지에 TIMER_ACTIVE, TIMER_INACTIVE, NAVIGATE_BACK 처리를 추가했습니다.
  • 타이머 활성화 시 밝기 조절 및 keep-awake를 적용하고, 비활성화/앱 백그라운드 전환 시 원복하도록 구현했습니다.
  • 타이머 활성화 중에는 iOS 뒤로가기 제스처를 비활성화하고, Android 하드웨어 뒤로가기 입력은 웹 쪽 확인 이벤트를 먼저 보내도록 변경했습니다.

검증

  • pnpm lint
  • pnpm test -- --watchAll=false (No tests found, exiting with code 0)

이슈

close #61

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 타이머 활성 시 화면 유지(keep-awake) 및 선택적 화면 밝기 조절 기능 추가
    • 타이머 상태에 따른 WebView 내 이동/뒤로가기 동작 제어 및 iOS 제스처 제한
  • 버그 수정 / 개선

    • Android 하드웨어 뒤로가기 동작 개선(타이머 활성 시 적절한 동작 보장)
    • 앱 라이프사이클에 따른 타이머 화면 모드 자동 비활성화/재활성화
    • WebView 네비게이션 추적 안정성 향상(현재 출처 동기화)
  • 기타

    • 앱 버전·빌드 번호 업데이트 및 Expo 모듈 패치 업데이트, 밝기/keep-awake 모듈 추가

@ff1451 ff1451 linked an issue Apr 11, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 11, 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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b4457442-81a7-4207-ad36-01c2c8efa281

📥 Commits

Reviewing files that changed from the base of the PR and between a04e061 and 4c68ad8.

📒 Files selected for processing (1)
  • services/timerDisplayMode.ts

📝 Walkthrough

Walkthrough

네이티브 브리지로 WebView의 타이머 활성/비활성 메시지를 처리하고, 화면 밝기(dim) 조절·화면 꺼짐 방지(keep-awake)를 담당하는 timer display mode 서비스와 연동하도록 WebView 라우트·라이프사이클·하드웨어 백 처리 및 Expo 의존성·앱 버전 식별자를 업데이트했습니다.

Changes

Cohort / File(s) Summary
타이머 디스플레이 모드 서비스
services/timerDisplayMode.ts
새 파일 추가: keep-awake 활성/비활성, 플랫폼별 밝기(dim) 적용·복원, 지연 dim 스케줄링, 직렬화된 실행 큐, 공개 API enableTimerDisplayMode / disableTimerDisplayMode 및 옵션 타입 추가.
WebView 라우트 및 네이티브 브리지
app/webview/[path].tsx
네이티브 메시지 파싱 확장(TIMER_ACTIVE, TIMER_INACTIVE, NAVIGATE_BACK), origin 검증 추가, timerDisplayModeRef·isTimerActive 상태 보관, Android 하드백 및 앱 라이프사이클 연동(백그라운드/활성 전환에서 디스플레이 모드 토글), iOS에서 타이머 활성 시 제스처 비활성화 처리, currentOriginRef 동기화.
의존성 및 앱 설정
package.json, app.config.ts
Expo 및 일부 모듈 패치 버전 업, expo-brightness·expo-keep-awake 추가, react-native 버전 고정, 앱 version·iOS buildNumber·Android versionCode 증가.

Sequence Diagram(s)

sequenceDiagram
    participant WebView as WebView
    participant NativeBridge as NativeBridge
    participant TimerService as TimerDisplayMode 서비스
    participant ExpoKeepAwake as Expo Keep-Awake
    participant ExpoBrightness as Expo Brightness

    WebView->>NativeBridge: postMessage "TIMER_ACTIVE" {keepAwake, dimScreen, brightnessLevel}
    NativeBridge->>NativeBridge: origin 검증 (getUrlOrigin)
    NativeBridge->>TimerService: enableTimerDisplayMode(options)
    TimerService->>ExpoKeepAwake: activateKeepAwakeAsync (if keepAwake)
    TimerService->>ExpoBrightness: setBrightnessAsync / save original (if dimScreen)

    WebView->>NativeBridge: postMessage "TIMER_INACTIVE"
    NativeBridge->>TimerService: disableTimerDisplayMode()
    TimerService->>ExpoBrightness: restore original brightness
    TimerService->>ExpoKeepAwake: deactivateKeepAwake()

    WebView->>NativeBridge: postMessage "NAVIGATE_BACK"
    NativeBridge->>WebView: inject JS 또는 goBack() (origin 및 canGoBack 조건에 따라)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • #61 — [feat] 순공시간 타이머 동작 시 사용성 개선 — 타이머 동작 시 밝기 조절·화면 꺼짐 방지·이동 확인 요구사항과 직접적으로 연관됩니다.
  • BCSDLab/KONECT_FRONT_END#268 — 네이티브 타이머 통합(화면 꺼짐 방지·밝기 조절) 목표와 일치하므로 관련될 수 있습니다.

Possibly related PRs

  • BCSDLab/KONECT_REACT_NATIVE#47app/webview/[path].tsx의 WebView 메시지 처리/파싱 로직을 같이 수정하므로 연관성 있음.
  • BCSDLab/KONECT_REACT_NATIVE#37app.config.ts의 버전/빌드 번호 변경을 포함하므로 관련성 있음.

Suggested reviewers

  • kongwoojin
🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 PR의 주요 변경사항인 타이머 동작 중 사용성 개선을 명확히 설명하고 있어 변경사항과 완전히 관련됨.
Linked Issues check ✅ Passed PR이 모든 주요 요구사항을 구현함: 밝기 조절, keep-awake, 뒤로가기 확인 처리.
Out of Scope Changes check ✅ Passed 패키지 버전 업데이트와 앱 버전 증가는 타이머 기능 구현을 위한 필수적 변경이며 범위 내.

✏️ 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 61-feat-순공시간-타이머-동작-시-사용성-개선

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.

@ff1451 ff1451 marked this pull request as ready for review April 11, 2026 07:07
@ff1451 ff1451 requested a review from Copilot April 11, 2026 07:07
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

타이머(순공시간) 동작 중 화면 꺼짐/뒤로가기 등으로 흐름이 끊기는 문제를 줄이기 위해, 네이티브 레이어에서 밝기/keep-awake 및 뒤로가기 제어를 추가한 PR입니다.

Changes:

  • expo-brightness, expo-keep-awake 추가 및 Expo 관련 패키지 버전 정리
  • WebView 브리지 메시지에 타이머 활성/비활성 및 뒤로가기 제어(TIMER_ACTIVE, TIMER_INACTIVE, NAVIGATE_BACK) 추가
  • 타이머 활성 시 밝기/keep-awake 적용, 백그라운드 전환 및 언마운트 시 원복 처리

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
services/timerDisplayMode.ts 타이머 집중 모드(밝기 조절, keep-awake) enable/disable 유틸 추가
app/webview/[path].tsx WebView 브리지 메시지 확장, 타이머 중 iOS 제스처/Android 백 버튼 동작 변경, AppState 연동
package.json expo-brightness, expo-keep-awake 추가 및 Expo 패키지 버전 조정
pnpm-lock.yaml 의존성 추가/업데이트에 따른 lockfile 갱신
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread services/timerDisplayMode.ts
Comment thread services/timerDisplayMode.ts Outdated
Comment thread app/webview/[path].tsx
Comment thread pnpm-lock.yaml
Comment on lines 805 to 811
'@expo/router-server@55.0.11':
resolution: {integrity: sha512-Kd8J1OOlFR00DZxn+1KfiQiXZtRut6cj8+ynqHJa7dtt/lTL4tGkYistqmVhpKJ6w886eRY5WivKy7o0ZBFkJA==}
peerDependencies:
'@expo/metro-runtime': 5.0.4
'@expo/metro-runtime': ^55.0.6
expo: '*'
expo-constants: ^55.0.9
expo-font: ^55.0.4
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

@expo/router-server@55.0.11 now declares a peer dependency on @expo/metro-runtime: ^55.0.6, but this lockfile still resolves @expo/metro-runtime@5.0.4 (and there are no @expo/metro-runtime@55.x entries). This can lead to persistent peer-dependency warnings or an unintended runtime mismatch if router-server actually expects a different metro-runtime major. Consider re-syncing Expo package versions via expo install (or otherwise ensuring @expo/router-server and @expo/metro-runtime are on compatible version ranges).

Copilot uses AI. Check for mistakes.
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

Caution

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

⚠️ Outside diff range comments (1)
app/webview/[path].tsx (1)

93-100: ⚠️ Potential issue | 🔴 Critical

startsWith 기반 origin 검증은 우회 가능합니다.

event.nativeEvent.url은 전체 URL이기 때문에 https://allowed.example.evil/path 같은 주소도 현재 검사에 통과합니다. 이 상태에서는 외부 페이지가 LOGIN_COMPLETE/TOKEN_REFRESH/LOGOUT은 물론 이번에 추가된 TIMER_*/NAVIGATE_BACK까지 호출할 수 있으니, 문자열 prefix 대신 파싱된 origin을 정확히 비교해야 합니다.

🔒 예시: 정확한 origin 비교로 수정
   const handleMessage = useCallback(async (event: WebViewMessageEvent) => {
-    const origin = event.nativeEvent.url;
-    if (!origin || !ALLOWED_ORIGINS.some((allowed) => origin.startsWith(allowed))) {
+    let messageOrigin: string | null = null;
+    try {
+      messageOrigin = new URL(event.nativeEvent.url).origin;
+    } catch {
+      return;
+    }
+
+    if (!ALLOWED_ORIGINS.includes(messageOrigin)) {
       return;
     }
 
     try {
       const data: NativeBridgeMessage = JSON.parse(event.nativeEvent.data);

As per coding guidelines, app/webview/[path].tsx: postMessage 수신 시 origin 검증이 반드시 이루어지는지 확인하세요.

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

In `@app/webview/`[path].tsx around lines 93 - 100, The origin check in
handleMessage is using startsWith on event.nativeEvent.url which can be
bypassed; instead parse the URL (e.g., new URL(event.nativeEvent.url)) and
compare its .origin exactly against ALLOWED_ORIGINS (use equality, not prefix),
handle potential URL parse errors and reject messages when origin is not an
exact match before JSON.parse of event.nativeEvent.data or any other processing
tied to NativeBridgeMessage/TIMER_*/NAVIGATE_BACK/LOGIN_COMPLETE.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@services/timerDisplayMode.ts`:
- Around line 90-119: enableTimerDisplayMode and disableTimerDisplayMode can run
concurrently and race on the module state (isKeepAwakeActive, brightness), so
serialize their effects: introduce a single shared operation mutex/queue (e.g.,
a pendingOperation Promise or simple mutex) used by both enableTimerDisplayMode
and disableTimerDisplayMode to await any in-flight operation before proceeding,
perform checks and calls to activateKeepAwakeAsync/deactivateKeepAwake and
dimScreenIfNeeded/restoreScreenBrightness while holding the lock, and only
update isKeepAwakeActive inside the serialized section after the corresponding
async call succeeds (ensure finally blocks also run under the lock or schedule
state changes through the mutex) so that overlapping calls cannot leave the
module in the wrong state; reference functions/variables to modify:
enableTimerDisplayMode, disableTimerDisplayMode, isKeepAwakeActive,
activateKeepAwakeAsync, deactivateKeepAwake, dimScreenIfNeeded,
restoreScreenBrightness, TIMER_KEEP_AWAKE_TAG.

---

Outside diff comments:
In `@app/webview/`[path].tsx:
- Around line 93-100: The origin check in handleMessage is using startsWith on
event.nativeEvent.url which can be bypassed; instead parse the URL (e.g., new
URL(event.nativeEvent.url)) and compare its .origin exactly against
ALLOWED_ORIGINS (use equality, not prefix), handle potential URL parse errors
and reject messages when origin is not an exact match before JSON.parse of
event.nativeEvent.data or any other processing tied to
NativeBridgeMessage/TIMER_*/NAVIGATE_BACK/LOGIN_COMPLETE.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 663c7a94-105a-4915-9f6c-c7bf1fa19a6f

📥 Commits

Reviewing files that changed from the base of the PR and between 4ec19c6 and afbd69e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • app/webview/[path].tsx
  • package.json
  • services/timerDisplayMode.ts

Comment thread services/timerDisplayMode.ts
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/webview/[path].tsx Outdated
Comment thread services/timerDisplayMode.ts Outdated
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 `@services/timerDisplayMode.ts`:
- Around line 75-81: The finally block always setting isKeepAwakeActive = false
causes state to be out-of-sync when deactivateKeepAwake(TIMER_KEEP_AWAKE_TAG)
throws; change this so the local flag is only updated on successful
deactivation: remove the assignment from the finally, await deactivateKeepAwake
inside try and set isKeepAwakeActive = false in the successful path (after
await) and keep the catch to log the error; follow the same pattern as
activateKeepAwakeIfNeeded() so retries are possible when deactivate fails.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5bf7c79d-cc5a-4704-91bf-65c139cc2771

📥 Commits

Reviewing files that changed from the base of the PR and between 59a74df and a04e061.

📒 Files selected for processing (1)
  • services/timerDisplayMode.ts

Comment thread services/timerDisplayMode.ts
@ff1451 ff1451 merged commit 5402d6f into main Apr 11, 2026
1 check 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.

[feat] 순공시간 타이머 동작 시 사용성 개선

2 participants