Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b52efed
refactor: 패키지 구조 개선
chanho0908 Jan 16, 2026
d3ecb78
feat: Answer sealed class 구현
chanho0908 Jan 16, 2026
1942b6a
feat: Answer Response 모델 추가
chanho0908 Jan 16, 2026
6bc25f1
feat: Answer DataSource 구현
chanho0908 Jan 16, 2026
28e157a
feat: Answer Repository 및 DI 설정 추가
chanho0908 Jan 16, 2026
2b809c2
feat: DateFormatter 유틸리티 추가
chanho0908 Jan 16, 2026
5ccb471
feat: AnswerUiModel sealed class 구현
chanho0908 Jan 16, 2026
c3a7e75
feat: QuestionDetailUiState 및 UiEvent 추가
chanho0908 Jan 16, 2026
6658c3c
feat: QuestionDetailViewModel 구현
chanho0908 Jan 16, 2026
72d3be8
feat: Design System 컴포넌트 추가 및 개선
chanho0908 Jan 16, 2026
1ced23e
feat: AnswerCard 및 EmptyAnswerCard 컴포넌트 구현
chanho0908 Jan 16, 2026
fa2aa8c
feat: EditAnswerCard 컴포넌트 구현
chanho0908 Jan 16, 2026
bdf1ff4
feat: MyAnswer 컴포넌트 구현
chanho0908 Jan 16, 2026
0197320
feat: AnswerHistory 컴포넌트 구현
chanho0908 Jan 16, 2026
c7ce082
feat: AddAnswerBottomSheet 컴포넌트 구현
chanho0908 Jan 16, 2026
0a92c3e
feat: QuestionInfo 컴포넌트 구현
chanho0908 Jan 16, 2026
ebe48b4
feat: QuestionDetailScreen 구현
chanho0908 Jan 16, 2026
ad23e4a
feat: QuestionDetail Navigation 설정
chanho0908 Jan 16, 2026
dc7c295
feat: QuestionDetail DI 설정 추가
chanho0908 Jan 16, 2026
3a3886a
feat: QuestionDetail 문자열 리소스 추가
chanho0908 Jan 16, 2026
0b8e67f
feat: QuestionList와 QuestionDetail 연동
chanho0908 Jan 16, 2026
fcf7975
test: 패키지 이동에 따른 테스트 코드 업데이트
chanho0908 Jan 16, 2026
ae024aa
chore: 빌드 설정 및 의존성 추가
chanho0908 Jan 16, 2026
208087d
feat: 로딩된 답변이 올바른 질문에 연결되도록 수정
chanho0908 Jan 16, 2026
1f1ca2e
chore: 문제 상세 화면 TopAppBar 타이틀 제거
chanho0908 Jan 16, 2026
8eef341
feat: 문제 상세 화면과 리스트 화면 간 상태 동기화 구현
chanho0908 Jan 17, 2026
7918387
refactor: 코드 리뷰 피드백 반영
chanho0908 Jan 17, 2026
42e17f3
refactor: 추가 코드 리뷰 피드백 반영
chanho0908 Jan 17, 2026
0b05d5d
fix: CategoryOOP 색상 변경
chanho0908 Jan 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.compose.multiplatform)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
kotlin("native.cocoapods")
}

