Skip to content

MainActivity 랜딩 탭 지정을 Navigator 인터페이스로 리팩토링 - #412

Open
unam98 wants to merge 7 commits into
developfrom
feature/main-tab-navigator
Open

MainActivity 랜딩 탭 지정을 Navigator 인터페이스로 리팩토링#412
unam98 wants to merge 7 commits into
developfrom
feature/main-tab-navigator

Conversation

@unam98

@unam98 unam98 commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

작업 배경

  • MainActivity로 돌아갈 때 랜딩할 탭을 지정하는 EXTRA_FRAGMENT_REPLACEMENT_DIRECTION 문자열 키가 6개 파일에 각각 중복 선언돼 있고, 2곳은 상수화조차 안 돼 리터럴로 직접 박혀 있었음(타이포가 나도 컴파일 타임에 못 잡음).
  • 화면 간 네비게이션 구조 개선을 논의한 결과, Single-Activity + NavGraph가 근본 해법이지만 멀티 Activity 구조를 빅뱅으로 바꾸는 건 리스크가 커서 2단계 전략으로 진행: 1단계(이번 PR) = Navigator 인터페이스로 호출부를 구체 Activity/Intent로부터 분리, 2단계(추후) = Navigator 구현체만 NavController 기반으로 교체(strangler-fig 패턴, 호출부는 안 건드림).
  • 스코프는 이번 문제(MainActivity 랜딩 탭 지정, 6개 호출부)로 한정. 이미 타입 있는 Intent extra를 쓰는 40여 곳의 다른 네비게이션 호출부는 스코프 밖.

변경 사항

영역 내용
presentation/navigation/Navigator.kt Navigator 인터페이스, MainTab/NavigationMode enum 신설
presentation/navigation/NavigatorImpl.kt Context를 상태로 갖지 않는 순수 디스패처 구현체
presentation/navigation/MainTabDataFromMapper.kt EndRunActivityString → MainTab? 로컬 매핑 함수
di/NavigationModule.kt 기존 RepositoryModule.kt 패턴을 따르는 @Binds 바인딩
MainActivity.kt 문자열 기반 수신 로직을 MainTab 타입 기반으로 교체, 방어적 onNewIntent 추가
StorageScrapFragment.kt, DrawActivity.kt, CourseDetailActivity.kt, MyDrawDetailActivity.kt, EndRunActivity.kt Navigator 필드 주입 후 호출부 교체, 중복 상수 제거

영향 범위

  • MainActivity로 재진입하며 탭을 지정하는 6개 흐름(코스 그리기 완주, 코스 삭제, 스크랩 목록, 코스 상세 딥링크 백버튼, 내 코스 상세 삭제/딥링크 백버튼, 러닝 종료 화면 백버튼/저장)에 한정.
  • onNewIntent 추가는 현재 MainActivity가 launchMode=standard이고 어떤 호출부도 SINGLE_TOP을 쓰지 않아 항상 onCreate를 다시 타므로 동작 변화 없음 — 향후 launchMode 변경에 대비한 방어적 추가.
  • EndRunActivityCourseData.dataFrom(String)이 DrawActivity/CourseDetailActivity/MyDrawDetailActivity를 거쳐 흘러들어오는 값이라 타입을 바꾸는 게 스코프 밖이라, mapDataFromToMainTab()으로 로컬 매핑만 함 — 기존 when 분기를 그대로 옮긴 것이라 동작 변화 없음.
  • 런타임 영향 없음(순수 리팩토링, API/서버 변경 없음).

검증 매트릭스

영향 범위 테스트 코드
NavigationMode별 Intent 플래그 세팅 (DEFAULT/CLEAR_TOP/NEW_TASK_CLEAR_TASK) DEFAULT 모드는 플래그를 추가하지 않는다CLEAR_TOP 모드는 FLAG_ACTIVITY_CLEAR_TOP을 추가한다NEW_TASK_CLEAR_TASK 모드는 두 플래그를 함께 추가한다
MainTab extra 세팅 여부 (지정/미지정) tab이 지정되면 EXTRA_MAIN_TAB extra를 담는다tab이 null이면 extra를 담지 않는다
EndRunActivity의 dataFrom→MainTab 매핑 (기존 동작 무변경 검증) 그리기 관련 dataFrom 값은 STORAGE로 매핑된다코스발견 관련 dataFrom 값은 DISCOVER로 매핑된다매칭되지 않는 값은 null로 매핑된다null 입력은 null로 매핑된다

