Conversation
Walkthrough이번 변경에서는 Changes
Sequence Diagram(s)sequenceDiagram
participant UI
participant BaseViewModel
participant Repository
UI->>BaseViewModel: 이벤트 발생 (예: 데이터 요청)
BaseViewModel->>Repository: API 호출
Repository-->>BaseViewModel: ApiState 반환 (Success/Error/Loading)
BaseViewModel->>BaseViewModel: resultResponse로 상태 처리
alt 성공
BaseViewModel->>UI: 상태 업데이트 (StateFlow)
BaseViewModel->>UI: 이벤트 발생 (EventFlow)
else 에러
BaseViewModel->>UI: commonError LiveData 업데이트
end
Possibly related PRs
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
feature/src/main/java/com/matzip/feature/designSystem/Color.kt (1)
5-16: 색상 그룹화를 통한 가독성 개선을 제안합니다.색상을 기능별로 그룹화하여 주석을 추가하면 더 읽기 쉬워질 것 같습니다.
+// Background Colors val Background = Color(0xFFFAFAFA) val Box = Color(0xFFF0F0F0) + +// Brand Colors val Main = Color(0xFFFF8400) val MainLight1 = Color(0xFFFFB273) val MainLight2 = Color(0xFFFFDABB) + +// Neutral Colors val Black = Color(0xFF111111) val BlackBox = Color(0xFF282828) val DarkGray = Color(0xFF3C3C3C) + +// Text Colors val TextSub1 = Color(0xFF787878) val TextSub2 = Color(0xFFA8A8A8) val LightGray = Color(0xFFD9D9D9) + +// Accent Colors val Sub1 = Color(0xFFFFD000)feature/src/main/java/com/matzip/feature/base/PageState.kt (1)
3-3: sealed 키워드 추가를 고려해보세요.더 명확한 의도 표현과 컴파일 타임 안전성을 위해 sealed interface 사용을 고려해보세요.
-interface PageState{ +sealed interface PageState{
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
feature/src/main/res/font/pretendard_bold.ttfis excluded by!**/*.ttffeature/src/main/res/font/pretendard_light.ttfis excluded by!**/*.ttffeature/src/main/res/font/pretendard_medium.ttfis excluded by!**/*.ttffeature/src/main/res/font/pretendard_regular.ttfis excluded by!**/*.ttffeature/src/main/res/font/pretendard_semi_bold.ttfis excluded by!**/*.ttf
📒 Files selected for processing (8)
feature/build.gradle.kts(1 hunks)feature/src/main/java/com/matzip/feature/base/BaseViewModel.kt(1 hunks)feature/src/main/java/com/matzip/feature/base/Event.kt(1 hunks)feature/src/main/java/com/matzip/feature/base/PageState.kt(1 hunks)feature/src/main/java/com/matzip/feature/base/base.kt(0 hunks)feature/src/main/java/com/matzip/feature/designSystem/Color.kt(1 hunks)feature/src/main/java/com/matzip/feature/designSystem/Typo.kt(1 hunks)feature/src/main/java/com/matzip/feature/designSystem/designSystem.kt(0 hunks)
💤 Files with no reviewable changes (2)
- feature/src/main/java/com/matzip/feature/base/base.kt
- feature/src/main/java/com/matzip/feature/designSystem/designSystem.kt
🧰 Additional context used
🪛 detekt (1.23.8)
feature/src/main/java/com/matzip/feature/base/BaseViewModel.kt
[warning] 55-55: This empty block of code can be removed.
(detekt.empty-blocks.EmptyIfBlock)
🔇 Additional comments (14)
feature/src/main/java/com/matzip/feature/designSystem/Color.kt (1)
1-16: 색상 정의가 잘 구성되어 있습니다.색상 상수들이 의미있는 이름으로 잘 정의되어 있고, 브랜드 색상과 기능적 색상이 적절히 구분되어 있습니다.
feature/build.gradle.kts (1)
38-38: 도메인 모듈 의존성 추가가 적절합니다.Feature 모듈이 Domain 모듈에 의존하는 것은 클린 아키텍처 원칙에 맞는 올바른 구조입니다.
feature/src/main/java/com/matzip/feature/base/PageState.kt (1)
3-5: PageState 인터페이스 설계가 깔끔합니다.sealed interface 패턴을 사용한 상태 관리 구조가 잘 설계되어 있습니다. 향후 다양한 페이지 상태를 쉽게 추가할 수 있는 확장 가능한 구조입니다.
feature/src/main/java/com/matzip/feature/designSystem/Typo.kt (3)
18-110: 타이포그래피 시스템이 잘 구성되어 있습니다.체계적인 텍스트 스타일 정의와 일관된 구조가 인상적입니다. 헤더, 타이틀, 본문, 예시 텍스트가 적절히 구분되어 있습니다.
63-66: title4와 title5의 일관성을 확인해주세요.title4와 title5가 동일한 폰트 크기(14sp)와 라인 높이(18.2sp)를 가지지만 폰트 웨이트만 다릅니다. 의도된 설계인지 확인해주세요.
10-16: 폰트 리소스 확인 완료
feature/src/main/res/font 디렉터리에 Pretendard 굵기별(.ttf) 파일이 모두 존재함을 확인했습니다. 추가 조치가 필요하지 않습니다.feature/src/main/java/com/matzip/feature/base/Event.kt (1)
45-53: collectEvent 확장 함수가 잘 구현되어 있습니다.이벤트 수집 로직이 명확하고 단일 소비 패턴을 올바르게 구현했습니다.
feature/src/main/java/com/matzip/feature/base/BaseViewModel.kt (7)
1-11: 임포트 구성이 적절합니다.필요한 Android 라이프사이클 컴포넌트, 코루틴, 도메인 레이어 의존성들이 적절히 임포트되어 있습니다.
13-15: 클래스 선언이 잘 설계되었습니다.제네릭 타입 제약과 생성자 파라미터가 적절히 정의되어 있어 타입 안전성과 재사용성을 보장합니다.
17-18: 상태 관리 구현이 우수합니다.MutableStateFlow를 내부적으로 사용하고 읽기 전용 StateFlow로 노출하는 것은 Android 권장 패턴을 잘 따르고 있습니다.
20-21: 이벤트 플로우 구현을 검증해주세요.EventFlow를 사용한 이벤트 처리 구현이 적절해 보이지만, PR 목표에서 언급한 대로 새로운 이벤트 시스템이므로 다양한 이벤트 처리 시나리오를 테스트해주시기 바랍니다.
23-24: 공통 에러 처리 설정이 올바릅니다.MutableLiveData를 사용한 에러 처리 구조가 적절하며, 실제 에러 처리 로직은 TODO 섹션에서 구현 예정인 것으로 보입니다.
26-30: 상태 업데이트 함수가 잘 구현되었습니다.viewModelScope를 사용한 코루틴 실행과 flow.update를 사용한 안전한 상태 업데이트가 적절히 구현되어 있습니다.
31-35: 이벤트 발생 함수가 올바르게 구현되었습니다.viewModelScope를 사용한 코루틴 실행과 EventFlow를 통한 이벤트 발생이 적절히 처리되어 있습니다.
| class EventFlow<T> { | ||
| private val _events = MutableSharedFlow<Event<T>>( | ||
| // 이벤트를 단일 소비로 처리하기 위해 | ||
| replay = 1, | ||
| // 버퍼 크기를 1로 설정하여 최신 이벤트만 유지 | ||
| extraBufferCapacity = 1 | ||
| ) | ||
|
|
||
| val events: SharedFlow<Event<T>> = _events.asSharedFlow() | ||
|
|
||
| suspend fun emit(value: T) { | ||
| _events.emit(Event(value)) | ||
| } | ||
|
|
||
| fun tryEmit(value: T) { | ||
| _events.tryEmit(Event(value)) | ||
| } | ||
| } |
There was a problem hiding this comment.
EventFlow 설정에 잠재적 문제가 있습니다.
replay = 1과 extraBufferCapacity = 1의 조합이 예상과 다르게 동작할 수 있습니다. 이 설정은 구독자가 없어도 이벤트가 버퍼에 유지되어 나중에 구독하는 경우 이전 이벤트를 받을 수 있습니다.
단일 소비 이벤트가 목적이라면 다음과 같이 수정을 고려해보세요:
private val _events = MutableSharedFlow<Event<T>>(
- // 이벤트를 단일 소비로 처리하기 위해
- replay = 1,
- // 버퍼 크기를 1로 설정하여 최신 이벤트만 유지
- extraBufferCapacity = 1
+ // 단일 소비를 위해 replay 없이 설정
+ replay = 0,
+ extraBufferCapacity = 1
)📝 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.
| class EventFlow<T> { | |
| private val _events = MutableSharedFlow<Event<T>>( | |
| // 이벤트를 단일 소비로 처리하기 위해 | |
| replay = 1, | |
| // 버퍼 크기를 1로 설정하여 최신 이벤트만 유지 | |
| extraBufferCapacity = 1 | |
| ) | |
| val events: SharedFlow<Event<T>> = _events.asSharedFlow() | |
| suspend fun emit(value: T) { | |
| _events.emit(Event(value)) | |
| } | |
| fun tryEmit(value: T) { | |
| _events.tryEmit(Event(value)) | |
| } | |
| } | |
| class EventFlow<T> { | |
| private val _events = MutableSharedFlow<Event<T>>( | |
| // 단일 소비를 위해 replay 없이 설정 | |
| replay = 0, | |
| extraBufferCapacity = 1 | |
| ) | |
| val events: SharedFlow<Event<T>> = _events.asSharedFlow() | |
| suspend fun emit(value: T) { | |
| _events.emit(Event(value)) | |
| } | |
| fun tryEmit(value: T) { | |
| _events.tryEmit(Event(value)) | |
| } | |
| } |
🤖 Prompt for AI Agents
In feature/src/main/java/com/matzip/feature/base/Event.kt around lines 26 to 43,
the combination of replay = 1 and extraBufferCapacity = 1 in MutableSharedFlow
causes events to be buffered and replayed to new subscribers, which conflicts
with the intended single consumption behavior. To fix this, set replay to 0 to
prevent replaying past events and adjust extraBufferCapacity as needed to allow
buffering without replay, ensuring events are consumed only once by active
subscribers.
There was a problem hiding this comment.
그러면 딜레이 이슈로 구독 전 이벤트 발생했을 때 누락되는 문제가 발생하는거 아님?
There was a problem hiding this comment.
@rudtjr1106 맞습니다! 정확한 지적이에요.
replay = 0으로 설정하면 구독 전에 발생한 이벤트는 누락되는 문제가 있습니다. 이는 다음과 같은 상황에서 발생할 수 있어요:
- 화면 초기화 지연
- 코루틴 스코프 설정 지연
- 컴포저블 생성 타이밍 이슈
현재 구현의 trade-off:
replay = 1: 단일 소비 원칙은 위배되지만 이벤트 누락 방지replay = 0: 단일 소비는 보장되지만 타이밍 이슈로 이벤트 누락 가능
대안 방안들:
- 현재 구현 유지 - 이벤트 누락 방지를 우선시
- Channel 사용 - 자연스러운 큐잉으로 타이밍 이슈 해결
- 용도별 분리 - 중요한 이벤트는 replay, 일반 이벤트는 replay 0
실제 사용 패턴에서 어떤 것이 더 중요한지에 따라 결정하는 것이 좋겠네요. 현재 구현이 더 안전한 선택일 수 있습니다.
✏️ Learnings added
Learnt from: rudtjr1106
PR: the-spot-campus/MatzipBook-Android#10
File: feature/src/main/java/com/matzip/feature/base/Event.kt:26-43
Timestamp: 2025-07-11T02:28:30.612Z
Learning: EventFlow에서 replay = 1 vs replay = 0 설정은 트레이드오프가 있음. replay = 1은 단일 소비 원칙을 위배하지만 구독 전 이벤트 누락을 방지함. replay = 0은 단일 소비를 보장하지만 타이밍 이슈로 이벤트가 누락될 수 있음.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
| class Event<out T>(private val content: T) { | ||
|
|
||
| private var hasBeenHandled = false | ||
|
|
||
| fun getContentIfNotHandled(): T? { | ||
| return if (hasBeenHandled) { | ||
| null | ||
| } else { | ||
| hasBeenHandled = true | ||
| content | ||
| } | ||
| } | ||
|
|
||
| fun peekContent(): T = content | ||
| } |
There was a problem hiding this comment.
Event 클래스의 스레드 안전성을 개선해주세요.
hasBeenHandled 플래그가 스레드 안전하지 않습니다. 멀티스레드 환경에서 동일한 이벤트가 여러 번 처리될 수 있습니다.
+import java.util.concurrent.atomic.AtomicBoolean
+
class Event<out T>(private val content: T) {
- private var hasBeenHandled = false
+ private val hasBeenHandled = AtomicBoolean(false)
fun getContentIfNotHandled(): T? {
- return if (hasBeenHandled) {
+ return if (hasBeenHandled.getAndSet(true)) {
null
} else {
- hasBeenHandled = true
content
}
}📝 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.
| class Event<out T>(private val content: T) { | |
| private var hasBeenHandled = false | |
| fun getContentIfNotHandled(): T? { | |
| return if (hasBeenHandled) { | |
| null | |
| } else { | |
| hasBeenHandled = true | |
| content | |
| } | |
| } | |
| fun peekContent(): T = content | |
| } | |
| import java.util.concurrent.atomic.AtomicBoolean | |
| class Event<out T>(private val content: T) { | |
| private val hasBeenHandled = AtomicBoolean(false) | |
| fun getContentIfNotHandled(): T? { | |
| return if (hasBeenHandled.getAndSet(true)) { | |
| null | |
| } else { | |
| content | |
| } | |
| } | |
| fun peekContent(): T = content | |
| } |
🤖 Prompt for AI Agents
In feature/src/main/java/com/matzip/feature/base/Event.kt around lines 9 to 23,
the hasBeenHandled flag is not thread-safe, which can cause the same event to be
handled multiple times in a multithreaded environment. To fix this, make the
hasBeenHandled flag access atomic by using synchronization or atomic variables
such as AtomicBoolean. Update the getContentIfNotHandled() method to check and
set the flag atomically to ensure only one thread can handle the event.
| protected fun<D> resultResponse( | ||
| response: ApiState<D>, | ||
| successCallback : (D) -> Unit, | ||
| errorCallback : ((String) -> Unit)? = null, | ||
| needLoading : Boolean = true) | ||
| { | ||
| when(response){ | ||
| is ApiState.Error -> { | ||
| //TODO 에러 코드를 다룰 예정입니다. | ||
| // if(response.errorCode == StatusCode.ERROR_404 || | ||
| // response.errorCode == StatusCode.ERROR || | ||
| // response.errorCode == StatusCode.NETWORK_ERROR) { | ||
| // showCommonError(response.errorCode) | ||
| // } | ||
| // else errorCallback?.invoke(response.errorCode) | ||
| // endLoading() | ||
| } | ||
| // TODO Loading 상태일때 화면을 처리할 예정입니다. | ||
| ApiState.Loading -> if(needLoading) {} | ||
| is ApiState.Success -> { | ||
| successCallback.invoke(response.data) | ||
| //endLoading() | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
❓ Verification inconclusive
API 응답 처리 함수의 구현을 완료해주세요.
다음 사항들을 개선해야 합니다:
- 빈 if 블록 제거: 55번째 줄의 빈 if 블록은 정적 분석 도구에서 지적한 대로 제거하거나 구현해야 합니다.
- TODO 주석 해결: 에러 코드 처리와 로딩 상태 처리 로직이 미완성 상태입니다.
- 주석 처리된 코드: 계획된 기능이지만 구현되지 않은 코드가 주석으로 남아있습니다.
- 함수명 개선:
resultResponse보다handleApiResponse가 더 명확합니다.
다음 개선 사항을 적용하시겠습니까?
- protected fun<D> resultResponse(
+ protected fun<D> handleApiResponse(
response: ApiState<D>,
successCallback : (D) -> Unit,
errorCallback : ((String) -> Unit)? = null,
needLoading : Boolean = true)
{
when(response){
is ApiState.Error -> {
- //TODO 에러 코드를 다룰 예정입니다.
+ // TODO: 에러 코드 처리 로직 구현 필요
+ errorCallback?.invoke("API 에러 발생") // 임시 구현
}
- // TODO Loading 상태일때 화면을 처리할 예정입니다.
- ApiState.Loading -> if(needLoading) {}
+ ApiState.Loading -> {
+ if(needLoading) {
+ // TODO: 로딩 상태 처리 로직 구현 필요
+ }
+ }
is ApiState.Success -> {
successCallback.invoke(response.data)
- //endLoading()
+ // TODO: 로딩 종료 처리 필요
}
}
}에러 처리 및 로딩 상태 관리 로직을 구현하는 데 도움이 필요하시면 알려주세요.
API 응답 처리 함수 구현 완료 및 리팩토링 필요
파일: feature/src/main/java/com/matzip/feature/base/BaseViewModel.kt (37–61줄)
다음 사항을 반영해주세요:
- 빈 if 블록 제거 혹은 로직 추가 (Loading 상태)
- TODO 주석 제거 및 실제 에러/로딩 처리 로직 구현
- 주석 처리된 코드 정리 (에러 코드별 처리 분기)
- 함수명
resultResponse→handleApiResponse로 변경 검토
- protected fun<D> resultResponse(
+ protected fun<D> handleApiResponse(
response: ApiState<D>,
successCallback: (D) -> Unit,
errorCallback: ((String) -> Unit)? = null,
needLoading: Boolean = true
) {
when (response) {
is ApiState.Error -> {
- //TODO 에러 코드를 다룰 예정입니다.
+ // TODO: API 에러 처리 로직 구현 필요
+ errorCallback?.invoke(response.errorCode)
+ // endLoading()
}
- // TODO Loading 상태일때 화면을 처리할 예정입니다.
- ApiState.Loading -> if (needLoading) {}
+ ApiState.Loading -> {
+ if (needLoading) {
+ // TODO: 로딩 표시 로직 구현 필요
+ }
+ }
is ApiState.Success -> {
- successCallback.invoke(response.data)
- //endLoading()
+ successCallback.invoke(response.data)
+ // TODO: 로딩 종료 처리 구현 필요
}
}
}필요하시면 에러/로딩 처리 구현 부분에 대해 추가 지원을 드릴 수 있습니다.
📝 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.
| protected fun<D> resultResponse( | |
| response: ApiState<D>, | |
| successCallback : (D) -> Unit, | |
| errorCallback : ((String) -> Unit)? = null, | |
| needLoading : Boolean = true) | |
| { | |
| when(response){ | |
| is ApiState.Error -> { | |
| //TODO 에러 코드를 다룰 예정입니다. | |
| // if(response.errorCode == StatusCode.ERROR_404 || | |
| // response.errorCode == StatusCode.ERROR || | |
| // response.errorCode == StatusCode.NETWORK_ERROR) { | |
| // showCommonError(response.errorCode) | |
| // } | |
| // else errorCallback?.invoke(response.errorCode) | |
| // endLoading() | |
| } | |
| // TODO Loading 상태일때 화면을 처리할 예정입니다. | |
| ApiState.Loading -> if(needLoading) {} | |
| is ApiState.Success -> { | |
| successCallback.invoke(response.data) | |
| //endLoading() | |
| } | |
| } | |
| } | |
| protected fun<D> handleApiResponse( | |
| response: ApiState<D>, | |
| successCallback: (D) -> Unit, | |
| errorCallback: ((String) -> Unit)? = null, | |
| needLoading: Boolean = true | |
| ) { | |
| when (response) { | |
| is ApiState.Error -> { | |
| // TODO: API 에러 처리 로직 구현 필요 | |
| errorCallback?.invoke(response.errorCode) | |
| // endLoading() | |
| } | |
| ApiState.Loading -> { | |
| if (needLoading) { | |
| // TODO: 로딩 표시 로직 구현 필요 | |
| } | |
| } | |
| is ApiState.Success -> { | |
| successCallback.invoke(response.data) | |
| // TODO: 로딩 종료 처리 구현 필요 | |
| } | |
| } | |
| } |
🧰 Tools
🪛 detekt (1.23.8)
[warning] 55-55: This empty block of code can be removed.
(detekt.empty-blocks.EmptyIfBlock)
🤖 Prompt for AI Agents
In feature/src/main/java/com/matzip/feature/base/BaseViewModel.kt between lines
37 and 61, refactor the resultResponse function by renaming it to
handleApiResponse for clarity, remove all TODO comments, and implement the error
and loading handling logic instead of empty or commented blocks. Specifically,
replace the empty if block for ApiState.Loading with actual loading state
handling, restore and clean up the error code handling logic for ApiState.Error,
and remove commented-out code while ensuring the function properly calls
successCallback on success and handles endLoading or similar UI state updates as
needed.
JJun-He
left a comment
There was a problem hiding this comment.
기본 base 작업 너무 잘해주셔서 감사합니다!! 그리고 제가 MainScreen 구현해봐도 괜찮을까요??
There was a problem hiding this comment.
BaseViewModel 전반적으로 잘 구조화해주신것 같습니다. 상태 관리가 Flow와 LiveData가 혼용되어 있는데 , 전체를 다 Flow 기반으로 통일해도 괜찮나요? 보니까 uiState와 eventFlow는 StateFlow/Flow 기반으로 되어 있는데 commonError는 LiveData로 되어 있는거 같아서요!! coderabbit에서 말한 네이밍 수정과 TODO 부분 구현만 해주시면 깔끔할 것 같습니다!! 수고하셨습니다!!
There was a problem hiding this comment.
Event 클래스의 역할이 명확하게 잘 구현되어 있어서, 단일 소비 이벤트를 깔끔하게 처리할 수 있는 것 같습니다. codeRabbit에서 말한 멀티스레드 환경에서 동시 접근할 경우 race conditon에 노출될 수 있는것 같아서, 동기화 처리를 해보는 것도 좋을 것 같습니다 전반적으로 좋은 코드 감사합니다!!
🔎 작업 내용
대표적으로 Event와 그에따른 BaseViewmodel, 그리고 Color, Font 작업을 진행했습니다.
Event는 저도 기존에 사용했던 것과 다르게 새롭게 구현해본 내용이라 아직 버그가 있을 수 있습니다. 이 부분 유의해주시고 다양한 이벤트 처리를 테스트 하시면서 발생하는 오류가 있다면 전달해주시면 감사드리겠습니다.
BaseViewModel은 아직 미완성입니다. 공통 에러처리, 화면 로딩처리 등 구현해야 할 부분이 남았지만 당장 개발하는데 있어서 문제는 없습니다. 이는 TODO 주석으로 달아놨으며 공통으로 ViewModel과 State를 관리하는 로직이 구현되어있습니다.
Color와 Font도 정의해뒀습니다.
하지만 Figma 보시면 아시다시피 색상은 같지만 실제 디자인에 적용된 이름은 달라 자세히 확인하시고 적용하셔야 합니다.
마찬가지로 Font또한 실제 디자인에 Typo가 적용되지 않은 상태로 되어있어 이 부분도 bold, size등 주의깊게 확인하셔서 정의해둔 Font로 적용하시면 될 것 같습니다.
🔧 앞으로의 과제
준희님이 이제 온보딩 작업에 들어갈 준비가 된 것 같습니다.
개인적인 의견으로는 준희님이 MainScreen을 작성해보시는게 어떤지 하여 아직 구현하지 않았습니다.
MainScreen에는 NavigationController, BottomNav, Error 처리 등 들어가는데 혹시 이 부분 구현하고싶은 의향이 있으신지 여쭤봅니다.
저는 이제 Home파트를 진행할 예정입니다. 아직 MainScreen 구현이 어려우시다면 제가 빠른 시간내에 작업해서 올리겠습니다.
➕ 이슈 링크
Summary by CodeRabbit
신규 기능
리팩터링
기타