Expand Down Expand Up @@ -61,8 +62,10 @@ kotlin {

implementation(libs.bundles.koin)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlinx.collections.immutable)
implementation(libs.napier)
implementation(libs.kotlinx.datetime)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
Expand Down Expand Up @@ -113,9 +116,3 @@ android {
dependencies {
debugImplementation(libs.compose.ui.tooling)
}

// compose.resources {
// publicResClass = false
// nameOfResClass = "Res"
// packageOfResClass = "com.peto.droidmorning.composeapp.generated.resources"
// }
33 changes: 33 additions & 0 deletions composeApp/src/commonMain/composeResources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,37 @@
<string name="category_android">Android</string>
<string name="category_compose">Compose</string>
<string name="category_oop">OOP</string>

<!-- Question Detail Screen -->
<string name="back">뒤로가기</string>
<string name="favorite">즐겨찾기</string>
<string name="answer_completed">답변 완료</string>

<!-- My Answer Section -->
<string name="my_answer">내 답변</string>
<string name="edit">수정</string>
<string name="delete">삭제</string>
<string name="cancel">취소</string>
<string name="save">저장</string>
<string name="no_answer_yet">아직 작성한 답변이 없습니다</string>
<string name="answer_placeholder">답변을 입력하세요</string>

<!-- Delete Confirmation -->
<string name="delete_answer_title">답변 삭제</string>
<string name="delete_answer_confirm_message">정말 이 답변을 삭제하시겠습니까?</string>
<string name="delete_answer_confirm">정말 이 답변을 삭제하시겠습니까?</string>
<string name="delete_history_confirm">이 답변을 삭제하시겠습니까?</string>

<!-- Answer History Section -->
<string name="answer_history_count">답변 히스토리 (%d)</string>

<!-- Bottom Action -->
<string name="add_answer">답변 추가하기</string>

<!-- Add Answer Screen -->
<string name="add_answer_title">답변 작성</string>
<string name="add_answer_placeholder">면접에서 이 질문을 받았을 때 어떻게 답변할지 적어보세요</string>

<!-- Date Formatting -->
<string name="last_modified_prefix">마지막 수정: </string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.peto.droidmorning.common.util

import kotlinx.datetime.TimeZone
import kotlinx.datetime.number
import kotlinx.datetime.toLocalDateTime
import kotlin.time.Instant

object DateFormatter {
private const val DATE_SEPARATOR = "."

fun formatDate(
instant: Instant,
timeZone: TimeZone = TimeZone.currentSystemDefault(),
): String {
val date =
instant
.toLocalDateTime(timeZone)
.date

return buildString {
append(date.year)
append(DATE_SEPARATOR)
append(
date.month.number
.toString()
.padStart(2, '0'),
)
append(DATE_SEPARATOR)
append(date.day.toString().padStart(2, '0'))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package com.peto.droidmorning.di
import com.peto.droidmorning.login.navigation.LoginNavGraphContributor
import com.peto.droidmorning.main.navigation.MainNavGraphContributor
import com.peto.droidmorning.navigation.NavGraphContributor
import com.peto.droidmorning.questions.detail.navigation.QuestionDetailNavGraph
import org.koin.core.qualifier.named
import org.koin.dsl.module

val navigationModule =
module {
single<NavGraphContributor>(named("login")) { LoginNavGraphContributor() }
single<NavGraphContributor>(named("main")) { MainNavGraphContributor() }
single<NavGraphContributor>(named("QuestionDetail")) { QuestionDetailNavGraph() }
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.peto.droidmorning.di

import com.peto.droidmorning.login.vm.LoginViewModel
import com.peto.droidmorning.question.vm.QuestionViewModel
import com.peto.droidmorning.questions.detail.vm.QuestionDetailViewModel
import com.peto.droidmorning.questions.list.vm.QuestionViewModel
import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module

val viewModelModule =
module {
viewModelOf(::LoginViewModel)
viewModelOf(::QuestionViewModel)
viewModelOf(::QuestionDetailViewModel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.SavedStateHandle
import com.peto.droidmorning.designsystem.theme.AppTheme
import com.peto.droidmorning.history.HistoryScreen
import com.peto.droidmorning.profile.ProfileScreen
import com.peto.droidmorning.question.QuestionScreen
import com.peto.droidmorning.questions.list.QuestionScreen
import com.peto.droidmorning.test.TestScreen
import org.jetbrains.compose.resources.stringResource

@Composable
fun MainScreen() {
fun MainScreen(
onNavigateToQuestionDetail: (Long) -> Unit = {},
savedStateHandle: SavedStateHandle? = null,
) {
var selectedTab by remember { mutableStateOf(BottomNavigationType.QUESTION) }

Scaffold(
Expand All @@ -41,6 +45,8 @@ fun MainScreen() {
) { paddingValues ->
MainContent(
selectedTab = selectedTab,
onNavigateToQuestionDetail = onNavigateToQuestionDetail,
savedStateHandle = savedStateHandle,
modifier = Modifier.padding(paddingValues),
)
}
Expand Down Expand Up @@ -89,6 +95,8 @@ private fun BottomNavigationBar(
@Composable
private fun MainContent(
selectedTab: BottomNavigationType,
onNavigateToQuestionDetail: (Long) -> Unit,
savedStateHandle: SavedStateHandle?,
modifier: Modifier = Modifier,
) {
Box(
Expand All @@ -97,8 +105,10 @@ private fun MainContent(
when (selectedTab) {
BottomNavigationType.QUESTION ->
QuestionScreen(
onNavigateToDetail = {},
onNavigateToDetail = onNavigateToQuestionDetail,
savedStateHandle = savedStateHandle,
)

BottomNavigationType.TEST -> TestScreen()
BottomNavigationType.HISTORY -> HistoryScreen()
BottomNavigationType.PROFILE -> ProfileScreen()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ class MainNavGraphContributor : NavGraphContributor {
route = graphRoute.route,
startDestination = startDestination,
) {
composable(NavRoutes.Main.route) {
MainScreen()
composable(NavRoutes.Main.route) { backStackEntry ->
MainScreen(
onNavigateToQuestionDetail = { questionId ->
navController.navigate(NavRoutes.QuestionDetail.createRoute(questionId))
},
savedStateHandle = backStackEntry.savedStateHandle,
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.peto.droidmorning.navigation

import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

@Serializable
sealed class NavRoutes(
val route: String,
@Transient val route: String = "",
) {
data object LoginGraph : NavRoutes("login_graph")

Expand All @@ -16,4 +20,17 @@ sealed class NavRoutes(
data object History : NavRoutes("history")

data object Profile : NavRoutes("profile")

data object QuestionDetailGraph : NavRoutes("question_detail_graph")

@Serializable
data class QuestionDetail(
val questionId: Long,
) : NavRoutes(route = ROUTE) {
companion object {
const val ROUTE: String = "question_detail/{questionId}"

fun createRoute(questionId: Long): String = "question_detail/$questionId"
}
}
}
Loading