Test Plan

  • ./gradlew :app:compileDebugKotlin 통과
  • ./gradlew :app:assembleDebug 통과
  • ./gradlew :app:testDebugUnitTest 전체 통과(신규 9개 포함, 기존 테스트 회귀 없음)
  • grep -rn "EXTRA_FRAGMENT_REPLACEMENT_DIRECTION" 결과 0건 확인
  • 수동 QA: DrawActivity 저장 후 "보관함으로" → 보관함 탭 랜딩
  • 수동 QA: StorageScrapFragment 코스발견 이동 → 코스발견 탭 랜딩
  • 수동 QA: CourseDetailActivity 딥링크 진입 후 백버튼 → 코스발견 탭 랜딩(태스크 스택 초기화)
  • 수동 QA: MyDrawDetailActivity 코스 삭제 후 → 보관함 탭 랜딩
  • 수동 QA: MyDrawDetailActivity 딥링크 진입 후 백버튼 → 보관함 탭 랜딩
  • 수동 QA: EndRunActivity 완주 후 백버튼/저장 → 출처에 맞는 탭 랜딩

🤖 Generated with Claude Code

unam98 added 7 commits August 18, 2026 19:50
MainActivity 랜딩 탭 지정 로직에서 앞으로 쓸 화면 전환 추상화를
먼저 도입한다. Intent 플래그를 그대로 노출하지 않고 NavigationMode로
감싸서, 추후 NavController 기반 구현체로 교체할 때 호출부를 건드리지
않아도 되게 했다.
문자열 기반 EXTRA_FRAGMENT_REPLACEMENT_DIRECTION 수신 로직을
타입 있는 MainTab enum 기반으로 교체했다. 아직 호출부들이 옛 키를
보내고 있어 이 커밋만으로는 탭 전환이 정상 동작하지 않는다 — 이후
커밋들에서 호출부를 순차적으로 Navigator로 옮긴다.

onNewIntent를 방어적으로 추가했다. 현재 MainActivity는 launchMode가
standard이고 어떤 호출부도 SINGLE_TOP을 쓰지 않아 CLEAR_TOP/
NEW_TASK|CLEAR_TASK 모두 항상 onCreate를 다시 타므로 동작 변화는
없다 — 향후 launchMode 변경에 대비한 방어적 추가다.
상수화조차 안 돼있던 "fromMyScrap" 리터럴을 MainTab.DISCOVER로 교체.
삭제 후(STORAGE/DEFAULT)와 딥링크 백버튼(STORAGE/NEW_TASK_CLEAR_TASK)
2곳을 Navigator로 교체했다. EXTRA_FROM_MY_DRAW_DETAIL은 Intent extra
키가 아니라 CourseData.dataFrom에 실리는 데이터 마커였을 뿐이라
DATA_FROM_MY_DRAW_DETAIL로 리네이밍해 혼동을 없앴다.
backBtn/onBackPressed/저장 성공 3곳을 모두 Navigator로 교체했다.
CourseData.dataFrom(String)이 DrawActivity/CourseDetailActivity/
MyDrawDetailActivity를 거쳐 흘러들어오는 값이라 타입을 바꾸는 건
스코프 밖이라, mapDataFromToMainTab()으로 로컬 매핑만 했다 —
MainActivity.checkIntentValue()의 기존 when 분기를 그대로 옮긴 것이라
동작 변화는 없다("detail"처럼 기존에도 매칭 안 되던 값은 여전히
매칭 없음).
@unam98 unam98 self-assigned this Aug 18, 2026
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@unam98, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 28535f15-f4d5-4a26-ac15-c1767eeaed0c

📥 Commits

Reviewing files that changed from the base of the PR and between efb0dd4 and b16c6c1.

📒 Files selected for processing (12)
  • app/src/main/java/com/runnect/runnect/di/NavigationModule.kt
  • app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt
  • app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt
  • app/src/main/java/com/runnect/runnect/presentation/draw/DrawActivity.kt
  • app/src/main/java/com/runnect/runnect/presentation/endrun/EndRunActivity.kt
  • app/src/main/java/com/runnect/runnect/presentation/navigation/MainTabDataFromMapper.kt
  • app/src/main/java/com/runnect/runnect/presentation/navigation/Navigator.kt
  • app/src/main/java/com/runnect/runnect/presentation/navigation/NavigatorImpl.kt
  • app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt
  • app/src/main/java/com/runnect/runnect/presentation/storage/mydrawdetail/MyDrawDetailActivity.kt
  • app/src/test/java/com/runnect/runnect/presentation/navigation/MainTabDataFromMapperTest.kt
  • app/src/test/java/com/runnect/runnect/presentation/navigation/NavigatorImplTest.kt

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.

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.

1 participant